Nginx Guide: From Installation to Production Configuration

Nginx is a high-performance, event-driven web server and reverse proxy used by millions of sites. This guide walks through installation, core configuration directives, and common deployment patterns.

Installation

# Debian/Ubuntu
sudo apt update
sudo apt install nginx
sudo systemctl enable --now nginx

# RHEL/CentOS/Fedora
sudo dnf install nginx
sudo systemctl enable --now nginx

# Verify
curl -I http://localhost

Configuration Structure

The main configuration file is /etc/nginx/nginx.conf. It uses a nested block structure:

# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile      on;
    keepalive_timeout 65;

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;
    gzip_min_length 256;

    # Limit upload size
    client_max_body_size 50m;

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

Server Blocks (Virtual Hosts)

Each site gets its own server block, typically in /etc/nginx/sites-available/:

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com/html;
    index index.html index.htm;

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

    # Static assets with long cache
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Deny access to hidden files
    location ~ /\. {
        deny all;
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t          # test configuration syntax
sudo systemctl reload nginx

Reverse Proxy with proxy_pass

Forward requests to an application server:

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

SSL/TLS Configuration

Terminate TLS at Nginx (see also the dedicated SSL/TLS Setup guide):

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    root /var/www/example.com/html;

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

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

The try_files Directive

try_files checks paths in order and falls back to the last argument:

# Serve file, then directory index, then pass to app
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

# Single-page application -- always serve index.html
location / {
    try_files $uri /index.html;
}

Gzip Compression

Compression reduces bandwidth significantly for text-based assets:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4;
gzip_min_length 256;
gzip_types
    text/plain
    text/css
    text/javascript
    application/json
    application/javascript
    application/xml
    image/svg+xml;

Common Troubleshooting

# Test configuration for syntax errors
sudo nginx -t

# View error log
sudo tail -f /var/log/nginx/error.log

# Check which process owns port 80
sudo ss -tlnp | grep :80

Return to the Web Servers hub or continue to Apache Guide and SSL/TLS Setup.