Harden Your Web Server

Terje Rutgersen · 2026 · Guide

The moment you put a server on the internet, it starts getting scanned. Bots check every IP range, constantly, looking for open ports, default configs, known vulnerabilities. Most of them are automated. None of them are personal. Your server isn't being targeted because it's interesting. It's being tested because it exists.

For a static site, the attack surface is already small. There's no database to leak, no login page to brute-force, no API to exploit. But "small" isn't the same as "zero," and a few headers and config tweaks can make your server genuinely boring to attackers. Boring is what you want. Boring means they move on to someone who didn't bother.

Don't show your directory structure

By default, if someone requests a URL that doesn't match a file, Nginx might show them a list of everything in that directory. That's giving away information for free. Turn it off:

location / {
    try_files $uri $uri/ =404;
    autoindex off;
}

Block access to hidden files

If you've ever pushed a .git directory or a .env file to your web root by accident (and honestly, who hasn't), this stops anyone from reading them through the browser:

location ~ /\.(?!well-known).* {
    deny all;
}

The .well-known exception is there for Let's Encrypt certificate validation. Everything else gets blocked.

Security headers

These are HTTP headers that tell browsers to be more cautious about what they load and how they behave on your site. None of them cost performance. All of them make certain classes of attacks harder:

add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self';";

Force HTTPS with HSTS. Once a browser sees this header, it won't even try HTTP for your domain for a year:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Stop your site leaking referrer data when visitors click outbound links:

add_header Referrer-Policy "no-referrer";

And tell browsers not to let your site use the microphone, camera, or geolocation API. Since it's a static site, it has no reason to:

add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";

Testing it

Once you've added all this, reload Nginx and scan your site with something like securityheaders.com or SSL Labs. They'll tell you if you missed anything. Aim for an A. It's surprisingly satisfying for something that takes about ten minutes of config editing.

None of this makes your server invulnerable. But it makes it a lot less interesting to the bots. And on the internet, being uninteresting to bots is basically a superpower.