Nginx Production Checklist
Introduction
Deploying Nginx in production requires careful consideration of security, performance, and reliability. This checklist will guide you through the essential steps to ensure your Nginx server is properly configured for a production environment. Whether you're hosting a simple website or a complex web application, following these best practices will help you create a robust, secure, and efficient setup.
Nginx (pronounced "engine-x") is a popular web server, reverse proxy, and load balancer known for its high performance, stability, and low resource consumption. When moving from development to production, it's critical to properly configure Nginx to handle real-world traffic and potential security threats.
Pre-Deployment Preparation
Update to the Latest Stable Version
Always use the latest stable version of Nginx to benefit from security patches and performance improvements.
# Check current version
nginx -v
# Update on Ubuntu/Debian
sudo apt update
sudo apt upgrade nginx
# Update on CentOS/RHEL
sudo yum update nginx
Choose the Right Nginx Flavor
Depending on your needs, consider using:
- Nginx Open Source: The free, community version
- Nginx Plus: Commercial version with additional features like advanced load balancing and monitoring
- OpenResty: Nginx bundled with LuaJIT for extended functionality
- Tengine: Alibaba's fork with additional features
Essential Configuration Best Practices
Basic Configuration Structure
Keep your configuration organized using include directives:
# Main nginx.conf
http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Server Blocks (Virtual Hosts)
Use separate server blocks for each domain:
# /etc/nginx/sites-available/example.com.conf
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
# Additional configuration
}
Enable HTTPS
In production, HTTPS is mandatory for security:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# Rest of configuration
}
Let's Encrypt provides free SSL certificates:
# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get a certificate
sudo certbot --nginx -d example.com -d www.example.com
Redirect HTTP to HTTPS
Force all traffic to use HTTPS:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Security Hardening
Hide Server Information
Prevent exposing Nginx version information:
# In http block
http {
server_tokens off;
}
Configure Security Headers
Add security headers to protect against common vulnerabilities:
server {
# Other configuration
# Security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self';" always;
}
Implement Rate Limiting
Protect against brute force attacks and DoS attempts:
http {
# Define a zone
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
# Apply rate limiting to login endpoint
location /login {
limit_req zone=one burst=5;
# Other configuration
}
}
}
Configure Allowed Methods
Restrict HTTP methods to only those needed:
server {
# Other configuration
# Only allow GET, HEAD, and POST requests
if ($request_method !~ ^(GET|HEAD|POST)$) {
return 444;
}
}
Secure File Access
Prevent access to sensitive files:
server {
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Deny access to backup files
location ~ ~$ {
deny all;
}
}
Performance Optimization
Enable Gzip Compression
Reduce bandwidth and improve loading times:
http {
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/javascript
application/json
application/xml
text/css
text/plain
text/xml;
}
Configure Worker Processes and Connections
Optimize based on your server's resources:
# Automatically set worker processes based on CPU cores
worker_processes auto;
events {
# Increase worker connections based on your server capacity
worker_connections 1024;
multi_accept on;
}
Set Up Buffers and Timeouts
Configure appropriate buffer sizes and timeouts:
http {
# Client buffer size
client_body_buffer_size 10k;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;
# Timeouts
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
}
Configure Caching
Enable caching for static content:
http {
# Define cache path
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
server {
# Apply caching to static content
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000";
}
# Cache API responses
location /api/ {
proxy_pass http://backend_server;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
}
}
}
Logging and Monitoring
Configure Proper Logging
Set up detailed logs without exposing sensitive information:
http {
# Define log format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Apply log format
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
server {
# Site-specific logs
access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log warn;
}
}
Log Rotation
Set up log rotation to manage log files:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
Set Up Monitoring
Integrate with monitoring tools by enabling the Nginx status page:
server {
# Other configuration
# Status page only accessible from localhost
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
High Availability and Load Balancing
Configure Upstream Servers
Set up load balancing across multiple backend servers:
http {
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com;
server backup1.example.com backup;
keepalive 16;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
}
Load Balancing Methods
Choose the appropriate load balancing algorithm:
upstream backend {
# Round Robin (default)
server backend1.example.com;
server backend2.example.com;
# Or least connections
least_conn;
# Or IP hash for session persistence
ip_hash;
}
Configuration Testing and Deployment
Test Configuration Before Applying
Always verify your configuration before reloading Nginx:
# Test configuration
sudo nginx -t
# Apply configuration if test passes
sudo nginx -s reload
Continuous Integration Workflow
Production Deployment Checklist
Use this checklist before going live:
- ✅ Latest stable Nginx version installed
- ✅ HTTPS configured with proper certificates
- ✅ HTTP to HTTPS redirection enabled
- ✅ Security headers implemented
- ✅ Server information hidden
- ✅ Rate limiting configured
- ✅ Gzip compression enabled
- ✅ Worker processes and connections optimized
- ✅ Buffers and timeouts configured
- ✅ File access restrictions in place
- ✅ Caching strategy implemented
- ✅ Proper logging configured
- ✅ Log rotation set up
- ✅ Monitoring enabled
- ✅ Backup and disaster recovery plan in place
- ✅ Configuration tested and validated
Real-World Example: Complete Production Server Block
Here's a comprehensive example that incorporates many of the best practices discussed:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; form-action 'self';" always;
# Root directory and index files
root /var/www/example.com/public;
index index.html index.htm index.php;
# Logs
access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log warn;
# Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000";
access_log off;
}
# PHP handling
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}
# API proxy with caching
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
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_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_bypass $http_pragma;
add_header X-Cache-Status $upstream_cache_status;
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
# Default location block
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
Maintenance Best Practices
Regular Updates and Patches
Schedule regular maintenance windows to apply updates:
# Set up unattended upgrades for security patches
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Backup Strategy
Regularly back up your Nginx configuration:
# Create a backup script
#!/bin/bash
BACKUP_DIR="/backup/nginx/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
cp -R /etc/nginx/* $BACKUP_DIR
tar -czf $BACKUP_DIR.tar.gz $BACKUP_DIR
rm -rf $BACKUP_DIR
Summary
This Nginx production checklist covers the essential aspects of deploying Nginx in a production environment:
- Pre-Deployment Preparation: Keep Nginx updated and choose the right flavor for your needs.
- Essential Configuration: Organize your configuration, set up server blocks, and enable HTTPS.
- Security Hardening: Hide server information, add security headers, implement rate limiting, and restrict file access.
- Performance Optimization: Enable compression, optimize workers and connections, configure buffers and timeouts, and set up caching.
- Logging and Monitoring: Configure proper logging, set up log rotation, and enable monitoring.
- High Availability: Set up load balancing and choose appropriate balancing methods.
- Testing and Deployment: Test configurations before applying and establish a CI/CD workflow.
- Maintenance: Keep Nginx updated and back up configurations regularly.
By following these best practices, you'll ensure your Nginx server is secure, performant, and reliable in a production environment.
Additional Resources
- Official Nginx Documentation
- Nginx Security Hardening Guide
- Mozilla SSL Configuration Generator
- Nginx Tuning for Best Performance
Exercises
- Set up a basic Nginx server with HTTPS using Let's Encrypt.
- Configure rate limiting to protect a login endpoint.
- Implement a caching strategy for a website with static and dynamic content.
- Set up a load balancer to distribute traffic across two backend servers.
- Create a monitoring dashboard for your Nginx server using Prometheus and Grafana.
If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)