CLOUD
Guides

Nginx Configuration: Complete Guide from Scratch

CLOUD|January 24, 2026|5 min read|638 views
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.

Share