Commit

Author:

Hash:

Timestamp:

+208 -0 +/-2 browse

Kevin Schoon [me@kevinschoon.com]

6c36dbdcf0bc6c8c6370a4f1ec705429472c8c25

Wed, 08 Jul 2026 10:00:48 +0000 (1 week ago)

add a basic tutorial
add a basic tutorial

There is considerably more to document but this is at least a start.
1diff --git a/ayllu-tutorial.7.md b/ayllu-tutorial.7.md
2new file mode 100644
3index 0000000..781e717
4--- /dev/null
5+++ b/ayllu-tutorial.7.md
6 @@ -0,0 +1,205 @@
7+ ayllu-tutorial 7 "User Manual"
8+ ==================================================
9+
10+ # GETTING STARTED
11+
12+ The most basic way to use Ayllu is to change to a directory containing a Git
13+ repository and run the command `ayllu-web serve`. This will provide a static
14+ user interface for browsing your local repository.
15+
16+ This guide assumes that you have installed Ayllu on a Linux distribution with
17+ systemd.
18+
19+ ## USER OR SYSTEM ACCOUNT?
20+
21+ Ayllu can be run as a regular user or as a dedicated system user. As a developer
22+ you probably want to run Ayllu as a regular system user and so we'll cover that
23+ configuration first. If you are a sysadmin and managing a public installation
24+ then you likely want to run it as a dedicated system user.
25+
26+ ## BASIC CONFIG FILE
27+
28+ For regular users you should install a TOML file at
29+ `~/.config/ayllu/config.toml` and add a few basic settings.
30+
31+ ```toml
32+ default_branch = "main"
33+
34+ [web]
35+ blurb = """
36+ My own personal instance of Ayllu!
37+ """
38+ # enable static hosting
39+ sites = { enabled = true }
40+
41+ [database]
42+ [build]
43+ ```
44+
45+ ## DATABASE
46+
47+ By default Ayllu handles no persistent state directly but builds and other
48+ components require this ability. Ayllu uses a single global SQLite instance
49+ for this purpose. To enable it you can add an empty `[database]` section in
50+ your configuration file. By default the database will be stored in
51+ `~/.local/share/ayllu/ayllu.sqlite` or `/var/lib/ayllu/ayllu.sqlite`.
52+
53+ ```toml
54+ [database]
55+ ```
56+
57+ And then run `ayllu-migrate` to initialize it. NOTE that prior to version 1.0
58+ Ayllu makes no guarantees about migrations or data retention.
59+
60+ ## STATIC HOSTING
61+
62+ Ayllu can host static content from any git repository. You need to toggle the
63+ the setting in your global configuration file:
64+
65+ ```toml
66+ [web.sites]
67+ enabled = true
68+ ```
69+
70+ Once enabled you can either use `ayllu-shell` to configure the settings of your
71+ repository or you can manually edit your repository's configuration file.
72+
73+ ```gitconfig
74+ [ayllu-sites]
75+ enabled = true
76+ # Any site with a matching host header is served
77+ header = Host=example.org
78+ # Path to HTML content within the repository
79+ content = gen
80+ branch = master
81+ ```
82+
83+ ## REMOTE ACCESS (SYSTEM ACCOUNT)
84+
85+ First you should create a new configuration file at `/etc/ayllu/config.toml`
86+ that is owned by the `root` user. Your distribution may already provide you with
87+ a sample file here.
88+
89+ Next we'll setup a base path and configure an identity and a new collection of
90+ repositories to serve.
91+
92+ ```toml
93+ site_name = "Just Another Ayllu Instance"
94+ origin = "code.example.org"
95+ default_branch = "main"
96+ base_path = "/var/lib/ayllu/repos"
97+
98+ [shell]
99+ motd = """
100+ Welcome to Ayllu!
101+ """
102+
103+ [[identities]]
104+ username = "demo"
105+ authorized_keys = [
106+ "... your public key here ..."
107+ ]
108+
109+ [[collections]]
110+ name = "miscellaneous"
111+ description = "disparate software written in haste"
112+ ```
113+
114+ Before we connect remotely let's run the `ayllu-shell` command and initialize
115+ a new repository.
116+
117+ ```sh
118+ sudo -u ayllu ayllu-shell
119+ ```
120+
121+ Choose "Create Repository" and follow the prompts. Of course, if you don't
122+ want to use `ayllu-shell` you can just create a repository manually:
123+
124+ ```sh
125+ sudo -u ayllu git init --bare /var/lib/ayllu/repos/miscellaneous/my-new-repo
126+ ```
127+
128+ You can now start and enable the ayllu-web service permanently.
129+
130+ ```sh
131+ systemctl enable ayllu-web
132+ systemctl start ayllu-web
133+ ```
134+
135+ Next let's configure OpenSSH to delegate access to the `ayllu` user.
136+ **WARNING: Make sure you have an alternative way to connect to your server in
137+ the event of miss-configuration** We'll add a configuration drop-in at
138+ `/etc/ssh/sshd_config.d/30-ayllu-keys.conf`:
139+
140+ ```txt
141+ AuthorizedKeysCommand /usr/bin/userdbctl ssh-authorized-keys %u --chain /usr/bin/ayllu-keys %u %h %t %k
142+ AuthorizedKeysCommandUser root
143+ ```
144+
145+ Next restart the OpenSSH process:
146+
147+ ```
148+ systemctl restart sshd
149+ ```
150+
151+ Now each time a user makes an SSH connection OpenSSH will delegate key
152+ verification to the ayllu-keys script which will grant access to any configured
153+ identities as well as allowing users to push and pull over SSH. If the
154+ verification fails the server will fall back to regular public key
155+ identification.
156+
157+ Now that repository is setup let's try to clone it from another computer. We
158+ assume the server is listening at `code.example.org` which we can verify by
159+ opening a regular SSH connection: `ssh ayllu@code.example.org`. With any luck
160+ you should be prompted with the `ayllu-shell` screen you saw in the previous
161+ step. Now that we've confirmed the shell is listening we can clone the
162+ repository over SSH: git clone ayllu@code.example.org:miscellaneous/my-new-repo.
163+
164+ ## REVERSE PROXY CONFIGURATION
165+
166+ Ayllu is designed to be run behind a reverse proxy such as Nginx.
167+
168+ ### EXAMPLE NGINX CONFIG
169+
170+ ```nginx
171+ server {
172+ listen 443 ssl;
173+ server_name forge.example.org;
174+
175+ set $backend "http://127.0.0.1:10000";
176+
177+ location / {
178+ proxy_pass $backend;
179+ proxy_set_header Host $host;
180+ proxy_set_header X-Real-IP $remote_addr;
181+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
182+ }
183+
184+ # Hidden repositories can be password protected if desireable
185+
186+ location ~ /private* {
187+ proxy_pass $backend;
188+ # include proxy.conf;
189+ auth_basic "private";
190+ auth_basic_user_file /etc/nginx/.htpasswd-private-repos;
191+ }
192+ }
193+
194+
195+ # Static sites can simply match a Host header such as below.
196+
197+ server {
198+ listen 443 ssl;
199+ server_name my-website.example.org;
200+
201+ set $backend "http://127.0.0.1:10000";
202+
203+ location / {
204+ proxy_pass $backend;
205+ proxy_set_header Host $host;
206+ proxy_set_header X-Real-IP $remote_addr;
207+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
208+ }
209+
210+ }
211+ ```
212 diff --git a/xtask/src/main.rs b/xtask/src/main.rs
213index 61a3da1..d250f52 100644
214--- a/xtask/src/main.rs
215+++ b/xtask/src/main.rs
216 @@ -15,6 +15,8 @@ const DIST_COMPLETE_PATH: &str = "dist/completion";
217 const DIST_MAN_PATH: &str = "dist/man";
218
219 const AYLLU_SUMMARY: &[u8] = include_bytes!("../../ayllu.7.md");
220+ const AYLLU_TUTORIAL: &[u8] = include_bytes!("../../ayllu-tutorial.7.md");
221+
222 const AYLLU_CONFIG: &str = include_str!("../../ayllu.5.md");
223 const AYLLU_ANNOTATED_EXAMPLE: &str = include_str!("../../config.example.toml");
224
225 @@ -152,6 +154,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
226
227 // Misc man pages
228 md2man(AYLLU_SUMMARY, &man_dir.join("ayllu.7"))?;
229+ md2man(AYLLU_TUTORIAL, &man_dir.join("ayllu-tutorial.7"))?;
230 html_gen(&man_dir.join("ayllu.7"), &man_dir.join("ayllu.7.html"))?;
231 let mut md_input = AYLLU_CONFIG.to_string();
232 md_input.push_str("\n```\n");