Skip to content

Cybersecurity

Self-hosting security: a hardening checklist for a home server or VPS

A practical order of operations for securing a self-hosted server: SSH keys, firewall, updates, a reverse proxy with TLS, backups, monitoring and keeping admin panels off the internet.

By · Published · 3 min read

Short answer: most self-hosted compromises come from a short list of mistakes: password SSH login, services published directly to the internet, unpatched software, default credentials and no backups. Fix those in order: SSH keys, a default-deny firewall, automatic updates, everything behind a reverse proxy with TLS, admin panels reachable only over a VPN, and tested backups.

What do attackers actually do?

Put a server on a public IP address and within minutes you will see automated login attempts. Bots scan for open SSH, exposed databases, admin panels and known-vulnerable web apps. They are not targeting you. They try everything on everyone. Your job is to not be the easy one.

1. Lock down SSH

# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AllowUsers deploy

Test a second login in a new terminal before you close the first, then run sudo systemctl reload ssh. Keys are far stronger than passwords. Changing the port reduces log noise and is not a real defence. A tool like fail2ban can ban repeated failures.

2. Default-deny firewall

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80,443/tcp
sudo ufw enable

Remember that Docker adds its own rules and can publish ports around ufw. Bind container ports to 127.0.0.1 unless they must be public. A cloud provider's network firewall is a second layer.

3. Keep everything updated

  • Enable unattended security upgrades on the host (unattended-upgrades on Debian and Ubuntu).
  • Update container images on a schedule. Pin versions and read release notes for the apps that matter.
  • Subscribe to the security announcements of the software you expose.

4. Put services behind a reverse proxy with TLS

One entry point means one place for certificates, headers, rate limits and logs. Only ports 80 and 443 face the internet. Details are in reverse proxy security hardening.

5. Keep admin interfaces off the public internet

Database consoles, Portainer, Proxmox, router panels, Grafana, your automation tool's editor: put them behind a VPN such as WireGuard or Tailscale, or an identity-aware proxy. Anything with a login page on a public address will be attacked.

6. Remove default and shared credentials

  • Change every default password on first start. Create the admin account on installation, not later.
  • Use a password manager and unique passwords per service.
  • Turn on two-factor authentication for anything that supports it.
  • Give each service its own database user with only the rights it needs.

7. Backups you have restored

A backup is real when you have restored it. Follow the 3-2-1 idea: three copies, two kinds of media, one off-site. Encrypt the off-site copy and store the key separately. Practise a restore on a spare machine. I wrote about doing this for a database in restore drill for PostgreSQL business software, and about what happens without it in recovering from self-hosted data loss.

8. Watch and alert

  • Collect logs somewhere that survives the server being wiped.
  • Use uptime monitoring from outside your network.
  • Alert on disk space, certificate expiry, failed backups and unexpected new listening ports (ss -tulpn).

9. Limit the blast radius

  • Run services as non-root users and in containers with restricted settings.
  • Separate untrusted or experimental apps onto another VM or VLAN.
  • Do not reuse the same credentials across services.

A quick audit

sudo ss -tulpn                  # what is listening
sudo ufw status verbose         # firewall rules
docker ps --format '{{.Names}}\t{{.Ports}}'
sudo last -a | head             # recent logins
sudo grep 'Failed password' /var/log/auth.log | tail

If anything in that output surprises you, you have found your first task.

References

Author

Raktim Ranjit is a software engineer and the founder of NodeDR Infotech. He builds and maintains the software described here.

Have something in mind?

Let’s build something useful.

Tell me about the idea, product, or workflow you’re working through.

Tap to say hello