Secure nginx configuration: HTTPS, security headers and access limits

A practical checklist with ready-to-use snippets for a website or reverse proxy on nginx.

nginx is fast and flexible, but the default configuration is made to work everywhere, not to be strict. These settings add encryption, protective headers and simple access controls. Combine them with regular updates — see our article about nginx vulnerabilities in 2026.

Before you start: replace example.am with your domain and 192.168.88.0/24 with your office or VPN network. Test every change with nginx -t before reloading, and keep a copy of the working configuration.

Step 1. Redirect all HTTP to HTTPS

Visitors and search engines should always land on the encrypted version of the site.

server {
    listen 80;
    server_name example.am www.example.am;
    return 301 https://$host$request_uri;
}

Step 2. Get a free certificate

Let's Encrypt certificates are free and renew automatically with certbot.

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.am -d www.example.am

Step 3. Modern TLS and security headers

Allow only TLS 1.2 and 1.3, hide the nginx version and add headers that protect browsers from common attacks. Add a Content-Security-Policy once you know which external scripts the site uses.

# in the http { } block:
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
client_max_body_size 10m;
# in the server { } block for HTTPS:
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Step 4. Block hidden files and protect admin areas

Deployment leftovers such as .git or .env must never be downloadable. Admin panels should be reachable only from trusted networks.

# block hidden files such as .git and .env (keep Let's Encrypt working)
location ~ /\.(?!well-known) {
    deny all;
}
# admin area only from the office / VPN
location /admin/ {
    allow 192.168.88.0/24;
    deny all;
}

Step 5. Slow down password guessing

Limit how often one address can request the login page.

# in the http { } block:
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
# in the location that handles the login page:
limit_req zone=login burst=5 nodelay;

Step 6. Check and apply

Test the configuration, reload without downtime and verify the headers.

sudo nginx -t && sudo systemctl reload nginx
curl -sI https://example.am | grep -iE 'strict|x-frame|x-content|server'

A good configuration is invisible to normal visitors and very inconvenient for everyone else.

Need help with this? Contact CySec for a free consultation.


All articles

Need help with this?

Our engineers can review your current setup and propose concrete improvements.