Tag: server management

  • What Hardening a Production Server Actually Looks Like

    What Hardening a Production Server Actually Looks Like

    There’s a version of “server hardening” that exists in compliance documents: a tidy checklist, a one-time audit, a box ticked. Then there’s what it actually looks like in production — messy, iterative, and never quite finished.

    I’ve spent the last several weeks hardening infrastructure across multiple environments, and the pattern is always the same. What was secure at deployment drifts. Defaults get forgotten. Services get bolted on. And suddenly the thing you trusted is quietly doing something you never intended.

    Here’s what the real work looks like.

    The Problem Nobody Warns You About: Configuration Drift

    You deploy a server with a locked-down SSH config, a clean firewall, and sensible defaults. Three months later, someone adds a web server, opens a port for debugging, and forgets to close it. Or an Nginx vhost gets added without an explicit server_name, and the default catch-all starts serving the wrong site to the wrong visitors.

    This isn’t hypothetical. I recently found a production edge server where the Nginx default_server block was silently intercepting requests meant for a different virtual host. The site was working — but it was serving the wrong content to a subset of visitors. No errors in the logs. No alerts. Just quiet, invisible misconfiguration that had been running who knows how long.

    The fix was straightforward: explicit server_name directives on every vhost, and removing the catch-all entirely. But finding it required actually looking, which is the part that doesn’t happen often enough.

    SSH Access With a Dynamic IP: The Failsafe Pattern

    Here’s another one that comes up constantly. You lock SSH down to specific source IPs — best practice, absolutely. But your home IP is assigned by your ISP via DHCP, and it changes. Now you’re locked out of your own server, or you’re tempted to leave the firewall wide open “just until I update it.”

    The solution I implemented on a production VPS was an automated failsafe script. It runs periodically, detects the current public IP, and updates the firewall allowlist if the IP has changed. The key design principles:

    • The script authenticates outbound — it calls a known endpoint to discover the current IP, then pushes the update.
    • It only modifies the specific allowlist rule — it doesn’t touch any other firewall configuration.
    • It logs every change — so there’s an audit trail of when and why the IP was updated.
    • It fails closed — if the script can’t determine the current IP, it doesn’t open anything up.

    This pattern means you get the security of IP-restricted SSH without the operational risk of locking yourself out when your ISP rotates your address. It’s not fancy. It’s just honest about the reality that infrastructure has to be operable by humans.

    Multi-Hop SSH: Key Management Across Trust Boundaries

    The more complex the infrastructure, the more carefully you need to think about SSH key propagation. In one environment, the access path runs through multiple hops: local machine to management host, management host to container runtime, container runtime to VPS.

    Each hop is a trust boundary. The question at each one is: what keys exist here, who can use them, and what happens if this host is compromised?

    The hardening approach:

    • Separate keys per hop — no single key traverses the entire chain. If one host is compromised, the blast radius is limited to the next hop, not the entire path.
    • Keys are never copied manually — they’re provisioned through automation, with expiry and rotation baked in.
    • Agent forwarding is scoped, not blanket — it’s enabled only for specific connections and disabled by default.
    • Every key has a known owner and purpose — if you can’t explain why a key exists, it gets removed.

    This is the kind of thing that feels excessive until the day it prevents a lateral move during an incident. Then it feels like the most important work you did.

    The Hardening Checklist You Can Actually Use

    If you’re responsible for production infrastructure — whether you’re a CTO, a technical founder, or the person who just ended up owning the servers — here’s a practical checklist drawn from real hardening work:

    1. Audit your firewall rules quarterly. Every rule should have a comment explaining why it exists. If you can’t explain it, remove it.
    2. Remove default_server catch-alls from web servers. Every vhost should have an explicit server_name. If a request doesn’t match a known vhost, it should get a 444 or a meaningful error — not silently served by the wrong site.
    3. Automate your SSH access management. If your source IP can change, build the failsafe before you get locked out, not after.
    4. Segment your SSH keys by trust boundary. One key per hop. No exceptions for convenience.
    5. Review listening services monthly. Run ss -tlnp and verify every open port is intentional. You will find surprises.
    6. Check for configuration drift after every change. The best time to catch a misconfiguration is right after someone made a different change nearby.
    7. Log access and changes. If you can’t tell who connected, when, and what they changed, you don’t have a hardened server — you have a shared secret.

    The Uncomfortable Truth

    Hardening isn’t a project with a finish line. It’s a discipline. The servers that get compromised aren’t usually the ones that were never hardened — they’re the ones that were hardened once and then left to drift.

    The work is unglamorous. It’s reviewing firewall rules on a Friday afternoon. It’s removing a default_server block that “seems to be working.” It’s writing a small script so your SSH access doesn’t break when your ISP does its thing.

    But this is the work that keeps production infrastructure trustworthy. And it’s the work that separates infrastructure that looks secure from infrastructure that is secure.

    If this is on your roadmap — or if you’d rather someone else owned it — get in touch or review the relevant services.