Commit graph

18 commits

Author SHA1 Message Date
59b5b4468a ansible: nightly restic backups to both object storage regions
Hetzner's server backups cost 20% of each server's price and only
restore whole disks. Back up what matters with restic instead, into the
backup buckets we already pay for: one repository per host in hel1
(asxpio-backups-main) and one in fsn1 (asxpio-backups-repl), written
independently so either region alone is a full copy.

Postgres goes in as a dump, Forgejo's and vhpbot's SQLite databases
through the online backup API, Garage with a fresh metadata snapshot,
ejabberd through its own backup command. Keeps 7 daily, 4 weekly and
6 monthly snapshots, prunes on Sundays, and mails the journal when a
run fails.

restic is the pinned upstream release, so its version is tracked in
the repo like everything else. The vault gains the restic password
and the Xray config for the role that follows.

Assisted-by: Claude:opus-5-5
2026-11-12 20:53:44 +04:00
f00505a27d base: drop the one-off crontab migration
The prune job now lives in /etc/cron.d on both hosts and root's crontab
entry is gone, so the tasks that removed it have nothing left to do.

Assisted-by: Claude:fable-5-2
2026-11-12 07:01:07 +04:00
33fbc06681 base: do not fail when the prune entry is root's only cron line
grep -v exits 1 when it prints nothing, and with pipefail that failed
the task on both hosts, although the crontab had been rewritten
correctly. Ignore grep's exit status.

Assisted-by: Claude:fable-5-2
2026-11-12 06:50:37 +04:00
e76d2a022c docs: describe the servers as they are
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
2026-11-12 06:47:09 +04:00
63bd67a86d ci: deploy site.yaml from Forgejo Actions
Service changes were made by hand on the servers, which is how the
repository drifted. Apply site.yaml from a workflow instead: every
push dry-runs it against production, and a push to main applies it.

Jobs run in containers on asxpio-services. asxpio-ops is reached over
the private network; the services host is reached through asxpio-ops,
because a container connecting to its own host arrives from a Docker
bridge address that sshd and the firewall refuse. Host keys are pinned
in known_hosts.

Ansible comes from a pinned nixpkgs revision so every run uses the
same version.

Assisted-by: Claude:fable-5-2
2026-11-12 06:47:09 +04:00
27ccdc4255 ansible: describe what runs on the servers
The roles had drifted far from production: Forgejo was pinned at 12
while 15.0.11 runs, its config lacked the mailer, packages and the real
database path, and several services existed only on the hosts. Running
a role would have rolled production back. Take the servers as the truth
and make the repository match them.

site.yaml now holds the desired state of both hosts:

 - base: unattended upgrades, fail2ban, Docker daemon config and the
   weekly image prune, as found on the hosts. New: a 500M journal cap,
   and the Docker systemd override is kept absent. That override once
   opened dockerd on tcp/2375 without authentication.
 - traefik: templates as deployed, version in a variable (v3.7.18).
   The Coraza WAF files are removed; no router ever used them.
 - forgejo: 15.0.11, app.ini generated from the live file with the
   secrets taken from the vault.
 - crawler_alert, sillytavern, minecraft, minecraft_fossils: added
   from the hosts.

Forgejo's canonical name becomes git.asxp.io; git.czsk.it stays as an
alias on the same router.

docker_service restarts a stack when its config changes, no longer
forces ownership on existing data directories, and hides template
diffs because they carry secrets. Containers listed in
service_graceful_stop are saved and stopped with a long timeout before
compose recreates them: Docker's 10 s default is too short for a
Minecraft world. Both game servers get stop_grace_period for the same
reason.

Removed: the full-deployment and runner playbooks with their prompts,
the Forgejo backup and restore roles for the old bare-metal host, and
inventory entries for services that were never deployed. SSH hardening
stays a manual playbook, since a mistake there locks everyone out.

New secrets (SMTP, RCON, CurseForge key) went into the vault.

Assisted-by: Claude:fable-5-2
2026-11-12 06:47:08 +04:00
a79b110259 forgejo-runner: match the live runner and pin the nix image
The role had drifted from what runs on asxpio-services: capacity 4,
a bridge network per workflow so service containers start, the Docker
socket automounted into jobs, and a nix-latest label backed by a
persistent nix-store volume.

That volume caused a CI outage on 2026-10-18. nixos/nix:latest moved on,
and since the image's /bin/sh and /etc/nix/nix.conf link into /nix/store,
the old volume left them dangling. Pin the image through
forgejo_runner_nix_version and name the volume after it, so a bump is
deliberate and always gets a store seeded from its own image.

Assisted-by: Claude:opus-5-5
2026-10-18 09:48:14 +04:00
0af23425f9 swap: add a swapfile role, 2 GB on asxpio-ops
The ops server has 3.7 GB RAM and no swap. Forgejo, MinIO and the apps
fit with room to spare, but a spike (a big push, git gc, parallel
image pulls) would OOM-kill a service instead of paging out.

swappiness 10, so it only swaps under real pressure.

Assisted-by: Claude:opus-5
2026-10-12 05:31:32 +04:00
66ab6d8db3 s3fs: allow turning the mounts off, off on asxpio-ops
On the 38 GB ops disk the s3fs cache reserve (ensure_diskfree) never
fit, so all three mounts failed at every boot since 2026-09-22. Backups
now go to Hetzner S3 with rclone instead.

Add s3fs_enabled (default true); when false the role unmounts the
buckets and drops their fstab entries, keeping the credentials file
that the rclone wrapper reads.

Assisted-by: Claude:opus-5
2026-10-12 05:03:11 +04:00
ad056c97dc ssh: add user zerrtika 2026-08-13 07:04:04 +04:00
b717a4194d add wg: sanya 2026-04-05 19:17:18 +03:00
a7449512b1 zerrtika wg 2026-03-10 23:27:31 +02:00
8581835ebe wg aleks 2025-12-26 02:45:17 +02:00
f6c583ddfc ssh managment 2025-11-09 11:58:19 +02:00
8ef380bc9b ansible cleanup 2025-11-04 14:23:16 +02:00
eecff4345a ansible rework 2025-11-04 11:06:35 +02:00
67414814c0 ansible 2025-11-01 22:46:38 +02:00
b81f7e15b2 ansible 2025-11-01 17:15:42 +02:00