Nginx Installation and Reverse Proxy Configuration Guide
Install Nginx from scratch, configure virtual hosts, and set up reverse proxy for Node.js / PHP-FPM. Performance and security tips.
Using Nginx instead of Apache, or want to put a reverse proxy in front of your Node.js/Python/Docker app? You’re in the right place. Nginx is in roughly 35% of modern web servers — its async architecture uses far less resources than Apache. This guide covers install, vhost, and reverse proxy step by step.
Prerequisites
- Ubuntu 22.04 / Debian 12 (use
dnffor AlmaLinux) - Root access
- Ports 80, 443 open (UFW post)
1. Install Nginx
sudo apt update
sudo apt install nginx -y
sudo systemctl enable --now nginx
sudo systemctl status nginx
Open http://vds-ip in browser → you should see the Nginx default page.
2. Check for Apache conflict
If Apache is already installed, Nginx won’t start (port 80 conflict):
sudo systemctl stop apache2
sudo systemctl disable apache2
Or move Apache to 8080 (advanced).
3. First virtual host (your site)
sudo nano /etc/nginx/sites-available/yoursite.com
server {
listen 80;
listen [::]:80;
server_name yoursite.com www.yoursite.com;
root /var/www/yoursite.com;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
# PHP-FPM (for WordPress)
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}
# Long cache for static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
access_log /var/log/nginx/yoursite.com_access.log;
error_log /var/log/nginx/yoursite.com_error.log;
}
Activate:
sudo ln -s /etc/nginx/sites-available/yoursite.com /etc/nginx/sites-enabled/
sudo nginx -t # syntax test
sudo systemctl reload nginx
4. Reverse proxy: in front of Node.js / Docker
Say your Node.js app runs on port 3000. Put Nginx on 80/443 and proxy to it:
server {
listen 80;
server_name app.yoursite.com;
location / {
proxy_pass http://localhost: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;
}
}
Wins:
- WebSocket support (
proxy_http_version 1.1+ Upgrade header) - SSL termination (Let’s Encrypt at Nginx, app stays plain HTTP)
- Serve static content (don’t tax Node.js)
5. Add SSL (Let’s Encrypt)
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yoursite.com -d www.yoursite.com
Details: Let’s Encrypt post.
Certbot adds the HTTPS block to your vhost and sets up HTTP→HTTPS redirect.
6. Performance tuning
/etc/nginx/nginx.conf:
worker_processes auto;
worker_connections 4096;
# Buffer settings
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 50m;
large_client_header_buffers 4 8k;
# 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 image/svg+xml;
# Brotli (if module installed)
# brotli on;
# brotli_comp_level 6;
# HTTP/2
listen 443 ssl http2;
sudo nginx -t && sudo systemctl reload nginx
7. Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Test: https://securityheaders.com/
8. Rate limiting (DDoS protection)
# In nginx.conf, http block
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
# In server block
location /api/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://localhost:3000;
}
Our DDoS post details this: DDoS Protection.
9. Log management
# Live tail
sudo tail -f /var/log/nginx/yoursite.com_access.log
# Top hitting IPs
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 404s
sudo grep " 404 " /var/log/nginx/access.log | tail -20
logrotate is pre-configured for Nginx (/etc/logrotate.d/nginx).
Common errors
- “nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)”: Apache is running → stop it
- “502 Bad Gateway”: reverse proxy backend down →
systemctl status node-app - “413 Request Entity Too Large”: bump
client_max_body_size - “504 Gateway Timeout”: add
proxy_read_timeout 300s; - PHP not running: PHP-FPM installed and running?
sudo systemctl status php8.3-fpm
Nginx vs Apache comparison
| Nginx | Apache | |
|---|---|---|
| Architecture | Async, event-driven | Process-based |
| Resources | Less RAM/CPU | More |
| Static files | Very fast | Fast |
| .htaccess | ❌ Not supported | ✓ |
| Reverse proxy | Native | Via mod_proxy |
| Config | sites-available syntax | .conf files |
Both work for WordPress; Nginx is more efficient under high traffic.
Conclusion
Nginx is a cornerstone of the modern web stack. From one VDS, you can run multiple sites + reverse proxy + SSL termination. KavesNET VDS is optimized for Nginx.
Related: WordPress Manual Install · Cloudflare CDN
Related Posts
You might also like these.
What Is NVMe SSD? Its Impact on Server Performance (vs SATA SSD)
What is NVMe, and how does it differ from SATA SSD? IOPS, latency, and real-world numbers showing why NVMe is now the server standard.
Read More
What Is a Dedicated Server? Who Actually Needs One?
What is a dedicated server, how does it differ from a VDS, and when is it a must? Advantages, costs, and the co-location alternative — all in this guide.
Read More
VDS Rental Guide: 10 Criteria to Check Before You Order
From CPU model to disk type, DDoS protection to backups — the 10 criteria to verify before renting a VDS, explained one by one. Don't pick the wrong plan.
Read More