Nginx Complete Guide and Cheatsheet

Learn Nginx from the ground up with this complete guide and cheatsheet. From installing the latest version to configuration, security, and performance optimization.

 •  5 min read  •  ... views
Featured image for Nginx Complete Guide and Cheatsheet

Nginx (engine x) is a powerful, high-performance web server and reverse proxy server that has gained immense popularity due to its speed, scalability, and flexibility. It is widely used for serving static content, load balancing, and handling high traffic websites.

In this complete guide and cheatsheet, I will try to cover everything we need to know to get started with Nginx, from installing the latest version to configuration, security, and performance optimization.

Installing Nginx

Let's start by installing nginx on our server. The installation process may vary depending on our operating system. I will cover the installation process for Ubuntu and Debian-based systems.

For other operating systems, please refer to the official Nginx installation guide.

Installing Nginx on Ubuntu/Debian

The version of Nginx available in the default package repositories of Ubuntu and Debian may not be the latest. To install the latest stable version, we can use the official Nginx repository.

For that, we need to install some prerequisite packages first by running the following command:

sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring

Next, we need to import the Nginx signing key by running this command:

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg

Now we can add the Nginx repository to our system's package sources by running this command chain:

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list

For security we should verify the fingerprint of the Nginx signing key by running the following command before installing Nginx from this source.

gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

The output should show a fingerprint that looks like this:

pub   rsa2048 2011-08-19 [SC] [expires: 2027-05-24]
      573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid                      nginx signing key <signing-key@nginx.com>

Match the fingerprint 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 with the one provided on the Nginx official website.

If the fingerprints match, it is safe to install Nginx from this repository.

So, now let's update our package list to include the Nginx repository by running:

sudo apt update

And finally, we can install Nginx by running:

sudo apt install nginx

Now we should have the latest stable version of Nginx installed on our system.

We can verify the installation by checking the Nginx version with:

nginx -v

The output should show the installed version of Nginx, for example:

nginx version: nginx/1.29.1

To see the full version information including the modules compiled with Nginx, we can run:

nginx -V

And this should give us a detailed output similar to this:

nginx version: nginx/1.29.1
built by gcc 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
built with OpenSSL 3.0.13 30 Jan 2024
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/run/nginx.pid --lock-path=/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/builder/debuild/nginx-1.29.1/debian/debuild-base/nginx-1.29.1=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=/home/builder/debuild/nginx-1.29.1/debian/debuild-base/nginx-1.29.1=/usr/src/nginx-1.29.1-1~noble -fPIC' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'

Here, we can see we have the HTTP/3 module (--with-http_v3_module) enabled, which we will use later in this guide.

Starting and Enabling Nginx

Now that we have Nginx installed, we need to start the Nginx service and enable it to start on boot.

sudo systemctl start nginx
sudo systemctl enable nginx

We can check the status of the Nginx service by running:

sudo systemctl status nginx

The output should show that the Nginx service is active and running.

Hit Q to exit the status output.

Configuring Firewall for Nginx

For security we should use a firewall to restrict unnecessary access to our server.

Let's configure UFW (Uncomplicated Firewall) to allow HTTP, HTTPS, and HTTP/3 traffic to our server.

sudo ufw enable
sudo ufw allow 'Nginx Full'

Now for HTTP/3 (QUIC), we need to allow UDP traffic on port 443, as HTTP/3 uses UDP instead of TCP.

sudo ufw allow 443/udp

We can check the status of UFW to ensure the rules are applied correctly by running:

sudo ufw status

The output should show that the firewall is active and the rules for Nginx are applied.

Status: active
To                         Action      From
--                         ------      ----
Nginx Full                ALLOW       Anywhere
Nginx Full (v6)           ALLOW       Anywhere (v6)
443/udp                   ALLOW       Anywhere
443/udp (v6)              ALLOW       Anywhere (v6)
... other rules ...

Great! Now our server is ready to serve web traffic securely! You can test it by opening your server's IP address in a web browser. You should see the default Nginx welcome page.

Some Useful Nginx Commands

Before we dive deeper into Nginx configurations, here are some useful commands that we will frequently use with Nginx.

CommandDescription
sudo systemctl start nginxStart the Nginx service
sudo systemctl stop nginxStop the Nginx service
sudo systemctl restart nginxRestart the Nginx service
sudo systemctl reload nginxReload Nginx configuration without downtime
sudo systemctl status nginxCheck the status of the Nginx service
sudo nginx -tTest Nginx configuration for syntax errors
sudo nginx -s reloadReload Nginx configuration
sudo nginx -s stopStop Nginx gracefully
sudo nginx -s quitQuit Nginx gracefully
sudo nginx -vDisplay Nginx version
sudo nginx -VDisplay Nginx version and compile options
sudo tail -f /var/log/nginx/access.logView Nginx access log in real-time
sudo tail -f /var/log/nginx/error.logView Nginx error log in real-time

If you don't have systemctl, you can use service command instead. For example, sudo service nginx start.

Here are some important Nginx related files and directories that we should be aware of:

