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.

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.
| Command | Description |
|---|---|
sudo systemctl start nginx | Start the Nginx service |
sudo systemctl stop nginx | Stop the Nginx service |
sudo systemctl restart nginx | Restart the Nginx service |
sudo systemctl reload nginx | Reload Nginx configuration without downtime |
sudo systemctl status nginx | Check the status of the Nginx service |
sudo nginx -t | Test Nginx configuration for syntax errors |
sudo nginx -s reload | Reload Nginx configuration |
sudo nginx -s stop | Stop Nginx gracefully |
sudo nginx -s quit | Quit Nginx gracefully |
sudo nginx -v | Display Nginx version |
sudo nginx -V | Display Nginx version and compile options |
sudo tail -f /var/log/nginx/access.log | View Nginx access log in real-time |
sudo tail -f /var/log/nginx/error.log | View Nginx error log in real-time |
If you don't have
systemctl, you can useservicecommand instead. For example,sudo service nginx start.
Nginx Related Files and Directories
Here are some important Nginx related files and directories that we should be aware of:
| File/Directory | Description |
|---|---|
/etc/nginx/nginx.conf | Main 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.log | Nginx access log file |
/var/log/nginx/error.log | Nginx 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.
