- Shell 42.6%
- JavaScript 38.6%
- Dockerfile 11.5%
- HCL 7.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| caddy | ||
| dns | ||
| doco-cd | ||
| forgejo | ||
| hypercomics | ||
| rustfs | ||
| sharp | ||
| .doco-cd.yml | ||
| bootstrap.sh | ||
| README.md | ||
| site.env | ||
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 | Watches the bare repos in /srv/git, runs docker compose up (with build:) on every push, updates itself |
| 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 | The forge at git.fuckingtech.ch: account and repos declared in site.env + forgejo/, hydrated on every deploy |
Layers
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..doco-cd.yml+*/compose.yaml: the base stacks (doco-cd, caddy, gitore). doco-cd applies them on every push tomain.- Apps: each app repository carries its own
.doco-cd.ymland compose file, and is listed indoco-cd/compose.yaml'sPOLL_CONFIG.
Use
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:
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).
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.