File/DirectoryDescription
/etc/nginx/nginx.confMain Nginx configuration file
/etc/nginx/conf.d/Directory for additional configuration files
/etc/nginx/sites-available/Directory for available server block files
/etc/nginx/sites-enabled/Directory for enabled server block files
/var/www/html/Default web root directory
/var/log/nginx/access.logNginx access log file
/var/log/nginx/error.logNginx error log file

These files and directories are crucial for managing and configuring Nginx effectively.

Configuring Nginx

Now that we have Nginx installed and running, and we are familiar with some useful commands and important files, let's dive into configuring Nginx.

Default Configuration: nginx.conf

When we install Nginx from the official repository, it comes with a very basic default configuration file located at /etc/nginx/nginx.conf.

Now we will replace it with a more optimized and secured one.

Let's first create the directories we need:

sudo mkdir -p /etc/nginx/sites-available
sudo mkdir -p /etc/nginx/sites-enabled

Next, we will create a backup of the original nginx.conf file and then create a new one:

sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo nano /etc/nginx/nginx.conf

Now, let's add the following configuration to the new nginx.conf file:

user www-data;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65536; # Limit the number of open files
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024; # Increase based on available resources
    multi_accept on;
    use epoll;
    accept_mutex off;
}

http {
    # Basic Settings
    sendfile on;
    sendfile_max_chunk 1m;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 60s;
    keepalive_requests 1000;
    types_hash_max_size 2048;
    server_tokens off;

    # Server Names
    server_names_hash_bucket_size 128;
    server_names_hash_max_size 8192;

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

    # Buffer Settings
    client_body_buffer_size 128k;
    client_max_body_size 10m;
    client_header_buffer_size 1k;
    client_header_timeout 30s;
    large_client_header_buffers 4 4k;
    output_buffers 1 32k;
    postpone_output 1460;

    # HTTP/2 Settings

    # SSL/TLS Settings (Optimized for modern browsers)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_session_timeout 1d;
    ssl_session_cache shared:TLS:10m; # Increase based on available resources
    ssl_session_tickets on;

    # Generate this file with: openssl rand 80 > /etc/nginx/ssl_session_ticket.key
    ssl_session_ticket_key /etc/nginx/ssl_session_ticket.key;

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_early_data on;
    ssl_buffer_size 4k;

    # DNS Resolver for OCSP Stapling
    resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # Security Headers (Global defaults)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # Logging (Optimized with HTTP/3 support)
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" rt=$request_time '
                    'ups_rt=$upstream_response_time ups_addr=$upstream_addr '
                    '"$http_x_forwarded_for"';

    log_format quic '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http3"';

    access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    error_log /var/log/nginx/error.log warn;

    # Compression (Enhanced)
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 1000;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-font-opentype
        application/x-font-truetype
        image/x-icon
        application/vnd.font-fontforge-sfd;

    # Brotli Compression (uncomment if module available)
    # brotli on;
    # brotli_comp_level 6;
    # brotli_static on;
    # brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # File Cache (Enhanced)
    open_file_cache max=2000 inactive=30s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    # Rate Limiting Zones
    limit_req_zone $binary_remote_addr zone=api:1m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=general:1m rate=5r/s;
    limit_req_status 429;

    # Connection Limiting
    limit_conn_zone $binary_remote_addr zone=addr:1m;
    limit_conn_status 429;

    # Map for WebSocket upgrade
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    # Cache Configurations
    proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=api_cache:2m inactive=60m use_temp_path=off max_size=100m;
    proxy_cache_path /var/cache/nginx/static levels=1:2 keys_zone=static_cache:10m inactive=1y use_temp_path=off max_size=1g;

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

This configuration includes several optimizations and security enhancements, such as:

  • Improved SSL/TLS settings for better security and performance.
  • Enhanced logging formats to include more detailed request information.
  • Compression settings for faster content delivery.
  • File caching to reduce disk I/O and improve response times.
  • Rate limiting to protect against abuse and ensure fair usage.
  • Connection limiting to prevent resource exhaustion.
  • WebSocket support for real-time applications.
  • Customizable cache paths for different content types.

After adding the configuration, save and exit the file (by pressing CTRL + X, then Y, and ENTER in nano).

Now let's generate the SSL session ticket key file:

sudo openssl rand -out /etc/nginx/ssl_session_ticket.key 80
sudo chmod 600 /etc/nginx/ssl_session_ticket.key

This key is used for encrypting session tickets, which helps improve the performance of SSL/TLS connections.

Now, let's test the Nginx configuration for any syntax errors by running:

sudo nginx -t

If the output shows syntax is ok and test is successful, we can proceed to reload Nginx to apply the new configuration:

sudo systemctl reload nginx

Now Nginx is configured with a more optimized and secure setup.

This configuration is optimize for low powered (1 CPU, 1-2GB RAM) VMs, if you have more powerful system, you can increase some of the values to get the most out of your machine.

By default, Nginx does not come with the Brotli compression module enabled. If we want to use Brotli compression, we need to compile Nginx from source with the Brotli module or use a pre-built package that includes it.

Using Nginx

Now that we have Nginx installed and configured, let's explore how to use it effectively for different use cases.

Hosting a Static Website with Nginx