Nginx Default Configuration Structure and Logging Formats
Nginx loads its primary configuration from /etc/nginx/nginx.conf. Near the end of that file, an include directive pulls in additional files, commonly /etc/nginx/conf.d/*.conf, which is where most virtual hosts are defined.
List default fragments under conf.d:
- ls -l /etc/nginx/conf.d/
Core structure of nginx.conf
-
Global (main) context
- user: OS account used by the master/worker processses
- worker_processes: number of workers (auto is typical)
- error_log: global error log path and level
- pid: location of the master PID file
- worker_rlimit_nofile: upper bound on open FDs per worker
-
events context
- use: event loop mechanism (epoll on modern Linux, kqueue on BSD/macOS)
- worker_connections: max connections per worker
- multi_accept: whether a worker accepts as many queued connections as possible
-
http context
- MIME types and default_type
- log_format definitions and access_log targets
- I/O tuning (sendfile, tcp_nopush, tcp_nodelay)
- keepalive_timeout and gzip settings
- include of virtual host files (e.g., conf.d/*.conf)
Example nginx.conf (concise and production-safe)
# ===== main (global) =====
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
worker_rlimit_nofile 65535;
# ===== events =====
events {
use epoll; # kqueue on *BSD/macOS
worker_connections 8192; # per worker
multi_accept on;
}
# ===== http =====
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Extended access log with upstream timing and status
log_format main_ext
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_addr $upstream_status';
access_log /var/log/nginx/access.log main_ext;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65s;
gzip on;
gzip_comp_level 2;
gzip_min_length 1k;
gzip_types text/plain text/css application/json application/javascript application/xml;
include /etc/nginx/conf.d/*.conf;
}
Load balancing pool (define upstream backends in any http context, commonly in a file under conf.d):
upstream backend_pool {
# 192.0.2.0/24 is TEST-NET-1; replace with real backends
server 192.0.2.11:80 weight=3 max_fails=2 fail_timeout=30s;
server 192.0.2.12:80 weight=2;
server 192.0.2.13:80 backup; # only used when primaries fail or are overloaded
}
Example virtual host (/etc/nginx/conf.d/default.conf)
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html index.htm;
# Reverse proxy to load-balanced backends
location / {
proxy_pass http://backend_pool;
# Preserve client/proto info
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;
# Timeouts
proxy_connect_timeout 30s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffering
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
proxy_temp_file_write_size 64k;
# Bodies
client_max_body_size 10m;
client_body_buffer_size 128k;
# Let nginx serve custom error pages instead of relaying upstream errors directly
proxy_intercept_errors on;
}
# PHP via FastCGI (if PHP-FPM is present)
location ~ \.ph(p|p5)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Static asset caching
location ~* \.(?:jpg|jpeg|png|gif|bmp|svg|webp|ico)$ {
expires 10d;
access_log off;
}
location ~* \.(?:css|js)$ {
expires 1h;
access_log off;
}
# Lightweight status (limit visibility appropriately)
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
Directive highlights and tuning notes
- worker_processes: Use auto to match CPU cores unless constrained by memory/FD limits.
- worker_rlimit_nofile: Typically matches ulimit -n; ensure it’s high enough for expected concurrency.
- worker_connections: Effective connection ceiling ≈ worker_processes × worker_connections.
- use epoll: Highest-throughput choice for modern Linux; kqueue for BSD/macOS.
- sendfile/tcp_nopush/tcp_nodelay: Optimize file transfer and packetization; keep tcp_nopush on with sendfile.
- keepalive_timeout: 60–75s is a common balance of reuse vs. resource retention.
- gzip: Compress text-like payloads; avoid images and already-compressed formats.
Logging fundamentals
-
error_log
- Captures Nginx runtime issues and upstream/proxy errors.
- Levels: debug, info, notice, warn, error, crit, alert, emerg.
- Example: error_log /var/log/nginx/error.log warn;
-
access_log
- Records each HTTP request and response according to a chosen log_format.
- You can define multiple log_format entries and assign different ones per server/location.
log_format syntax
- log_format name [escape=default|json] string ...;
- Defined inside http { } and referenced by access_log path name;
JSON-friendly logging example
http {
# ...
log_format api_json escape=json '{"ts":"$time_iso8601","ip":"$remote_addr",'
'"method":"$request_method","uri":"$request_uri",'
'"status":$status,"bytes":$body_bytes_sent,"
'ref":"$http_referer","ua":"$http_user_agent",'
'"xff":"$http_x_forwarded_for","rt":$request_time}';
access_log /var/log/nginx/api.log api_json;
# ...
}
Common variables used in log_format
- $remote_addr: client IP address
- $remote_user: authenticated username (empty if not used)
- $time_local / $time_iso8601: server timestamp
- $request: full request line (method, URI, protocol)
- $request_method: HTTP method
- $request_uri: URI with args
- $status: response status code
- $body_bytes_sent: body bytes sent to client (no headers)
- $bytes_sent: total bytes sent including headers
- $http_referer: referring page
- $http_user_agent: user agent string
- $http_X: any inbound HTTP header accessible as $http_
- $upstream_addr / $upstream_status / $upstream_response_time: upstream details for proxied requests
- $request_time: total time to serve request
- $arg_name: query parameter named name, for example $arg_token
Validating and reloading configuration
- Syntax check: nginx -t -c /etc/nginx/nginx.conf
- Reload without downtime: nginx -s reload -c /etc/nginx/nginx.conf
Inspecting an HTTP exchange from the client side
- Use curl to print request/response metadata: curl -v https://example.com/ > /dev/null
- Lines beginning with > show the request; lines with < show the response
Static and dynamic separation pattern (illustrative)
# Dynamic requests to an app server; static assets served by nginx
location ~ \.(?:jsp|jspx|do)$ {
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;
proxy_pass http://127.0.0.1:8080;
}
location ~* \.(?:htm|html|gif|jpg|jpeg|png|bmp|swf|ico|rar|zip|txt|flv|pdf|xls|doc|ppt|mp3|wma)$ {
expires 15d;
}
location ~* \.(?:js|css)$ {
expires 1h;
}
Discovering included configuration files at runtime
- The default http block usually ends with: include /etc/nginx/conf.d/*.conf;
- Enumerate included files with: ls /etc/nginx/conf.d/