Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Remove the container deployment

9bce37233413e6a56c38d5cf90e79dfa496649b2 · Keenan Nemetz · 3d ago · parent c1edfd3c

Remove the container deployment

A Vole instance is one process whose state is a directory on local disk. A
container therefore adds a layer without removing one, and it costs
something real: the service unit's hardening, and the CI half, which needs
an OCI runtime the container does not have without mounting the host's
socket — the thing the runner docs refuse.

It was also the weakest path in practice. No image is published, so an
upgrade meant a source checkout and a Go build where the package is one
`apt install`. CI never ran the container; it was tested by hand once, which
is a surface that rots quietly.

So the Dockerfile, the compose file, the entrypoint, the image's
configuration, and the guide go. The deployment checker loses its compose
and COPY checks, and the render script is the only shipped script left.

Every other mention of Docker in the repository means the CI container
runtime, and those stay.

Users who manage their machines with Compose or Kubernetes are told where
they stand: give the forge a small virtual machine of its own, and the
first-boot file works there unchanged.

docs/deploy/docker.md −145

@@ -1,145 +0,0 @@
1 # Vole in a container
2
3 Vole is one process with its own SSH listener, so it fits in one container: no
4 `sshd`, no sidecar, and one volume holding the whole instance.
5
6 ## What you need
7
8 - Docker with the Compose plugin.
9 - A clone of the Vole repository, because the image compiles from source.
10 - A DNS name, and something to terminate TLS. Vole can do TLS itself — see
11 [Let Vole terminate TLS](#let-vole-terminate-tls) — but the default here is a
12 proxy on the same host, which is how most container hosts are already set up.
13 - Your SSH public key.
14
15 ## Build the image
16
17 From the repository root:
18
19 ```sh
20 docker build -f deploy/docker/Dockerfile -t vole:local .
21 ```
22
23 The first build compiles Vole and takes a few minutes; later ones reuse the
24 layers. Nothing about the running instance is in the image: state lives in a
25 volume, and the configuration is a file you mount.
26
27 ## Configure and start
28
29 ```sh
30 cd deploy/docker
31 cp vole.toml ./vole.toml
32 $EDITOR ./vole.toml # set public_url to https://forge.example.com
33 docker compose up -d
34 ```
35
36 `public_url` is the one setting that must be right before anyone signs in:
37 browsers bind a passkey to that address, and changing it later means re-enrolling
38 everyone.
39
40 The default ports are 2222 for Git over SSH and 8080 published on loopback, for a
41 proxy. Port 2222 is a plain TCP port, not HTTP: a proxy cannot route it, so
42 publish it directly.
43
44 Create the first account and make it an instance admin:
45
46 ```sh
47 docker compose exec -T vole admin account create admin --key - < ~/.ssh/id_ed25519.pub
48 docker compose exec vole admin account role admin admin
49 ```
50
51 Pushing works immediately, because the account and the key are written together.
52 The browser needs a passkey, which that command prints when the account has none:
53
54 ```sh
55 docker compose exec vole admin account invite admin
56 ```
57
58 Keep the link private: it is the one thing that grants browser access.
59
60 ## Put TLS in front
61
62 The smallest thing that works is Caddy on the same host:
63
64 ```caddyfile
65 forge.example.com {
66 reverse_proxy 127.0.0.1:8080 {
67 header_up Host {host}
68 }
69 }
70 ```
71
72 Caddy sets `X-Forwarded-For` itself, and `vole.toml` names that header, so the
73 per-client clone limit and the sign-in rate limits see the real address. Whatever
74 proxy you use has to keep the `Host` header unchanged: hosted sites are routed by
75 host name.
76
77 ## Let Vole terminate TLS
78
79 If nothing else on the host serves 80 and 443, Vole can hold the certificate:
80
81 ```toml
82 http_addr = ":80"
83 https_addr = ":443"
84 public_url = "https://forge.example.com"
85 acme_email = "you@example.com"
86 ```
87
88 and in `compose.yaml`, publish `80:80` and `443:443` instead of the loopback 8080.
89 The container runs as an unprivileged user, so add the capability for the two low
90 ports:
91
92 ```yaml
93 cap_add:
94 - NET_BIND_SERVICE
95 ```
96
97 The health check in the packaged `compose.yaml` asks `/healthz` on port 8080,
98 which is the proxy arrangement above. With `https_addr` set, port 80 answers the
99 certificate challenge and redirects everything else, so either point the check at
100 `https://127.0.0.1/healthz` or remove it.
101
102 ## CI runners stay outside
103
104 A runner executes repository code in containers and needs a real OCI runtime, so
105 it does not belong in this container. Run it on the host or another machine and
106 point it at the instance:
107
108 ```sh
109 vole runner --remote ssh://git@forge.example.com:2222 --container-runtime podman
110 ```
111
112 See [CI runners](runner.md) for the machine setup, and [Runners](../runner.md) for
113 every option.
114
115 ## Where the data is, and how to get it out
116
117 The volume holds everything: repositories, the account database, CI history,
118 logs, LFS objects, the SSH host key, and the key that seals repository secrets.
119
120 ```sh
121 docker compose exec vole admin account backup /var/lib/vole/users.db.bak
122 docker compose cp vole:/var/lib/vole/users.db.bak ./users.db.bak
123 ```
124
125 Two files must be copied out separately and kept apart from that backup: the SSH
126 host key, `data/ssh_host_ed25519_key`, and the secrets key, `data/secrets.key`. A
127 backup holding the data directory and that key is a backup of plaintext. The full
128 procedure is in [Operations § Back up an instance](../operations.md#back-up-an-instance).
129
130 A bind mount instead of a named volume works, but the directory has to be writable
131 by the image's user: `sudo chown -R 999:999 /srv/vole`.
132
133 ## Upgrading
134
135 ```sh
136 docker compose exec vole admin account backup /var/lib/vole/users.db.bak
137 docker compose cp vole:/var/lib/vole/users.db.bak ./users.db.bak
138 git pull
139 docker build -f deploy/docker/Dockerfile -t vole:local .
140 docker compose up -d
141 ```
142
143 Back up first: the account database is migrated in place the first time a newer
144 binary reads it, and that migration cannot be undone. A new image also reads the
145 configuration file you mounted, so settings survive.