Layout, Validation, and Operations Runbook
Use one inspected service root:
sudo mkdir -p /srv/{caddy,rsshub,infohub,uptime-kuma,backups}
sudo chown -R "$VPS_USER:$VPS_USER" /srv
Never recursively change ownership before checking existing content. An empty /srv/backups directory is not a backup system; recovery needs schedules, versions, off-site copies, and restore tests.
systemctl is-active asks whether a service runs now; is-enabled asks whether it starts on boot. Diagnose with:
systemctl --failed --no-pager
sudo journalctl -u docker --since today --no-pager
sudo journalctl -u tailscaled --since today --no-pager
Redact logs before sharing them. For updates, run apt update, inspect apt list --upgradable, and then apt upgrade. Simulate risky automated changes with apt-get -s. Phased ordinary updates may be deferred intentionally.
Check /var/run/reboot-required; before rebooting, verify Tailscale access, keep a session, reboot deliberately, reconnect, and recheck the kernel and failed units.
Validation checklist
hostnamectl; timedatectl
nproc; free -h; df -h /
ip -brief addr; ip route
tailscale status; tailscale ip -4
sudo ufw status verbose
sudo sshd -t
sudo sshd -T | grep -E \
'^(permitrootlogin|passwordauthentication|pubkeyauthentication) '
docker --version; docker compose version
systemctl is-active docker tailscaled
docker info
docker ps -a
systemctl --failed --no-pager
find /srv -maxdepth 2 -printf '%M %u:%g %p\n' | sort
From WSL2, a fresh Tailscale SSH transport must pass and a fresh public-IP SSH attempt must fail. After every deployment, check the related service, UFW, and docker ps; weekly check updates, failed units, disk, and containers; monthly review tailnet devices, keys, exposed ports, and log growth.
During an incident: preserve access, stop widening the change, identify the failing layer, collect non-secret evidence, restore the nearest safe state, and verify recovery with a new connection or full request. Use Tmux for long work, but remember that it survives SSH disconnects, not host reboots.