22 Jun 2026
·
8 min read
·
DevOps · Linux · Security
Hardening a DigitalOcean Droplet in an Afternoon
The checklist I run on every server I own for a client platform: firewall, SSH, fail2ban, WireGuard for admin access, TLS, and monitoring. Nothing exotic — just done every time.
I own the servers behind the platforms my team ships. That means when something is exposed, it is my problem, so I stopped treating hardening as a task for later and turned it into a fixed sequence I run on every new droplet before a single container starts. It takes an afternoon, and it has held up.
1. Baseline
Update everything, create a non-root user with sudo, and set the timezone and hostname. Boring, but every later step assumes it.
2. Firewall: deny by default
UFW with a default deny policy, then open only what the platform needs. On a typical box that is SSH, HTTP, and HTTPS. Database ports stay closed to the world; containers talk over the Docker network.
One thing to know: Docker manipulates iptables directly and can bypass UFW rules for published ports. I publish container ports only on 127.0.0.1 and let Nginx be the only thing that faces the internet.
3. SSH: keys only, and fail2ban behind it
Password authentication off, root login off, keys only. Then fail2ban watches the auth log and bans repeat offenders. Even with keys only, the noise from bots is real; banning them keeps the logs readable.
4. WireGuard for anything administrative
Dashboards, database admin tools, monitoring — anything that is not the public site — should not be on the public internet at all. A WireGuard tunnel takes fifteen minutes to set up and moves all of it onto a private address. Nginx then serves those tools only on the WireGuard interface.
5. TLS without thinking about it
Let’s Encrypt with automatic renewal, or Cloudflare in front when the client already uses it. Either way the rule is the same: HTTPS everywhere, HTTP only redirects, and modern ciphers in Nginx. Certificate expiry is the most common self-inflicted outage I have seen; renewal is a systemd timer, not a calendar reminder.
6. Monitoring you will actually look at
I run Beszel, a lightweight monitoring server with an agent per droplet. CPU, memory, disk, network, and container stats in one place, with alerts to the team chat. It is not Grafana, and that is the point — nobody on a fifteen-person team has time to babysit dashboards. A single page that turns red is enough.
The checklist
Non-root deploy user, sudo, timezone
UFW default deny; only 22, 80, 443 open
Container ports bound to 127.0.0.1; Nginx is the only public face
SSH keys only, no root login, fail2ban on
WireGuard for every admin surface
TLS with automatic renewal
Beszel agent reporting before the first deploy
None of this is clever. Its value is that it happens every time, in the same order, before the platform goes live — which is the only kind of security that survives a busy delivery team.
Written by Lasha Kakashvili — Tech Lead at Koober Coders, instructor at IT Step Academy.