Since 25-Oct-2026 the operating-system settings of host-1.rachelski.net are kept as an Ansible playbook in the debian-host-1 Gitea repo. Instead of changing settings by hand on the server, you change the files in the repo and let Ansible apply them. Ansible connects over SSH as mark and uses sudo; nothing needs installing on host-1.
| Area (tag) | What Ansible keeps in place |
|---|---|
unattended_upgrades |
Security updates install automatically, and the server reboots at 20:00 UTC (03:00 Bangkok) when an update needs it |
ssh |
Root can't log in over SSH, password logins are off, X11 forwarding is off, 3 login attempts max. The file is checked with sshd -t before SSH is reloaded, so a mistake can't lock you out |
crowdsec |
CrowdSec's collections, reading traefik's log, and the firewall rule that also blocks banned IPs from the websites |
kopia |
The nightly backup to the data-barn-1 storage box (19:30 UTC) and its settings |
tailscale |
The Tailscale client, kept up to date automatically, and host-1's membership of our tailnet (host-1.rachelski.tailnet, tag:host-1). See "SSH to host-1 over the tailnet" on the host-1 page |
It does not manage the containers (traefik, Keycloak, headscale, …). Each of those is deployed from its own repo.
Ansible lives in a Python environment inside the project folder, so nothing is installed system-wide and the Ansible version is pinned in requirements.txt.
Use a normal terminal, not VS Code's built-in one. VS Code is installed as a Flatpak, and its terminal sees a different Python, so the environment won't work there. In VS Code you can run
flatpak-spawn --host bashfirst to get a normal shell.
git clone ssh://docker-automation@192.168.200.155:2222/mark/debian-host-1.git ~/projects/cloud/debian-host-1
cd ~/projects/cloud/debian-host-1
/usr/bin/python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/pip install -r requirements.txt
.venv/bin/ansible --version # should show the version pinned in requirements.txt
You also need a device on the tailnet that the access policy lets reach host-1, because port 22 is closed to the internet. Since 25-Oct-2026 the playbook's inventory.yml connects to host-1.rachelski.tailnet by itself, using the key ~/.ssh/id_ed25519_host1, so it doesn't depend on your ~/.ssh/config. Check it with ssh mark@host-1.rachelski.tailnet true. Using a different key? Change ansible_ssh_private_key_file in inventory.yml.
To upgrade Ansible, change the version in requirements.txt and re-run the pip install line. To start over, delete the .venv folder and repeat the setup.
Every run asks for BECOME password:, which is mark's sudo password on host-1.
cd ~/projects/cloud/debian-host-1
# 1. Always do a dry run first: shows what WOULD change, changes nothing
.venv/bin/ansible-playbook site.yml --check --diff
# 2. Apply for real
.venv/bin/ansible-playbook site.yml
# Only one area, e.g. just CrowdSec
.venv/bin/ansible-playbook site.yml --tags crowdsec
If you prefer shorter commands, run source .venv/bin/activate once per terminal session and then just type ansible-playbook …; deactivate turns it off again.
The summary line at the end looks like ok=17 changed=0 failed=0:
--diff output shows exactly what.When nobody has changed anything by hand, a dry run should end with changed=0. Anything else means the server has drifted from the repo, and the diff shows how.
No passwords or keys are stored in the repo.
kopia repository password: only needed if kopia ever has to be connected again (for example on a rebuilt server). It's in BitWarden as kopia - host-1.rachelski.net repository. Enter it like this, so it isn't shown on screen or saved in your shell history:
read -rsp 'Kopia repository password: ' KOPIA_PASSWORD; echo; export KOPIA_PASSWORD
.venv/bin/ansible-playbook site.yml --tags kopia
unset KOPIA_PASSWORD
Tailscale join key: only needed when host-1 joins the tailnet (the first time, or after a rebuild). It's a one-time key that you create in headscale right before the run. It's valid for 30 minutes and can only be used once:
ssh mark@host-1.rachelski.tailnet 'docker exec headscale headscale preauthkeys create --user 1 --tags tag:host-1 --expiration 30m'
read -rsp 'Tailscale key: ' TS_AUTHKEY; echo; export TS_AUTHKEY
.venv/bin/ansible-playbook site.yml --tags tailscale
unset TS_AUTHKEY
The tag must come from the key. Don't add --advertise-tags anywhere: headscale then rejects the join with requested tags ... are invalid or not permitted.
CrowdSec's API keys: they stay on host-1; Ansible leaves them alone.
| You see | Likely cause |
|---|---|
Missing sudo password or Incorrect sudo password |
Typo at the BECOME password: prompt. Use mark's sudo password on host-1 |
ModuleNotFoundError: No module named 'ansible' or Python errors |
Running from VS Code's built-in terminal (see the Flatpak note above), or .venv wasn't created |
UNREACHABLE / SSH errors |
Check ssh mark@host-1.rachelski.tailnet true works on its own first. If it doesn't, check tailscale status: your device must be on the tailnet |
| You changed SSH settings and can't get back in | Use the Hetzner Cloud console, which doesn't use SSH, and fix or remove /etc/ssh/sshd_config.d/10-hardening.conf |