selfhostedops-stack/HARDENING.md

2.8 KiB

~$ Hardening checklist

This is the non-negotiable baseline before real company data touches the box. Every item is copy-paste ready for Debian/Ubuntu.

1. SSH: keys only, no root

adduser ops && usermod -aG sudo,docker ops
mkdir -p /home/ops/.ssh && cp ~/.ssh/authorized_keys /home/ops/.ssh/ \
  && chown -R ops:ops /home/ops/.ssh && chmod 700 /home/ops/.ssh

/etc/ssh/sshd_config.d/hardening.conf:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
systemctl restart ssh
# TEST A NEW SSH SESSION BEFORE CLOSING THIS ONE.

2. Firewall — four ports, nothing else

apt install -y ufw
ufw default deny incoming
ufw allow 80/tcp 443/tcp 443/udp   # caddy (http/https/h3)
ufw allow 2222/tcp                 # git ssh
ufw allow 51820/udp                # wireguard (only if using --profile vpn)
ufw allow 22/tcp                   # your ssh (move it if you want)
ufw enable

Note: Docker's published ports bypass ufw INPUT rules — that's exactly why this compose file publishes only caddy, git-ssh and wireguard, and keeps postgres/redis on the internal network with no ports at all. Don't add ports: to internal services "for debugging" and forget them.

3. Automatic security updates

apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

4. fail2ban (ssh brute force)

apt install -y fail2ban   # default ssh jail is enough to start

5. Vaultwarden specifics

  • VAULTWARDEN_SIGNUPS_ALLOWED=false the moment your team is on board.
  • Use an argon2 ADMIN_TOKEN (vaultwarden hash / see wiki), not a plain string.
  • The admin panel (/admin) is for setup — consider blocking it in Caddy afterwards:
vault.{$DOMAIN} {
	@admin path /admin*
	respond @admin 404
	reverse_proxy vaultwarden:80
}

6. Pin your images

latest is fine on day one, dangerous on day 300. Pin majors at minimum (caddy:2-alpine, forgejo:11, uptime-kuma:1 already are). Watchtower blindly auto-updating a password manager at 3 a.m. is how you get incidents — update deliberately: docker compose pull && docker compose up -d after reading release notes. n8n and Outline move fast; Vaultwarden occasionally has breaking web-vault pairs.

7. Backups (minimum viable, today)

# stop, snapshot volumes, start — cron it nightly until Episode 10 (borgmatic offsite)
docker compose stop
tar czf /backup/stack-$(date +%F).tgz -C /var/lib/docker/volumes .
docker compose start

Plus: enable your provider's server snapshots. Two clicks, saves your company.

8. What this list is NOT

Not covered here, on purpose (own episodes): SSO everywhere, 2FA enforcement per service, Netbird zero-trust mesh, central logging, CrowdSec, offsite borg. Baseline first. Perfect later.