66 lines
3.3 KiB
Markdown
66 lines
3.3 KiB
Markdown
# head-vps
|
|
|
|
The HEAD VPS (`185.143.103.191`, Ubuntu 24.04, 4 vCPU, 3.8 GB) as code. Everything it runs is in
|
|
this repository; a `git push` to the bare repo on the VPS deploys it. No CI, no external forge.
|
|
|
|
| Piece | Role |
|
|
|---|---|
|
|
| [doco-cd](https://doco.cd) | Watches the bare repos in `/srv/git`, runs `docker compose up` (with `build:`) on every push, updates itself |
|
|
| [caddy-docker-proxy](https://github.com/lucaslorentz/caddy-docker-proxy) | Reverse proxy with automatic HTTPS, configured by `caddy.*` labels on containers |
|
|
| RustFS (`rustfs/`) | The S3 of every app: API at `s3.fuckingtech.ch`, public media at `assets.fuckingtech.ch` |
|
|
| sharp (`sharp/`) | Image transformer at `sharp.fuckingtech.ch` (from `nestarz/remove-background`, without background removal) |
|
|
| [Forgejo](https://forgejo.org) | The forge at git.fuckingtech.ch: account and repos declared in `site.env` + `forgejo/`, hydrated on every deploy |
|
|
|
|
## Layers
|
|
|
|
1. **`bootstrap.sh`**: only to rebuild the host from scratch (`ssh fuckingtech.ch 'sudo bash -s -- <app repos>' < bootstrap.sh`,
|
|
push, run again) or to create a new app's bare repo; doco-cd manages everything else, itself included.
|
|
2. **`.doco-cd.yml` + `*/compose.yaml`**: the base stacks (doco-cd, caddy, gitore). doco-cd applies them
|
|
on every push to `main`.
|
|
3. **Apps**: each app repository carries its own `.doco-cd.yml` and compose file, and is listed in
|
|
`doco-cd/compose.yaml`'s `POLL_CONFIG`.
|
|
|
|
## Use
|
|
|
|
```sh
|
|
git remote add forge ssh://git@git.fuckingtech.ch:2222/headpoolnumerique/head-vps.git
|
|
git push forge main # deploys; follow with: ssh fuckingtech.ch 'docker logs -f doco-cd-doco-cd-2'
|
|
```
|
|
|
|
Repositories belong to the organisation `headpoolnumerique` (public to read); Forgejo stores them in
|
|
`/srv/git/headpoolnumerique/<name>.git`, where doco-cd reads them.
|
|
|
|
A site is two labels on a container that joins the external `caddy` network:
|
|
|
|
```yaml
|
|
labels:
|
|
caddy: storytellurx.fuckingtech.ch
|
|
caddy.reverse_proxy: "{{upstreams 8000}}"
|
|
```
|
|
|
|
## Certificates
|
|
|
|
Caddy keeps its certificates and ACME account in the `caddy_data` volume: restarts and redeploys reuse
|
|
them and never count against Let's Encrypt, and renewal is automatic. Let's Encrypt allows 5 failed
|
|
validations per name per hour, so **a new name goes in this order: DNS record first, Caddy label after**.
|
|
A label published while the name points elsewhere fails on every retry and locks the name out.
|
|
|
|
## DNS
|
|
|
|
`dns/` (OpenTofu, official `Infomaniak/infomaniak` provider) declares only the records that point at
|
|
the VPS: A and AAAA for `storytellurx`, `v1.storytellurx`, `git` in `fuckingtech.ch`.
|
|
Each `infomaniak_record` is a single record, so nothing else in a zone is read or changed.
|
|
|
|
It is a workflow run **by the VPS**: the `dns` stack (in `.doco-cd.yml`) builds `dns/Dockerfile`
|
|
(OpenTofu + fnox + the provider) and runs `apply.sh` once whenever `dns/` changes. The token
|
|
(scopes `dns:read dns:write`) and the state passphrase are in `dns/fnox.toml` (recipients: Elias, the
|
|
VPS); the state lives in the VPS's `dns_state` volume, encrypted (OpenTofu state encryption, AES-GCM).
|
|
|
|
```sh
|
|
ssh fuckingtech.ch 'docker logs dns-apply-1' # the last run's plan and apply
|
|
```
|
|
|
|
## Mirror
|
|
|
|
`github.com/bureaudouble/head-vps` (private) is a copy, pushed alongside: `git push forge main && git push github main`.
|
|
Deployments only ever come from Forgejo's repositories on the VPS.
|