The READMEs still tracked the 2025 migration from bare metal and listed Grafana, Immich, Valheim, Prosody and others that do not run. Replace them with what is deployed, how a change reaches production and where the secrets live. Assisted-by: Claude:fable-5-2
83 lines
3.1 KiB
Markdown
83 lines
3.1 KiB
Markdown
# asxp.io infrastructure
|
|
|
|
Two Hetzner Cloud servers, described by Terraform and configured by
|
|
Ansible. Pushing to `main` deploys: a Forgejo Actions workflow applies
|
|
`ansible/site.yaml` to both servers.
|
|
|
|
## Servers
|
|
|
|
| Server | Size | Runs |
|
|
|--------|------|------|
|
|
| asxpio-ops | 2 vCPU, 4 GB | Traefik, Forgejo, crawler-alert; app stacks deployed from their own repos |
|
|
| asxpio-services | 8 vCPU, 16 GB | Forgejo Actions runner, Minecraft (Paper and Fossils), SillyTavern |
|
|
|
|
Both are reachable for administration only over WireGuard
|
|
(10.20.0.0/24) or the private network (10.10.0.0/20).
|
|
|
|
## Layout
|
|
|
|
- `terraform/`: servers, network, firewalls, object storage buckets.
|
|
- `ansible/site.yaml`: everything the pipeline manages (see below).
|
|
- `ansible/playbooks/`: host bootstrap, run by hand.
|
|
- `.forgejo/workflows/deploy.yaml`: the pipeline.
|
|
|
|
## What the pipeline manages
|
|
|
|
| Role | Host | What |
|
|
|------|------|------|
|
|
| `base` | both | unattended upgrades, fail2ban, journal size cap, Docker daemon config, weekly image prune |
|
|
| `traefik` | ops | reverse proxy, TLS, dashboard on WireGuard |
|
|
| `crawler_alert` | ops | daily and weekly crawler report timers |
|
|
| `forgejo` | ops | Forgejo at git.asxp.io (git.czsk.it is an alias), SSH passthrough |
|
|
| `forgejo_runner` | services | Actions runner and its job labels |
|
|
| `sillytavern` | services | SillyTavern on the WireGuard address |
|
|
| `minecraft`, `minecraft_fossils` | services | game servers, daily restart timer |
|
|
|
|
Not managed here: the app stacks on asxpio-ops (asxpio, datacenterbingo,
|
|
blog, czsk, vhpbot, storage). Each deploys from its own repository into
|
|
`/opt/<app>`.
|
|
|
|
## Changing something
|
|
|
|
1. Edit the role or variable, for example an image tag in
|
|
`ansible/inventory/group_vars/` or a compose file under
|
|
`ansible/roles/<role>/files/`.
|
|
2. Push a branch. The pipeline does a dry run against production.
|
|
3. Merge to `main`. The pipeline dry-runs again, then applies.
|
|
|
|
A run with nothing to change touches nothing and restarts nothing.
|
|
|
|
Things to know:
|
|
|
|
- **Game servers** are saved and stopped with a 120 s timeout before a
|
|
compose change recreates them.
|
|
- **The runner** executes the pipeline. A change to it recreates the
|
|
container mid-job: the change lands, that job is reported as failed,
|
|
and the next run confirms it.
|
|
- **Forgejo** restarts on a config change; the job log may pause for a
|
|
few seconds.
|
|
|
|
To run it yourself, over WireGuard:
|
|
|
|
```sh
|
|
cd ansible
|
|
ansible-playbook site.yaml --check --diff # dry run
|
|
ansible-playbook site.yaml --tags traefik # one service
|
|
```
|
|
|
|
## Secrets
|
|
|
|
Nothing secret is stored in the clear. Service secrets live in
|
|
`ansible/inventory/group_vars/all/vault.yaml`, encrypted with Ansible
|
|
Vault. The pipeline needs two repository secrets:
|
|
|
|
- `ANSIBLE_VAULT_PASSWORD`: decrypts the vault.
|
|
- `SSH_DEPLOY_KEY`: private key of user `deploy` on both servers.
|
|
|
|
Locally, put the vault password in `ansible/.vault_pass` (ignored by git).
|
|
|
|
## Bootstrap (by hand)
|
|
|
|
`ansible/playbooks/` holds what is done once per host or can lock you
|
|
out: WireGuard, SSH hardening, s3fs mounts, swap, user creation.
|
|
See `ansible/README.md`.
|