🏠 Home← Back to .

Self-Hosting Best Practices

A practical reference for securing, maintaining, and operating self-hosted services.


1. Security Foundations

SSH Hardening

SSH is the primary attack vector for automated bots.

  • Disable password authentication β€” use key-based auth only. bash # /etc/ssh/sshd_config PasswordAuthentication no PubkeyAuthentication yes
  • Disable root login over SSH. bash PermitRootLogin no
  • Use Ed25519 keys (not RSA). bash ssh-keygen -t ed25519 -C "your-email@example.com"
  • Change the default port (optional but reduces log noise).
  • Install fail2ban to rate-limit brute-force attempts.
  • Limit SSH access to specific users via AllowUsers.
  • Additional hardening: bash # /etc/ssh/sshd_config ClientAliveInterval 300 ClientAliveCountMax 2 MaxAuthTries 3

Firewall

Enable a host firewall with a default-deny inbound policy.

# UFW (Debian/Ubuntu)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable

Only open ports you actually use. Review open ports regularly:

sudo ss -tlnp

System Updates

Unpatched software is the leading cause of compromise.

  • Enable automatic security updates: bash sudo apt install -y unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades
  • Update the system regularly: bash sudo apt update && sudo apt upgrade -y
  • Subscribe to security advisories for self-hosted applications.

2. Network Security

  • Disable UPnP on your router β€” prevents devices from opening ports without your knowledge.
  • Use VLANs to segment your network (servers, IoT, personal devices).
  • Use Tailscale or WireGuard for remote access instead of port forwarding.
  • Tailscale is recommended for most users β€” WireGuard encryption with automatic key management and NAT traversal.
  • Self-hosted WireGuard or Headscale if you need zero third-party dependency.
  • Disable IPv6 if unused β€” it can bypass IPv4 firewall rules.
  • Minimize port forwarding. Prefer Cloudflare Tunnel for web services.

3. Remote Access β€” Tailscale

Tailscale creates a secure mesh VPN using WireGuard underneath.

Installation:

curl -fsSL https://tailscale.com/install.sh | sudo sh
sudo tailscale up

Benefits: - No port forwarding needed - Devices reach each other by name - NAT traversal works behind most routers/CGNAT - Access controls via ACLs (Tailscale admin console)

Use cases: - SSH into your server from anywhere without exposing port 22 - Access admin interfaces privately (no need to expose to internet) - Treat remote devices as if they’re on the same LAN


4. Reverse Proxy & TLS

  • Force HTTPS everywhere β€” redirect all HTTP to HTTPS.
  • Use Let’s Encrypt / ACME for automatic certificates.
  • Set security headers: text Strict-Transport-Security: max-age=63072000; includeSubDomains; preload X-Content-Type-Options: nosniff X-Frame-Options: DENY Referrer-Policy: strict-origin-when-cross-origin
  • Restrict TLS protocols to 1.2/1.3.
  • Monitor certificate expiry and set alerts for < 14 days.

5. Authentication & Access Control

  • Use strong, unique passwords for every service.
  • Enable two-factor authentication on every supported service.
  • Use a self-hosted password manager like Vaultwarden.
  • Change default credentials immediately after deploying any service.
  • Apply least privilege:
  • Separate admin users from service users.
  • Avoid running services as root.
  • Limit API tokens to only required scopes.
  • Don’t expose admin interfaces (Portainer, database tools) to the internet. Use SSH tunnels or VPN instead.

6. Secrets Management

  • Store secrets in .env files, not in docker-compose.yml or git.
  • Encrypt sensitive configuration with tools like sops + age.
  • Never commit credentials to git β€” even in private repos.
  • Automate rotation where supported (database passwords, API tokens).
  • Store backup passwords separately from backup data.

7. Logging & Monitoring

What to Log

  • SSH logins (success and failure)
  • sudo invocations
  • Firewall drop events
  • Application errors and access logs
  • Systemd service state changes

Monitoring Stack

  • Uptime monitoring: Uptime Kuma, Healthchecks.io
  • System metrics: Netdata, Grafana + Prometheus
  • Logs: Ship logs off-host; use Grafana Loki or a remote syslog target

Alerts to Configure

Event Signal Threshold
SSH brute force Failed logins > 10 in 5 min
New SSH source IP Success from new address Any
Service down systemd active state failed
Disk full filesystem usage > 85%
TLS cert expiry days_until_expiry < 14 days
Unexpected sudo sudo log line Any non-whitelisted command

Monthly Review

  • Check auth logs
  • Run system updates
  • Review fail2ban bans
  • Scan open ports
  • Test a backup restore

8. Backup Strategy (3-2-1 Rule)

  • 3 copies β€” live data + 2 backups
  • 2 different media β€” e.g., SSD + HDD, local + cloud
  • 1 offsite β€” physically separate from the server

What to Back Up

Data Type Priority Frequency
Application databases Critical Every 4-6 hours
User-generated content Critical Daily
Configuration files High Daily or on change
Docker volumes High Daily
Media libraries Medium Weekly
Logs Low Optional

Tools

  • Restic β€” fast, always encrypted, works with every backend (local, S3, Backblaze B2, etc.)
  • BorgBackup β€” best dedup ratio for large datasets
  • Kopia β€” CLI + GUI option
  • Duplicati β€” beginner-friendly web UI

Automation

Prefer systemd timers over cron for better logging and dependency handling.

Test Restores Monthly

A backup you haven’t tested is not a backup.

restic -r /path/to/repo snapshots
restic -r /path/to/repo restore latest --target /tmp/restore-test

Monitor Backups

  • Heartbeat monitoring (Uptime Kuma, Healthchecks.io)
  • Alert if newest snapshot is older than 48 hours
  • Check backup volume free space

9. Maintenance Schedule

Frequency Task
Daily Automated security updates, backups run
Weekly apt update && apt upgrade -y, review auth logs
Monthly Fail2ban stats, port scan, Lynis audit, backup restore test
Quarterly Service inventory review, update runbooks, DR test
Annually Major OS upgrades, hardware health checks

10. Incident Response

  • Keep an inventory of services, versions, and patch dates.
  • Document recovery procedures for each service.
  • Know how to restore from backup before you need it.
  • Have a rollback plan for updates.
  • Run a firewall: ufw / nftables with default deny.
  • Block brute force: fail2ban on SSH and web services.
  • Patch automatically: unattended-upgrades for security fixes.
  • Use key-only SSH, disable root, rate-limit ports.
  • Back up offsite, encrypted, with tested restores.

11. Recommended Tooling

Category Tools
Firewall UFW, nftables
SSH hardening fail2ban, sshd_config tuning
Reverse proxy Nginx, Caddy, Traefik
SSL Certbot, acme.sh, Caddy (auto)
Monitoring Netdata, Grafana + Prometheus, Uptime Kuma
Backups Restic, BorgBackup, Duplicati
Security scanning Lynis, Trivy (container images)
Logging Grafana Loki, rsyslog β†’ remote target
Remote access Tailscale, WireGuard, Cloudflare Tunnel
Password manager Vaultwarden
Intrusion detection AIDE, auditd, Wazuh (optional)

Sources


Related Notes