Production-ready, modular nginx configuration for secure and performant web hosting. Battle-tested architecture suitable for single sites, multi-domain hosting, microservices, and API gateways.
- Modern TLS - TLS 1.2/1.3 only, Mozilla Intermediate profile
- Security Headers - HSTS, CSP, X-Frame-Options, X-Content-Type-Options
- Rate Limiting - Per-endpoint DDoS protection
- Secure Defaults - Server tokens off, deny dangerous files, HTTPS-only
- HTTP/2 - Multiplexed connections for faster load times
- Gzip Compression - Optimized static asset delivery
- Connection Pooling - Keepalive and upstream connection optimization
- Smart Caching - Configurable cache strategies for static and dynamic content
- Reusable Snippets - DRY configuration with include files
- Separation of Concerns - Global configs, site configs, security headers
- Template Library - 11 production-ready site templates
- Easy Customization - Clear documentation and examples
/etc/nginx/
├── nginx.conf # Main configuration file
│
├── conf.d/ # Global HTTP-level configurations
│ ├── logformat.conf # Custom log formats
│ ├── maps.conf # WebSocket upgrade mapping
│ ├── mime.types # MIME type definitions
│ ├── performance.conf # Performance tuning
│ ├── proxy.conf # Proxy timeout and buffering defaults
│ ├── security.conf # Global security settings
│ └── tls-intermediate.conf # SSL/TLS configuration
│
├── snippets/ # Reusable configuration blocks
│ ├── deny-files.conf # Block access to sensitive files
│ ├── error-pages.conf # Custom error pages (502, 503, 504)
│ ├── gzip.conf # Compression settings
│ ├── letsencrypt.conf # ACME challenge support
│ ├── proxy-headers.conf # Standard proxy headers
│ ├── rate-limiting.conf # Rate limit configurations
│ ├── security-headers.conf # Common security headers
│ ├── static-files.conf # Static asset caching
│ └── stub-status.conf # Nginx status endpoint
│
├── sites-available/ # Site configuration templates
│ ├── api-gateway.example.com.conf # Microservices API gateway
│ ├── development.conf # Local development
│ ├── docker-compose.conf # Container routing
│ ├── example-site.com.conf # Full-featured multi-subdomain
│ ├── grafana.example.com.conf # Grafana monitoring
│ ├── librenms.example.com.conf # LibreNMS network monitoring
│ ├── load-balancer.conf # Multi-server load balancing
│ ├── netbox.example.com.conf # NetBox IPAM
│ ├── reverse-proxy.conf # Simple reverse proxy
│ ├── static-site.conf # Static HTML/SPA
│ └── wordpress.conf # WordPress with PHP-FPM
│
├── sites-enabled/ # Active site configurations (symlinks)
│ ├── defaults-80.conf # HTTP default server (HTTPS redirect)
│ └── defaults-443.conf # HTTPS default server (close invalid requests)
│
├── sites-security/ # Per-site security headers (CSP, etc)
│ ├── example-site.com.conf
│ └── whynoipv6.com.conf
│
├── html/errors/ # Custom error pages
│ ├── 502.html # Bad Gateway (backend down)
│ ├── 503.html # Service Unavailable (maintenance)
│ └── 504.html # Gateway Timeout (backend slow)
│
└── examples/ # Reference configurations
├── sse-example.conf # Server-Sent Events
└── websocket-example.conf # WebSocket support
Ubuntu/Debian:
sudo apt update
sudo apt install nginxCentOS/RHEL:
sudo yum install nginx# Clone repository
git clone https://github.com/lasseh/nginx-conf.git
cd nginx-conf
# Backup existing nginx config
sudo mv /etc/nginx /etc/nginx.backup
# Deploy this configuration
sudo cp -r . /etc/nginx/
# Test configuration
sudo nginx -t
# Start nginx
sudo systemctl start nginx
sudo systemctl enable nginx# Copy template
sudo cp /etc/nginx/sites-available/static-site.conf /etc/nginx/sites-available/mysite.com.conf
# Edit configuration
sudo nano /etc/nginx/sites-available/mysite.com.conf
# Update: server_name, ssl_certificate paths, root directory
# Obtain SSL certificate
sudo certbot certonly --webroot \
-d mysite.com -d www.mysite.com \
-w /var/www/_letsencrypt \
--email your@email.com -n --agree-tos
# Enable site
sudo ln -s /etc/nginx/sites-available/mysite.com.conf /etc/nginx/sites-enabled/
# Test and reload
sudo nginx -t && sudo nginx -s reload- Sites Available Guide - Complete reference for all 11 site templates
- Security Checklist - Security hardening guide
- API Gateway Setup - Microservices routing configuration
- API Gateway Diagram - Architecture visualization
- Best Practice Site Setup - Multi-subdomain configuration
- Monitoring Setup - Logging and health checks
sudo cp sites-available/static-site.conf sites-available/yoursite.com.conf
# Edit configuration, enable site, reload nginxsudo cp sites-available/reverse-proxy.conf sites-available/yoursite.com.conf
# Update upstream backend, enable site, reload nginxsudo cp sites-available/api-gateway.example.com.conf sites-available/api.yoursite.com.conf
# Configure service routing, enable site, reload nginxsudo cp sites-available/wordpress.conf sites-available/yoursite.com.conf
# Update database and PHP-FPM settings, enable site, reload nginxsudo cp sites-available/docker-compose.conf sites-available/yoursite.com.conf
# Configure container routing, enable site, reload nginx- ✅ HTTPS-only (automatic HTTP→HTTPS redirect)
- ✅ HSTS with 2-year max-age
- ✅ Modern TLS configuration (Mozilla Intermediate)
- ✅ Security headers (X-Frame-Options, CSP, etc)
- ✅ Rate limiting zones (API, general)
- ✅ Dangerous file blocking (.git, .env, .htaccess)
- ✅ Default servers catch invalid requests
- IP whitelisting for admin areas
- Basic authentication
- Client certificate authentication
- ModSecurity WAF integration
- Fail2ban integration
- ✅ HTTP/2 enabled
- ✅ Gzip compression
- ✅ Static file caching with immutable headers
- ✅ Connection keepalive and pooling
- ✅ Upstream keepalive connections
- ✅ Sendfile and tcp_nopush enabled
- ✅ Worker process tuning
- Proxy caching for dynamic content
- FastCGI caching for PHP
- Microcaching strategies
- CDN integration
# Test nginx configuration
sudo nginx -t# Test HTTP to HTTPS redirect
curl -I http://yoursite.com
# Test HTTPS
curl -I https://yoursite.com
# Test security headers
curl -I https://yoursite.com | grep -E "(Strict-Transport|X-Frame|X-Content)"
# Test compression
curl -H "Accept-Encoding: gzip" -I https://yoursite.com# Apache Bench
ab -n 1000 -c 10 https://yoursite.com/
# wrk
wrk -t4 -c100 -d30s https://yoursite.com/- Choose appropriate template from
sites-available/ - Copy to new filename:
yoursite.com.conf - Edit:
server_name, SSL paths, backend upstreams - Create security headers:
sites-security/yoursite.com.conf(if needed) - Obtain SSL certificate with certbot
- Create symlink:
ln -s ../sites-available/yoursite.com.conf sites-enabled/ - Test:
nginx -t - Reload:
nginx -s reload
- Performance: Edit
conf.d/performance.conf - Security: Edit
conf.d/security.conf - TLS: Edit
conf.d/tls-intermediate.conf - Logging: Edit
conf.d/logformat.conf
Changes to conf.d/ affect ALL sites.
Place in snippets/ and include in location blocks:
location /api/ {
include snippets/proxy-headers.conf;
include snippets/rate-limiting.conf;
proxy_pass http://backend;
}# Nginx status (localhost only)
curl http://localhost/nginx-status
# Backend health
curl https://yoursite.com/health# Watch access logs
sudo tail -f /var/log/nginx/access.log
# Watch error logs
sudo tail -f /var/log/nginx/error.log
# Check for errors
sudo grep -E "error|warn" /var/log/nginx/error.log- Prometheus + nginx-prometheus-exporter
- Grafana dashboards
- ELK stack (Elasticsearch, Logstash, Kibana)
- Custom monitoring scripts
# Test syntax
sudo nginx -t
# Check error log
sudo tail -50 /var/log/nginx/error.log# Verify certificate
sudo openssl x509 -in /etc/letsencrypt/live/yoursite.com/cert.pem -noout -dates
# Test SSL connection
openssl s_client -connect yoursite.com:443 -servername yoursite.com# Check nginx user
ps aux | grep nginx
# Fix permissions
sudo chown -R nginx:nginx /var/www/yoursite
sudo chmod -R 755 /var/www/yoursite# Test backend directly
curl -I http://127.0.0.1:3000
# Check firewall
sudo ufw status
# Check SELinux (CentOS/RHEL)
sudo setsebool -P httpd_can_network_connect 1# Graceful reload (no downtime)
sudo nginx -s reload
# Restart (brief downtime)
sudo systemctl restart nginx# Certbot automatic renewal (runs via cron/systemd timer)
sudo certbot renew
# Manual renewal
sudo certbot renew --force-renewal
# Test renewal process
sudo certbot renew --dry-run# Ubuntu/Debian
sudo apt update && sudo apt upgrade nginx
# CentOS/RHEL
sudo yum update nginx
# After update, test and reload
sudo nginx -t && sudo systemctl reload nginxThis configuration follows these principles:
- Security by Default - HTTPS everywhere, secure headers, rate limiting
- Separation of Concerns - Global configs, site configs, security headers in separate files
- DRY (Don't Repeat Yourself) - Reusable snippets for common patterns
- Explicit Over Implicit - Clear configuration over magic defaults
- Performance Minded - Optimized but not over-optimized
- Production Ready - Tested patterns suitable for real-world use
nginx.conf (main)
↓
conf.d/* (global HTTP-level settings)
↓
sites-enabled/* (site-specific servers)
↓
snippets/* (reusable location blocks)
Issues and pull requests welcome! Please ensure:
- Configuration tested with
nginx -t - Documentation updated
- Security best practices followed
- Comments explain "why" not just "what"
MIT License - Use freely in personal and commercial projects
Built on nginx best practices from:
Need help? Check the documentation or open an issue on GitHub.