Skip to main content

nginx.conf Structure

Learning Focus

Leave this lesson with a working understanding of nginx.conf structure that you can apply immediately in production.

Nginx configuration uses a hierarchical block system. Understanding the context hierarchy is fundamental — directives in outer blocks are inherited by inner blocks, but inner blocks can override them.


Context Hierarchy

Main context (top of file — global settings)
└── events { } (connection handling)
└── http { } (all HTTP traffic)
└── server { } (one site / virtual host)
└── location { } (URL-path specific rules)

Directives only work inside their allowed context. Putting listen inside http {} is an error.


Annotated nginx.conf Template

/etc/nginx/nginx.conf
# ============================================================
# MAIN CONTEXT — global settings
# ============================================================

# User and group the worker processes run as
user www-data;

# Number of worker processes — match CPU count (or use auto)
worker_processes auto;

# Max number of open file descriptors per worker
worker_rlimit_nofile 65535;

# PID file location
pid /run/nginx.pid;

# Dynamic modules (Debian/Ubuntu)
include /etc/nginx/modules-enabled/*.conf;

# ============================================================
# EVENTS CONTEXT — connection model
# ============================================================
events {
# Max simultaneous connections per worker
# Total capacity = worker_processes × worker_connections
worker_connections 1024;

# Accept multiple connections per event (recommended)
multi_accept on;

# Connection processing method (epoll is best on Linux)
use epoll;
}

# ============================================================
# HTTP CONTEXT — all HTTP settings
# ============================================================
http {
# MIME types
include /etc/nginx/mime.types;
default_type application/octet-stream;

# ---- Logging ----
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;

# ---- Performance ----
sendfile on; # Efficient file serving via kernel
tcp_nopush on; # Send headers + start of file together
tcp_nodelay on; # Disable Nagle for keep-alive

# ---- Keep-Alive ----
keepalive_timeout 65;
keepalive_requests 1000;

# ---- Compression ----
gzip on;
gzip_types text/plain text/css application/json
application/javascript text/xml
application/xml image/svg+xml;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_vary on;

# ---- Security ----
server_tokens off; # Hide Nginx version in headers/error pages

# ---- Buffer Sizes ----
client_max_body_size 64m;
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

# ---- Timeouts ----
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;

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

Key Directives Reference

Main Context

DirectiveExampleWhat It Does
userwww-dataWorker process user
worker_processesautoNumber of workers (match CPU cores)
worker_rlimit_nofile65535Max open files per worker
pid/run/nginx.pidPID file path
error_log/var/log/nginx/error.log warnServer-level error log

Events Context

DirectiveExampleWhat It Does
worker_connections1024Max connections per worker
multi_acceptonAccept multiple connections per iteration
useepollLinux event model (epoll is optimal)

HTTP Context (Most Common)

DirectiveExampleWhat It Does
sendfileonKernel-level file sending (faster)
tcp_nopushonBatch send headers + data
tcp_nodelayonLow latency for keep-alive
keepalive_timeout65How long to keep idle connections
gziponEnable gzip compression
server_tokensoffHide Nginx version
client_max_body_size64mMax upload size

Apply Changes

# Always test before reloading
sudo nginx -t

# Graceful reload (zero downtime)
sudo nginx -s reload

# Or via systemctl
sudo systemctl reload nginx

# Full restart (drops active connections)
sudo systemctl restart nginx

# Dump the complete merged config (debug tool)
sudo nginx -T

Common Mistakes

MistakeErrorFix
Missing semicolon at end of directivenginx: [emerg] ...Add ; after every directive
Unclosed braceConfig parse errorMatch every { with }
Wrong context for directivedirective not allowed hereMove to correct context
Forgetting include for site configsSites not loadedCheck include paths in nginx.conf
Setting worker_processes too highCPU contentionUse auto or match core count

Hands-On Practice

# Verify Nginx is running
sudo systemctl status nginx

# Test config syntax
sudo nginx -t

# Reload without downtime
sudo nginx -s reload

# Check error log
sudo tail -20 /var/log/nginx/error.log

Common Pitfalls

PitfallWhat happensFix
Editing config without reloadingChanges not appliedsudo nginx -s reload after every edit
Not running nginx -t firstReload breaks with syntax errorAlways test syntax before reloading
Wrong socket path for PHP-FPM502 Bad Gatewayls /run/php/ and verify the exact socket filename

What's Next

  • Continue to the next lesson in this module, or go to the module index for an overview.
  • Use the Cheatsheets for quick CLI reference.