Security Headers and Access Control

Introduction

Nginx sits on the edge of your application—it can add security headers, hide version details, block IP ranges, and password-protect staging areas before traffic reaches Spring Boot or Node. This chapter covers practical hardening without replacing app-level auth or input validation.

Prerequisites

Hide Nginx Version

nginx
http {
    server_tokens off;
}

Response header changes from Server: nginx/1.24.0 to Server: nginx—minor obscurity, not a substitute for patching.

Common Security Headers

nginx
server {
    listen 443 ssl http2;
    server_name example.com;
 
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=()" always;
}

Code explanation:

HeaderPurpose
X-Frame-OptionsReduce clickjacking (embed in iframe)
X-Content-Type-OptionsStop MIME sniffing
Referrer-PolicyControl referer sent on navigation
Permissions-PolicyDisable browser features you do not use

Use always so headers appear on error responses too (when supported).

Content-Security-Policy (Concept)

CSP restricts where scripts and styles load from:

nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;

Warning

CSP Breaks Inline Scripts

Strict CSP requires refactored frontend builds. Tune in staging—one wrong directive blocks all JS.

Coordinate with your HTML/JS CSP strategy; Nginx can enforce site-wide baseline.

Strict-Transport-Security (HSTS)

Only on HTTPS after TLS is stable:

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

Forces browsers to use HTTPS—see SSL chapter warnings before enabling.

IP Allow and Deny

nginx
location /admin/ {
    allow 203.0.113.0/24;
    allow 198.51.100.10;
    deny all;
 
    proxy_pass http://127.0.0.1:8080;
}

Code explanation:

  • allow rules first, then deny all
  • Useful for internal admin panels on public VPS

Tip

Cloud WAF

Production teams often add cloud WAF/CDN in front of Nginx—defense in depth.

HTTP Basic Authentication

Protect staging site:

bash
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd staging
nginx
location / {
    auth_basic "Staging";
    auth_basic_user_file /etc/nginx/.htpasswd;
    root /var/www/staging;
}

Code explanation:

  • Not a replacement for app login—simple gate for previews
  • Use strong passwords; restrict .htpasswd permissions (640, root
    )

Block Sensitive Files

nginx
location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
}
 
location ~* \.(env|git|sql|bak)$ {
    deny all;
}

Prevent accidental deployment of .git or .env into web roots.

Limit Request Methods

nginx
if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$ ) {
    return 405;
}

Use sparingly—prefer app-level validation. Some APIs need OPTIONS for CORS preflight.

TLS and Cipher Hardening

Rely on Certbot options-ssl-nginx.conf or Mozilla Intermediate profile. Disable TLS 1.0/1.1. Keep Nginx package updated for OpenSSL fixes.

Layered Security Model

LayerNginx canApp must still
TLSTerminate HTTPSValidate auth tokens
HeadersSet CSP, HSTSCorrect CORS logic
IP allowBlock regionsAuthorization checks
basic authStaging gateUser accounts, RBAC

FAQ

add_header duplicated in nested locations?

Inner location may omit parent headers—duplicate important headers or use include snippet.

basic auth with API?

Possible but awkward for mobile/SPA—use OAuth/JWT at app layer for APIs.

deny all breaks Let's Encrypt?

HTTP-01 challenge needs port 80 reachable—do not deny all on /.well-known/acme-challenge/:

nginx
location ^~ /.well-known/acme-challenge/ {
    allow all;
    root /var/www/certbot;
}

Security headers on static vs API?

Apply at server level for both; tune CSP differently if API returns JSON only (often no CSP needed on JSON responses).

server_tokens off enough?

No—patch OS and Nginx regularly; headers are one small piece.

ModSecurity?

WAF module for Nginx—advanced; optional enterprise hardening.