Skip to main content

Nginx Configurations

Security configurations

TLS

Get a certificate from Let's Encrypt:

certbot certonly --nginx -d example.com --key-type rsa --rsa-key-size 4096

Set TLS ciphers in Nginx server context:

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

Self signed certificate

Generate a self-signed certificate for 5 years:

mkdir /etc/nginx/default_ssl
openssl req -x509 -nodes -newkey rsa:4096 -keyout /etc/nginx/default_ssl/key.pem -out /etc/nginx/default_ssl/cert.pem -days 1825

Configure the certificate in server context:

ssl_certificate /etc/nginx/default_ssl/cert.pem;
ssl_certificate_key /etc/nginx/default_ssl/key.pem;

Diffie-Hellman parameters

openssl dhparam -out /etc/nginx/dhparam.pem 4096

Ciphers

List available ciphers:

openssl ciphers -ciphersuites `openssl ciphers -s -tls1_3`

Strongest ciphers

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • ECDHE-RSA-AES256-GCM-SHA384
  • ECDHE-RSA-CHACHA20-POLY1305
  • DHE-RSA-AES256-GCM-SHA384
  • DHE-RSA-CHACHA20-POLY1305

Important:

  • Priority: AES over ChaCha
  • Keysize must be >= 256

Configure TLS ciphers in http or server context:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on;

OpenSSL

If Nginx version >= 1.19.4:

ssl_conf_command Options ServerPreference;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;

Below Nginx 1.19.4, edit /etc/ssl/openssl.cnf:

Options = ServerPreference
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Basic authentication

apt install apache2-utils
htpasswd -c /etc/nginx/.htpasswd user

Use it in a location context:

location /admin {
auth_basic "Message";
auth_basic_user_file /etc/nginx/.htpasswd;
}

Sample configs

nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 1024;
}

http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

include /etc/nginx/mime.types;
default_type application/octet-stream;

# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

# Gzip Settings
gzip off;

# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

sites-available/example.com

# https
server {

# Enable SSL and HTTP2
listen [::]:443 ssl http2;
listen 443 ssl http2;

server_name example.com;

# Set certificate path
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

# Enable OCSP
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1;
resolver_timeout 5s;

# Add security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy 'strict-origin' always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains" always;

# Set root path
root /var/www/html;
index index.php index.html index.htm;

location / {
try_files $uri $uri/ =404;
}

# Set basic authentication to /admin
location /admin {
# Basic authentication
auth_basic "Message";
auth_basic_user_file /etc/nginx/.htpasswd;
}

# Set FastCGI
location ~ \.php$ {
include snippets/fastcgi-php.conf;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
}

# Reverse proxy
location /proxy {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

proxy_ssl_trusted_certificate /etc/nginx/ssl/cert.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_ssl_session_reuse on;

proxy_pass http://127.0.0.1:8080;
}

# Disable accessing hidden files except .well-known
location ~ /\.(?!well-known).* {
deny all;
}

# Disable unused methods
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 405;
}

# Custom error pages
error_page 404 /404.html;
error_page 500 /500.html;
}

# http
server {

listen 80;
listen [::]:80;
server_name example.com;

# Redirect http to https
return 301 https://$host$request_uri;
}

sites-enabled/default

server {

listen [::]:443 ssl http2;
listen 443 ssl http2;

server_name _;

ssl_certificate /etc/nginx/default_ssl/cert.pem;
ssl_certificate_key /etc/nginx/default_ssl/key.pem;

return 444;
}

server {

listen 80;
listen [::]:80;

server_name _;

return 444;
}

conf.d/security.conf

# Do not send server version
server_tokens off;

# Set TLS ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on;

# Diffie-Hellman parameters
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ecdh_curve secp521r1:secp384r1;

# SSL session reuse
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# Reduce Time To First Byte
ssl_buffer_size 4k;

Basic reverse proxy template

# https
server {

# Enable SSL and HTTP2
listen 443 ssl http2;

server_name example.com;

# Set certificate path
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

# Enable OCSP
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1;
resolver_timeout 5s;

# Add security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy 'strict-origin' always;
add_header Strict-Transport-Security "max-age=63072000" always;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass http://127.0.0.1:8080;
}
}

# http
server {

listen 80;
server_name example.com;

# Redirect http to https
return 301 https://$host$request_uri;
}