Nginx Production Configuration

Collection of Nginx tweaks that improve performance, strengthen security, and ease application deployments in production.

After every change, test the syntax and reload the service.

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo service nginx restart

1. Let's Encrypt SSL Certificates

Follow the guide Installing Let's Encrypt SSL certificates with Nginx on Debian that issues the certificate, then apply the configuration below.

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

server {
    listen 80;
    listen [::]:80;

    server_name your_domain.com www.your_domain.com;
    return 301 https://$host$request_uri;
}

2. Self-signed SSL Certificates

Install the ssl-cert package to generate self-signed certificates on Debian 10.

sudo apt-get update && sudo apt-get install -y ssl-cert

Then adjust the server block as follows:

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    include snippets/snakeoil.conf;
}

server {
    listen 80;
    listen [::]:80;

    server_name your_domain.com www.your_domain.com;
    return 301 https://$host$request_uri;
}

3. Verify HTTPS Navigation

Self-signed certificates trigger warnings. You will see an error like this:

curl https://your_domain.com
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Use the -k flag to ignore the warning and continue.

curl -k https://your_domain.com
<html>
  <head>
    <title>Welcome to your_domain.com!</title>
  </head>
  <body>
    <h1>Success! The your_domain.com server block is working!</h1>
  </body>
</html>

Finally, test the HTTP-to-HTTPS redirect:

curl http://your_domain.com
<html>
  <head>
    <title>301 Moved Permanently</title>
  </head>
  <body bgcolor="white">
    <center><h1>301 Moved Permanently</h1></center>
    <hr />
    <center>nginx/1.14.2</center>
  </body>
</html>

4. Enable Cache Control

Specify which file types should be cached and for how long.

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 10m;
        add_header Cache-Control "public, no-transform";
    }

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

    include snippets/snakeoil.conf;
}

5. Enable File Compression

Turn on gzip to shrink static responses.

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    gzip on;
    gzip_comp_level 3;
    gzip_min_length 1000;
    gzip_types  text/xml text/css;
    gzip_http_version 1.1;
    gzip_vary  on;
    gzip_disable "MSIE [4-6] \.";

    include snippets/snakeoil.conf;
}

6. Custom Error Pages

Create an HTML page and reference it from the site block.

sudo nano /usr/share/nginx/html/custom_404.html

custom_404.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>404 Not Found</title>
  </head>
  <body>
    404 Not Found
  </body>
</html>
sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    error_page 404 /custom_404.html;
    location = /custom_404.html {
        root /usr/share/nginx/html;
        internal;
    }

    include snippets/snakeoil.conf;
}

7. Proxy for Node.js Applications

Expose your Node.js app behind a dedicated location block.

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    location /node-app/ {
        proxy_pass http://127.0.0.1:3000;
    }

    include snippets/snakeoil.conf;
}

8. Remove the .html Extension

Serve clean URLs without forcing the .html suffix.

sudo nano /etc/nginx/sites-available/your_domain.com

your_domain.com

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    root /var/www/your_domain.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name your_domain.com www.your_domain.com;

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

    include snippets/snakeoil.conf;
}

For example, the request https://your_domain.com/page will try paths in this order:

  1. /page.html
  2. /page
  3. /page/

If none exist, Nginx returns the 404 error page.

References

Published: June 8, 2020