Nginx Quick Reference
My notes about Nginx...
Table of Contents
- Introduction
- External Resources
- Snippets
- Base rules
- Performance
- Hardening
- Run as an unprivileged user
- Disable unnecessary modules
- Protect sensitive resources
- Hide Nginx version number
- Hide Nginx server signature
- Hide upstream proxy headers
- Keep only TLS 1.2 (+ TLS 1.3)
- Use only strong ciphers
- Use strong Key Exchange
- Use more secure ECDH Curve
- Use only 4096-bit private keys
- Defend against the BEAST attack
- Disable compression (mitigation of CRIME attack)
- HTTP Strict Transport Security
- Reduce XSS risks (Content-Security-Policy)
- Control the behavior of the Referer header (Referrer-Policy)
- Provide clickjacking protection (X-Frame-Options)
- Prevent some categories of XSS attacks (X-XSS-Protection)
- Prevent Sniff Mimetype middleware (X-Content-Type-Options)
- Reject unsafe HTTP methods
- Control Buffer Overflow attacks
- Mitigating Slow HTTP DoS attack (Closing Slow Connections)
Introduction
Before using the Nginx please read Beginner’s Guide.
Nginx (/ˌɛndʒɪnˈɛks/ EN-jin-EKS) is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev. For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VK, and Rambler.
To increase your knowledge, read Nginx Documentation.
General disclaimer
This is not an official handbook. Many of these rules refer to another resources. It is rather a quick collection of some things used by me in production environments.
The most important thing:
Do not follow guides just to get 100% of something. Think about what you actually do at your server!
And remember:
These guidelines provides recommendations for very restrictive setup.
SSL Report: blkcipher.info
Many of these recipes have been applied to the configuration of my private website. I finally got all 100%'s on my scores:
External Resources
About Nginx
References
Cheatsheets
Performance & Hardening
Static Analyzers
Log Analyzers
Performance Analyzers
Benchmarking tools
Online tools
Other
Snippets
Shell aliases
alias ng.test='nginx -t -c /etc/nginx/nginx.conf'
alias ng.stop='ng.test && systemctl stop nginx'
alias ng.reload='ng.test && systemctl reload nginx'
Base rules
🔰
Separate listen directives for 80 and 443
Rationale
...
Example
# For http:
server {
listen 10.240.20.2:80;
...
}
# For https:
server {
listen 10.240.20.2:443 ssl;
...
}
External resources
🔰
Organising Nginx configuration
Rationale
When your configuration grow, the need for organising your code will also grow. Well organised code is:
- easier to understand.
- easier to maintain.
- easier to work with.
Use
include
directive to attach your nginx specific code to global config, contexts and other.
Example
# Store this configuration in https-ssl-common.conf
listen 10.240.20.2:443 ssl;
root /etc/nginx/error-pages/other;
ssl_certificate /etc/nginx/domain.com/certs/nginx_domain.com_bundle.crt;
ssl_certificate_key /etc/nginx/domain.com/certs/domain.com.key;
# And include this file in server section:
server {
include /etc/nginx/domain.com/commons/https-ssl-common.conf;
server_name domain.com www.domain.com;
...
External resources
🔰
Use default_server directive at the beginning
Rationale
Nginx should prevent processing requests with undefined server names - also traffic on ip address. It also protects against configuration errors and providing incorrect backends.
Example
server {
listen 10.240.20.2:443 ssl;
# Place it at the beginning of the configuration file.
server_name default_server;
location / {
# serve static file (error page):
root /etc/nginx/error-pages/404;
# or redirect:
# return 301 https://badssl.com;
}
}
server {
listen 10.240.20.2:443 ssl;
server_name domain.com;
...
}
server {
listen 10.240.20.2:443 ssl;
server_name app.domain.com;
...
}
External resources
🔰
Force all connections over TLS
Rationale
You should always use HTTPS instead of HTTP to protect your website, even if it doesn’t handle sensitive communications.
Example
server {
listen 10.240.20.2:80;
server_name domain.com;
return 301 https://$host$request_uri;
}
server {
listen 10.240.20.2:443 ssl;
server_name domain.com;
...
}
External resources
🔰
Use geo/map modules instead allow/deny
Rationale
Creates variables with values depending on the client IP address. Use map or geo modules (one of them) to prevent users abusing your servers.
Example
# Map module:
map $remote_addr $globals_internal_map_acl {
# Status code:
# - 0 = false
# - 1 = true
default 0;
### INTERNAL ###
10.255.10.0/24 1;
10.255.20.0/24 1;
10.255.30.0/24 1;
192.168.0.0/16 1;
}
# Geo module:
geo $globals_internal_geo_acl {
# Status code:
# - 0 = false
# - 1 = true
default 0;
### INTERNAL ###
10.255.10.0/24 1;
10.255.20.0/24 1;
10.255.30.0/24 1;
192.168.0.0/16 1;
}
External resources
🔰
Map all the things...
Rationale
Map module provides a more elegant solution for clearly parsing a big list of regexes, e.g. User-Agents.
Example
map $http_user_agent $device_redirect {
default "desktop";
~(?i)ip(hone|od) "mobile";
~(?i)android.*(mobile|mini) "mobile";
~Mobile.+Firefox "mobile";
~^HTC "mobile";
~Fennec "mobile";
~IEMobile "mobile";
~BB10 "mobile";
~SymbianOS.*AppleWebKit "mobile";
~Opera\sMobi "mobile";
}
if ($device_redirect = "mobile") {
return 301 https://m.domain.com$request_uri;
}
External resources
🔰
Drop the same root inside location block
Rationale
If you add a root to every location block then a location block that isn’t matched will have no root. Set global
root
inside server directive.
Example
server {
server_name domain.com;
root /var/www/domain.com/public;
location / {
...
}
location /api {
...
}
location /static {
root /var/www/domain.com/static;
...
}
}
External resources
🔰
Use debug mode for debugging
Rationale
There's probably more detail than you want, but that can sometimes be a lifesaver (but log file growing rapidly).
Example
rewrite_log on;
error_log /var/log/nginx/error-debug.log debug;
External resources
Performance
🔰
Set manually worker processes
Rationale
The
worker_processes
directive is the sturdy spine of life for Nginx. This directive is responsible for letting our virtual server know many workers to spawn once it has become bound to the proper IP and port(s).
Official Nginx documentation say: "When one is in doubt, setting it to the number of available CPU cores would be a good start (the value "auto" will try to autodetect it)."
I think for high load proxy servers (also standalone servers) the best value is ALL_CORES - 1 (please test it before used).
Example
# VCPU = 4 , expr $(nproc --all) - 1
worker_processes 3;
External resources
🔰
Use HTTP/2
Rationale
All requests are downloaded in parallel, not in a queue, HTTP headers are compressed, pages transfer as a binary, not as a text file, which is more efficient and more.
Example
# For https:
server {
listen 10.240.20.2:443 ssl http2;
...
External resources
🔰
Maintaining SSL Sessions
Rationale
This improves performance from the clients’ perspective, because it eliminates the need for a new (and time-consuming) SSL handshake to be conducted each time a request is made.
Most servers do not purge sessions or ticket keys, thus increasing the risk that a server compromise would leak data from previous (and future) connections.
Example
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
ssl_session_tickets off;
ssl_buffer_size 1400;
External resources
Hardening
🔰
Run as an unprivileged user
Rationale
There is no real difference in security just by changing the process owner name. On the other hand in security, the principle of least privilege states that an entity should be given no more permission than necessary to accomplish its goals within a given system. This way only master process runs as root.
Example
# Edit nginx.conf:
user www-data;
# Set owner and group:
chown -R www-data:www-data /var/www/domain.com
External resources
🔰
Disable unnecessary modules
Rationale
It is recommended to disable any modules which are not required as this will minimize the risk of any potential attacks by limiting the operations allowed by the web server.
Example
# During installation:
./configure --without-http_autoindex_module
# Comment modules in the configuration file:
# load_module /usr/share/nginx/modules/ndk_http_module.so;
# load_module /usr/share/nginx/modules/ngx_http_auth_pam_module.so;
External resources
🔰
Protect sensitive resources
Rationale
Hidden directories and files should never be web accessible.
Example
if ( $request_uri ~ "/\.git" ) {
return 403;
}
# or
location ~ /\.git {
deny all;
}
# or all . directories/files in general (including .htaccess, etc)
location ~ /\. {
deny all;
}
External resources
Hide Nginx version number
🔰
Rationale
Disclosing the version of nginx running can be undesirable, particularly in environments sensitive to information disclosure.
Example
server_tokens off;
External resources
🔰
Hide Nginx server signature
Rationale
You should compile Nginx from sources with
ngx_headers_more
to usedmore_set_headers
directive.
Example
more_set_headers "Server: Unknown";
External resources
🔰
Hide upstream proxy headers
Rationale
When nginx is used to proxy requests from an upstream server (such as a PHP-FPM instance), it can be beneficial to hide certain headers sent in the upstream response (for example, the version of PHP running).
Example
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNetMvc-Version;
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-Drupal-Cache;
External resources
🔰
Keep only TLS 1.2 (+ TLS 1.3)
Rationale
TLS 1.1 and 1.2 are both without security issues - but only v1.2 provides modern cryptographic algorithms. TLS 1.0 and TLS 1.1 protocols will be removed from browsers at the beginning of 2020.
Example
ssl_protocols TLSv1.2;
External resources
- TLS/SSL Explained – Examples of a TLS Vulnerability and Attack, Final Part
- How to enable TLS 1.3 on Nginx
🔰
Use only strong ciphers
Rationale
This parameter changes quite often, the recommended configuration for today may be out of date tomorrow but remember - drop backward compatibility software components. Use only strong and not vulnerable ciphersuite.
If you use http/2 you can get
Server sent fatal alert: handshake_failure
error.
Example
ssl_ciphers "AES256+EECDH:AES256+EDH:!aNULL";
External resources
🔰
Use strong Key Exchange
Rationale
Default key size in OpenSSL is
1024 bits
- it's vurnelable and breakable. For the best security configuration use4096 bit
DH Group or pre-configured DH groups from mozilla.
Example
# Generating DH parameters:
openssl dhparam -dsaparam -out /etc/nginx/ssl/dhparam_4096.pem 4096
# Nginx configuration:
ssl_dhparam /etc/nginx/ssl/dhparams_4096.pem;
External resources
- Weak Diffie-Hellman and the Logjam Attack
- Pre-defined DHE groups
- Instructs OpenSSL to produce "DSA-like" DH parameters
🔰
Use more secure ECDH Curve
Rationale
X25519 is a more secure but slightly less compatible option. The NIST curves (prime256v1, secp384r1, secp521r1) are known to be weak and potentially vulnerable.
If web browser support X25519 curves -> use X25519 otherwise try the next curve listed.
Sometimes you should keep secp384r1 only for compatibility with some web browsers.
Example
ssl_ecdh_curve X25519;
# Alternative:
ssl_ecdh_curve X25519:prime256v1:secp521r1:secp384r1;
External resources
- SafeCurves: choosing safe curves for elliptic-curve cryptography
- Cryptographic Key Length Recommendations
🔰
Use only 4096-bit private keys
Rationale
Advisories recommend 2048 for now. Security experts are projecting that 2048 bits will be sufficient for commercial use until around the year 2030.
I always generate 4096 bit keys since the downside is minimal (slightly lower performance) and security is slightly higher (although not as high as one would like).
Example
( _fd="domain.com.key" ; _len="4096" ; openssl genrsa -out ${_fd} ${_len} )
# Letsencrypt:
certbot certonly -d domain.com -d www.domain.com --rsa-key-size 4096
External resources
🔰
Defend against the BEAST attack
Rationale
Enables server-side protection from BEAST attacks.
Example
ssl_prefer_server_ciphers on;
External resources
🔰
Disable compression (mitigation of CRIME attack)
Rationale
Disabling SSL/TLS compression stops the attack very effectively.
Example
gzip off;
External resources
🔰
HTTP Strict Transport Security
Rationale
The header indicates for how long a browser should unconditionally refuse to take part in unsecured HTTP connection for a specific domain.
Example
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains" always;
External resources
🔰
Reduce XSS risks (Content-Security-Policy)
Rationale
CSP reduce the risk and impact of XSS attacks in modern browsers.
Example
# This policy allows images, scripts, AJAX, and CSS from the same origin, and does not allow any other resources to load.
add_header Content-Security-Policy "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';" always;
External resources
🔰
Control the behavior of the Referer header (Referrer-Policy)
Rationale
Determine what information is sent along with the requests.
Example
add_header Referrer-Policy "no-referrer";
External resources
🔰
Provide clickjacking protection (X-Frame-Options)
Rationale
Helps to protect your visitors against clickjacking attacks. It is recommended that you use the x-frame-options header on pages which should not be allowed to render a page in a frame.
Example
add_header X-Frame-Options "SAMEORIGIN" always;
External resources
🔰
Prevent some categories of XSS attacks (X-XSS-Protection)
Rationale
Enable the cross-site scripting (XSS) filter built into modern web browsers.
Example
add_header X-XSS-Protection "1; mode=block" always
External resources
🔰
Prevent Sniff Mimetype middleware (X-Content-Type-Options)
Rationale
It prevents the browser from doing MIME-type sniffing (prevents "mime" based attacks).
Example
add_header X-Content-Type-Options "nosniff" always;
External resources
🔰
Reject unsafe HTTP methods
Rationale
Set of methods support by a resource. An ordinary web server supports the HEAD, GET and POST methods to retrieve static and dynamic content. Other (e.g. OPTIONS, TRACE) methods should not be supported on public web servers, as they increase the attack surface.
Example
add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 405;
}
External resources
🔰
Control Buffer Overflow attacks
Rationale
Buffer overflow attacks are made possible by writing data to a buffer and exceeding that buffers’ boundary and overwriting memory fragments of a process. To prevent this in nginx we can set buffer size limitations for all clients.
Example
client_body_buffer_size 100k;
client_header_buffer_size 1k;
client_max_body_size 100k;
large_client_header_buffers 2 1k;
External resources
🔰
Mitigating Slow HTTP DoS attack (Closing Slow Connections)
Rationale
Close connections that are writing data too infrequently, which can represent an attempt to keep connections open as long as possible.
Example
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 5 5;
send_timeout 10;