Skip to main content
  1. Posts/

Nginx Configurations

··627 words·3 mins·

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;
}