Skip to content

nginx

nginx is the other common web server. Same job as Apache: if the README doesn't require it, sudo apt purge nginx nginx-common; if it does, stop it advertising itself and add the browser protections.

Where

/etc/nginx/nginx.conf (global http block), /etc/nginx/sites-available/default and sites-enabled/ (the sites), /etc/nginx/conf.d/*.conf. After changes: sudo nginx -t && sudo systemctl reload nginx.

The settings

Setting Where Value Why
server_tokens http block in nginx.conf off Hides the version in the Server: header and error pages
ssl_protocols nginx.conf or the site TLSv1.2 TLSv1.3 No SSLv3, no TLS 1.0 or 1.1
add_header X-Frame-Options "SAMEORIGIN" always; server block present Clickjacking
add_header X-Content-Type-Options "nosniff" always; server block present
add_header Strict-Transport-Security "max-age=31536000" always; HTTPS server block present
autoindex any location off (the default; make sure nothing set it on) Directory listings
client_max_body_size http or server a sane limit such as 10m Uploads can't be used to fill the disk
location ~ /\. { deny all; } server block present Hidden files (.git, .env, .htpasswd) aren't served

Apply

sudo nano /etc/nginx/nginx.conf. Inside the http { … } block, find server_tokens (it ships as a comment, # server_tokens off;): remove the #. Find ssl_protocols and make it ssl_protocols TLSv1.2 TLSv1.3;. Every nginx directive ends with a semicolon; a missing one is the most common reason nginx -t fails.

The headers and upload limit go in a new file that the http block includes automatically:

sudo nano /etc/nginx/conf.d/hardening.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
client_max_body_size 10m;

Then:

sudo nginx -t
sudo systemctl reload nginx

Note that add_header in a server or location block replaces all headers from the http level; if a site sets its own headers, add these there too. grep -r autoindex /etc/nginx finds any listing turned on.

Files

Same as Apache: the web root (/var/www/html or whatever root says) owned by root, readable by www-data, writable only where the application needs it, and searched for things that aren't the site.

Verify

grep -rE 'server_tokens|ssl_protocols|autoindex|X-Frame-Options' /etc/nginx/
curl -sI http://localhost | grep -iE 'server|x-frame'
sudo nginx -t

Example

curl -I localhost shows Server: nginx/1.24.0. nginx.conf has # server_tokens off; commented and ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv3;. Uncomment the first, fix the second to TLSv1.2 TLSv1.3, add the headers file, reload. No X-Frame-Options appears until the reload; after it does.

Try it

  1. Set server_tokens off and compare curl -I output.
  2. Leave a semicolon off and run nginx -t.

Build it

An nginx-check.sh: grep the directives, nginx -t, curl -sI.

Next

PHP