SafeServerSetup
All case studies · Sample engagement · representative numbers

Hardened a fresh DigitalOcean droplet for a Laravel SaaS launch

Fresh droplet, two days from launch, no time to learn UFW.

Customer
Indie SaaS founder
Team size
1 person
Provider
DigitalOcean
OS
Ubuntu 24.04 LTS
Plan · Duration
Standard · 18 hours
Engagement summary

A solo founder spinning up a Laravel SaaS on a $24/mo DigitalOcean droplet. They wanted to launch on Friday and didn't want to spend Thursday reading firewall blog posts. We took the box from a default install to production-ready overnight.

Why they came to us

They'd shipped product-side code for years but had never personally locked down a Linux box. The Friday launch was a hard date — investor demo. Hiring a contractor felt heavy for a one-time job; they wanted "the boring stuff handled" so they could spend Thursday polishing onboarding.

Audit findings

What we found on the box.

First pass before changing anything. Severity ranges from critical (act immediately) to low (worth knowing).

  • SSH on port 22 with password authentication enabled

    critical
  • Root account accepting interactive logins

    critical
  • No host firewall — every listening port reachable from the internet

    critical
  • 31 days of unapplied security patches

    high
  • No fail2ban or equivalent brute-force protection

    high
  • NGINX exposing version banner via server_tokens on

    medium
  • TLS 1.0 / 1.1 still enabled on the default vhost

    medium
  • No swap configured (1GB RAM box, app would OOM under modest load)

    low
Hardening applied

What we changed, in order.

Each change is reversible and documented in the handover doc. Commands shown are illustrative.

  1. 1

    Created a deploy sudo user and installed the founder's ed25519 public key.

  2. 2

    Wrote /etc/ssh/sshd_config.d/90-hardened.conf: PermitRootLogin no, PasswordAuthentication no, KbdInteractiveAuthentication no, MaxAuthTries 3.

  3. 3

    Moved SSH off the default port and updated the DigitalOcean cloud firewall to match.

  4. 4

    UFW: default deny incoming, allow outgoing, plus the SSH port + 80/443. IPv6 enabled and verified.

  5. 5

    fail2ban with the SSH jail enabled, bantime=24h, findtime=15m, maxretry=3.

  6. 6

    unattended-upgrades configured for security patches with a 04:00 maintenance reboot window.

  7. 7

    Provisioned a 2GB swap file and set vm.swappiness=10.

  8. 8

    NGINX: HTTP/2, TLS 1.2 and 1.3 only, Mozilla Intermediate cipher list, HSTS with a 1-year max-age.

  9. 9

    Issued a Let's Encrypt cert via certbot and verified the renewal timer was firing.

  10. 10

    logrotate configured for application and access logs.

Before / after

The numbers that moved.

Representative figures from this engagement. Real, named-customer studies will publish actual numbers with a link to verify.

Open ports (external scan)
Before
21
After
3
SSL Labs rating
Before
F
After
A+
Patch lag
Before
31 days
After
0 days
SSH bot attempts / day
Before
4,800
After
~0
Security headers set
Before
0 / 6
After
6 / 6
Ready to be the next one

Hand us your VPS, get an engagement like this one.

Pick a plan, send the credentials through the encrypted form, and we'll come back with the same kind of audit + hardening + handover the studies above describe.