- Jinja 44.8%
- Python 34.6%
- HCL 20.6%
|
Some checks failed
nixos / asxpio-services (push) Failing after 54s
Renovate now runs from its own repository for every repo, with the shared rules in its preset. Extend that preset here and keep only what is specific to this repo (the Ansible var manager, the Paper JRE, the runner and nix notes); drop the workflow that ran it for iac alone. Assisted-by: Claude:opus-5-5 |
||
|---|---|---|
| .forgejo/workflows | ||
| ansible | ||
| nixos | ||
| terraform | ||
| .gitignore | ||
| README.md | ||
| renovate.json | ||
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), SillyTavern, XMPP (asxp.io), Xray |
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 |
services | Paper server |
xmpp |
services | ejabberd, apushd and tackygram for asxp.io; secrets stay in /opt/xmpp/state |
xray |
services | Xray VLESS Reality on :443, config in the vault |
restic_backup |
both | nightly restic backup to object storage, hel1 and fsn1 |
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
- Edit the role or variable, for example an image tag in
ansible/inventory/group_vars/or a compose file underansible/roles/<role>/files/. - Push a branch. The pipeline does a dry run against production.
- Merge to
main. The pipeline dry-runs again, then applies.
A run with nothing to change touches nothing and restarts nothing.
Backups
Hetzner's server backups are off. Each host runs restic-backup.timer
nightly (ops 03:30, services 04:15 UTC) into two independent
repositories, restic/<host> in asxpio-backups-main (hel1) and
asxpio-backups-repl (fsn1). Databases go in as dumps or online
copies; see restic_pre_hooks in ansible/inventory/host_vars/.
A failed run mails its journal.
restic-backup hel1 snapshots
restic-backup fsn1 restore latest --target /tmp/restore --include /opt/xmpp
The password is vault_restic_password in the vault. Keep a copy
outside the servers and this repo's CI: without it nothing can be read.
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:
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 userdeployon 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.