What 89 checkers actually return on a fresh nginx server
We span up a Debian 13 VM, ran apt install nginx, pointed an A record at it,
generated a Let's Encrypt cert, enabled HTTPS with the default snippets nginx ships, and
fired UnveilScan Extended at it. The score: 54 / D. This is what every
vanilla nginx looks like to a serious scanner. Below is the full finding list, ranked by
how to fix in order.
Critical (the deal-breakers)
CRITICAL tls.legacy_protocol_enabled
Default nginx ships with ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3 in
/etc/nginx/nginx.conf on Debian 13 (yes, in 2026). Fix in one line:
ssl_protocols TLSv1.2 TLSv1.3;
High
HIGH web.server_header_verbose
nginx leaks its version: Server: nginx/1.26.0.
# In nginx.conf, http block:
server_tokens off;
HIGH tls.ssl_session_tickets_unrotated
nginx generates one ticket key at startup and never rotates it; that key would decrypt every prior session if leaked.
ssl_session_tickets off;
# OR rotate manually with ssl_session_ticket_key + cron
Medium
MEDIUM web.hsts_missing
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
MEDIUM web.csp_missing
Start with a permissive CSP (cf. our CSP article):
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'" always;
MEDIUM dns.no_caa
No CAA record. Add one to limit which CA can issue for your domain:
# BIND zone
example.com. IN CAA 0 issue "letsencrypt.org"
example.com. IN CAA 0 iodef "mailto:security@example.com"
MEDIUM email.spf_missing / email.dmarc_missing
Even if you don't send mail, set explicit reject records to prevent spoofing:
example.com. IN TXT "v=spf1 -all"
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
Low
LOW web.xcto_missing / web.xfo_missing / web.referrer_policy_missing / web.permissions_policy_missing
Cookie-cutter headers, drop them in once and forget:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "interest-cohort=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
LOW web.security_txt_missing
$ mkdir -p /var/www/html/.well-known
$ cat > /var/www/html/.well-known/security.txt <<'EOF'
Contact: mailto:security@example.com
Expires: 2027-04-29T00:00:00Z
Preferred-Languages: en
EOF
LOW dns.no_aaaa
No IPv6 record. Add an AAAA pointing at your IPv6 address (most VPS now have one for free).
LOW tls.no_dane_tlsa
DANE TLSA record absent. Optional unless you run mail; skip if you don't.
The fix-everything snippet
One nginx config block that addresses 80% of the above. Drop in your server { }:
# TLS hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE+AESGCM:ECDHE+CHACHA20:!aNULL:!MD5;
ssl_session_tickets off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "interest-cohort=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'" always;
# Hide leaks
server_tokens off;
# Block sensitive files
location ~ /\. { deny all; return 404; }
location ~ \.(bak|sql|env|swp|tar\.gz)$ { deny all; return 404; }
Plus the DNS records above (CAA, SPF, DMARC, AAAA), and security.txt.
After applying everything
We re-scanned the same VM. Score: 91 / A. The remaining 9 points come from environmental findings (single-ASN hosting, no DNSSEC) that need infrastructure changes. For application-layer security on a default-config nginx, this snippet gets you from D to A in 5 minutes.
Verify the fix on your nginx
Apply the snippet, run a Basic scan, watch the score climb live.
Scan a domain