How to Secure, Harden and Improve Performance of Nginx Web Server
#1: Keep Nginx up to date
#2: Remove unnecessary modules in Nginx
To explicitly remove modules from Nginx while installing from source:
# ./configure --without-module1 --without-module2 --without-module3
Example:
# ./configure --without-http_dav_module --without-http_spdy_module
Removing modules from a previous Nginx installation requires recompilation.
Caution: configuration directives come from modules — verify you’re not disabling a module containing directives you still need. Check the Nginx documentation before disabling modules.
#3: Disable the server_tokens directive
The server_tokens directive displays the Nginx version on error pages. Hide this to
prevent attacks that target known vulnerabilities in a specific version.
server {
listen 192.168.0.25:80;
server_tokens off;
server_name example.com www.example.com;
access_log /var/www/logs/example.access.log;
error_log /var/www/logs/example.error.log error;
root /var/www/example.com/public_html;
index index.html index.htm;
}
#4: Deny bad HTTP user agents
Malware bots and crawlers waste resources. Create /etc/nginx/blockuseragents.rules:
map $http_user_agent $blockedagent {
default 0;
~*malicious 1;
~*bot 1;
~*backdoor 1;
~*crawler 1;
~*bandit 1;
}
Include it before the server block, then return 403 for blocked agents:
include /etc/nginx/blockuseragents.rules;
server {
listen 192.168.0.25:80;
server_tokens off;
server_name example.com www.example.com;
access_log /var/www/logs/example.access.log;
error_log /var/www/logs/example.error.log error;
root /var/www/example.com/public_html;
index index.html index.htm;
}
Test with:
# wget http://192.168.0.25/index.html
# wget --user-agent "I am a bandit haha" http://192.168.0.25/index.html
#5: Disable unwanted HTTP methods
Allow only GET, POST, and HEAD; return 444 for everything else (which fools malware into thinking there’s nothing there):
if ($request_method !~ ^(GET|HEAD|POST)$) {
return 444;
}
Test with:
# curl -X DELETE http://192.168.0.25/index.html
# curl -X POST http://192.168.0.25/index.html
#6: Set buffer size limitations
Prevent buffer overflow attacks. Create /etc/nginx/conf.d/buffer.conf:
client_body_buffer_size 1k;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
And include it:
include /etc/nginx/conf.d/*.conf;
#7: Limit connections by IP
limit_conn_zone $binary_remote_addr zone=addr:5m;
limit_conn addr 1;
#8: Set up monitoring for logs
#9: Prevent image hotlinking
location /img/ {
valid_referers none blocked 192.168.0.25;
if ($invalid_referer) {
return 403;
}
}
#10: Disable SSL, only enable TLS
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#11: Create certificates
# openssl genrsa -aes256 -out example.key 1024
# openssl req -new -key example.key -out example.csr
# cp example.key example.key.org
# openssl rsa -in example.key.org -out example.key
# openssl x509 -req -days 365 -in example.csr -signkey example.key -out example.crt
Add a separate server block for SSL:
server {
listen 192.168.0.25:443 ssl;
server_tokens off;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
ssl_certificate /etc/nginx/sites-enabled/certs/example.crt;
ssl_certificate_key /etc/nginx/sites-enabled/certs/example.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
#12: Redirect HTTP traffic to HTTPS
Add this to your port-80 server block:
return 301 https://$server_name$request_uri;
This returns a 301 (Moved Permanently) response, redirecting requests on port 80 to the HTTPS server block.