Nginx Configuration: Complete Guide from Scratch

Server blocks, SSL, gzip, caching, reverse proxy — every Nginx setting you need. We explain with ready config files.
Why nginx?
nginx (pronounced "engine-x") is a web server and reverse proxy that tops the list of most-used web servers globally. It serves over 30% of websites on the internet — including Netflix, Airbnb, and Dropbox. It excels in high performance and low memory consumption compared to Apache, especially with high concurrent connections.
Installation
# Ubuntu/Debian
sudo apt update
sudo apt install nginx -y
# Start and enable
sudo systemctl start nginx
sudo systemctl enable nginx
# Check status
sudo systemctl status nginx
# Check version
nginx -v
File Structure
/etc/nginx/
├── nginx.conf # Main configuration
├── conf.d/ # Additional configurations
├── sites-available/ # Available sites
├── sites-enabled/ # Enabled sites (symlinks)
├── snippets/ # Reusable snippets
└── mime.types # MIME types
Main Configuration (nginx.conf)
# File: /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
# Basics
sendfile on;
tcp_nopush on;
tcp_nodelay on;
types_hash_max_size 2048;
server_tokens off; # Hide nginx version
client_max_body_size 100M;
# MIME Types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/rss+xml
image/svg+xml;
# Timeouts
keepalive_timeout 65;
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
# Include site configurations
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Setting Up a Site with PHP (Laravel)
# File: /etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
# Site-specific logging
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# Security
location ~ /\.(?!well-known) {
deny all;
}
location ~* \.(env|log|git)$ {
deny all;
}
# Static files
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# Laravel Routing
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_read_timeout 300;
}
}
Enable the site:
# Create symlink
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
# Validate configuration
sudo nginx -t
# Reload
sudo systemctl reload nginx
SSL Setup with Let's Encrypt
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com
# Auto-renewal (automatically added via cron/systemd)
sudo certbot renew --dry-run
Optimized SSL Configuration
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL Certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Protocols and ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# Session Cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# 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;
root /var/www/example.com/public;
index index.php;
# ... remaining configuration as above
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Reverse Proxy
To forward requests to an application running on a specific port (Node.js, Python, etc.):
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_bypass $http_upgrade;
proxy_read_timeout 90;
}
}
Rate Limiting
# In the http block (nginx.conf)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=3r/m;
# In the server block
server {
# API — 10 requests per second
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://127.0.0.1:8000;
}
# Login page — 3 attempts per minute
location /login {
limit_req zone=login_limit burst=5;
try_files $uri /index.php?$query_string;
}
}
Caching
# In the http block
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m max_size=1g inactive=60m;
# In the location block
location /api/public/ {
proxy_cache app_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://127.0.0.1:8000;
}
Multiple Sites on One Server
# First site
server {
listen 80;
server_name site1.com;
root /var/www/site1/public;
# ...
}
# Second site
server {
listen 80;
server_name site2.com;
root /var/www/site2/public;
# ...
}
# API on subdomain
server {
listen 80;
server_name api.site1.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
Essential Management Commands
# Test configuration
sudo nginx -t
# Reload (no downtime)
sudo systemctl reload nginx
# Full restart
sudo systemctl restart nginx
# Show effective configuration
sudo nginx -T
# View logs
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
Troubleshooting Common Errors
| Error | Likely Cause | Solution |
|---|---|---|
| 502 Bad Gateway | PHP-FPM not running | sudo systemctl restart php8.3-fpm |
| 403 Forbidden | Wrong permissions | chown -R www-data:www-data /var/www |
| 413 Request Entity Too Large | Upload size limited | Increase client_max_body_size |
| 504 Gateway Timeout | Process takes too long | Increase fastcgi_read_timeout |
nginx on CLOUD
CLOUD (cloud.net.sa) servers come with a clean Ubuntu installation and root access — install nginx and configure it exactly as you need. With fast SSD storage and very low latency from Riyadh, you get high performance for your websites and applications.
Start with a VPS from CLOUD at competitive pricing — pricing and plans and set up nginx to host multiple sites on a single server with high efficiency.
Get Started
Want to try it yourself? Choose the right hosting plan or build your custom server with the specs you need.
