anvilsign in

collin/anvil

RenderedSource

1# Deploying anvil on hagrid
2
3anvil runs as a single Docker container at `anvil.richardscollin.com`, fronted by
4hagrid's Caddy reverse proxy.
5
6- **Web** — anvil listens on `:3000` *inside* the container. Caddy (on the
7 `hagrid` Docker network) reverse-proxies to it and provides HTTPS via Let's
8 Encrypt. The web port is **not** published to the host.
9- **SSH** — Caddy only fronts HTTP(S), so anvil's SSH server is **published
10 directly to the host** on `:2222`. Git-over-SSH connects to
11 `anvil.richardscollin.com:2222`.
12- **Runtime** — fully self-contained: SQLite and the SSH crypto are compiled in,
13 and gix is pure-Rust. No git, OpenSSH, or system sqlite in the image.
14
15## 1. DNS
16
17Add an `A`/`AAAA` (or `CNAME` to hagrid) record:
18
19```
20anvil.richardscollin.com -> <hagrid's public IP>
21```
22
23This one record covers both the web (443, via Caddy) and SSH (2222, direct to
24the host).
25
26## 2. Caddy + index (in the hagrid repo)
27
28In `~/Code/hagrid/Caddyfile`, add:
29
30```
31anvil.richardscollin.com {
32 reverse_proxy anvil:3000
33}
34```
35
36In `~/Code/hagrid/sites.yaml`, add an entry:
37
38```yaml
39- name: anvil
40 host: anvil.richardscollin.com
41```
42
43Then reload Caddy (`./hagrid.sh reload`, or `./hagrid.sh deploy` to push to the
44host). Caddy resolves `anvil:3000` by container name over the `hagrid` network,
45so the anvil container must join that network (the run script does this).
46
47## 3. Build & run the container
48
49On the hagrid host, from a checkout of this repo:
50
51```sh
52./deploy/run.sh
53```
54
55That builds `anvil:latest` and runs:
56
57```sh
58docker run -d --name anvil --network hagrid --restart unless-stopped \
59 -p 2222:2222 \
60 -v anvil-data:/data \
61 anvil:latest
62```
63
64- `--network hagrid` — so Caddy can reach `anvil:3000`.
65- `-p 2222:2222` — publishes SSH to the host.
66- `-v anvil-data:/data` — a named volume holding the SQLite DB, the bare repos,
67 and the persistent SSH **host key**. Use a named volume (not a host bind
68 mount) so it's owned by the in-container `anvil` user.
69
70The baked config lives at `/etc/anvil/anvil.toml` (see `deploy/anvil.toml`).
71Override it by bind-mounting your own file over that path.
72
73## 4. First run: create your account, key, and the repo
74
75```sh
76# admin user
77docker exec anvil anvild -c /etc/anvil/anvil.toml \
78 user create collin --email you@example.com --password '<password>' --admin
79
80# your SSH public key (so you can push over SSH)
81docker exec -i anvil anvild -c /etc/anvil/anvil.toml \
82 user add-key collin --title laptop --key "$(cat ~/.ssh/id_ed25519.pub)"
83
84# the anvil repo itself
85docker exec anvil anvild -c /etc/anvil/anvil.toml repo create collin/anvil \
86 --description "a minimal git forge in Rust"
87```
88
89(You can also create the user, add keys, and create repos from the web UI once
90signed in — the CLI is just convenient for the first admin.)
91
92## 5. Self-host anvil on anvil
93
94From your local anvil checkout:
95
96```sh
97git remote add origin ssh://git@anvil.richardscollin.com:2222/collin/anvil.git
98git push -u origin main
99```
100
101Then browse it at `https://anvil.richardscollin.com/collin/anvil`. HTTPS clone
102also works: `git clone https://anvil.richardscollin.com/collin/anvil.git`
103(pushes over HTTPS require your account password as the git password).
104
105## Operations
106
107- **Update**: re-run `./deploy/run.sh` (rebuilds the image, recreates the
108 container; the `anvil-data` volume persists). NOTE: adding new DB tables in a
109 future version won't auto-apply to an existing database yet (Toasty migration
110 support is pending) — the git repos on disk are unaffected, but repo metadata
111 in SQLite may need recreating until migrations land.
112- **Backup**: snapshot the `anvil-data` volume, e.g.
113 `docker run --rm -v anvil-data:/data -v "$PWD":/out debian:bookworm-slim \
114 tar czf /out/anvil-data.tgz -C /data .`
115- **Logs**: `docker logs -f anvil`.
116- **System routes** live under `/-/` (e.g. sign in at
117 `https://anvil.richardscollin.com/-/login`); `/{username}` is the user/repo
118 namespace.