Complete Nginx Configuration on Production Server — Full Flow
1. What is Nginx Here
Before Nginx:
Browser → directly hits Node on port 5000 (not professional, not secure)
After Nginx:
Browser → Nginx (port 80/443) → forwards to React/Node containers
Nginx sits in front of everything. Users never see ports like 3000 or 5000.
2. SSH Into Production Server
ssh user@your-server-ip
3. Install Nginx
# Update packages
sudo apt update
# Install nginx
sudo apt install nginx -y
# Check version (confirms install worked)
nginx -v
# Output: nginx version: nginx/1.24.0
# Check nginx is running
sudo systemctl status nginx
# Output: Active: active (running)
4. Understand the Nginx Folder Structure
/etc/nginx/
├── nginx.conf ← master config file (don't touch this)
├── sites-available/ ← all your project configs live here
│ └── myproject ← your config file (disabled until linked)
├── sites-enabled/ ← nginx actually reads from here
│ └── myproject → (symlink) ← points to sites-available/myproject
└── snippets/ ← reusable config pieces (ssl etc)
Key concept:
- You write config in
sites-available/ - Nginx only reads from
sites-enabled/ - You connect them with a symlink — this is how you enable/disable a site without deleting config
5. Create Your Project Config File
sudo nano /etc/nginx/sites-available/myproject
Paste this inside
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# React frontend
location / {
proxy_pass http://localhost:3000;
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;
}
# Node backend API
location /api/ {
proxy_pass http://localhost:5000;
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;
}
}
Save and exit:
- Press
Ctrl + X - Press
Y - Press
Enter
6. What Each Line Means
listen 80;
# Nginx listens on port 80 (HTTP)
# All browser requests come in through here
server_name yourdomain.com www.yourdomain.com;
# Which domain this config applies to
# If request domain matches this → use this config block
location / {
# Any request starting with / (homepage, /about, /contact)
# Goes to React container
proxy_pass http://localhost:3000;
# Forward this request to React running on port 3000
proxy_http_version 1.1;
# Use HTTP 1.1 (supports persistent connections)
proxy_set_header Host $host;
# Tell the container which domain was requested
proxy_set_header X-Real-IP $remote_addr;
# Pass the real user IP to your app (not nginx's IP)
}
location /api/ {
# Any request starting with /api/ (api/users, /api/login)
# Goes to Node container
proxy_pass http://localhost:5000;
# Forward to Node running on port 5000
}
7. Enable the Config (Symlink)
# Create symlink from sites-available to sites-enabled
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
# Verify symlink was created
ls -l /etc/nginx/sites-enabled/
# Output: myproject -> /etc/nginx/sites-available/myproject
8. Remove Default Nginx Page
# Default nginx page blocks your config if not removed
sudo rm /etc/nginx/sites-enabled/default
9. Test and Reload Nginx
# Test config for syntax errors
sudo nginx -t
# Output:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# Reload nginx with new config (no downtime)
sudo systemctl reload nginx
# Verify nginx still running
sudo systemctl status nginx
10. Add SSL (HTTPS) — Certbot
Port 443 (HTTPS) setup using free SSL from Let's Encrypt.
# Install certbot
sudo apt install certbot python3-certbot-nginx -y
# Get SSL certificate (auto updates your nginx config)
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Follow prompts:
# Enter email → agree terms → choose redirect HTTP to HTTPS
Certbot automatically updates your nginx config to:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
# Redirects all HTTP → HTTPS automatically
}
server {
listen 443 ssl;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /api/ {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
11. Full Request Flow After Nginx Is Configured
User types yourdomain.com
↓
DNS resolves → your server IP
↓
Request hits server port 80
↓
Nginx receives request
— is it HTTP? → redirect to HTTPS (port 443)
↓
Request hits port 443
↓
Nginx checks /etc/nginx/sites-enabled/
— finds myproject config
— matches server_name yourdomain.com
↓
Nginx checks the URL path
↓
├── path is / → proxy_pass → React port 3000
│ ↓
│ React serves frontend
│ ↓
│ Browser renders page
│
└── path is /api/... → proxy_pass → Node port 5000
↓
Node processes request
↓
Node queries Postgres (port 5432)
(internal Docker network only)
↓
Postgres returns data
↓
Node sends JSON response
↓
React updates UI
12. Useful Nginx Commands You'll Use Regularly
# Test config before applying
sudo nginx -t
# Reload after config changes (no downtime)
sudo systemctl reload nginx
# Full restart (downtime — use only if reload fails)
sudo systemctl restart nginx
# Stop nginx
sudo systemctl stop nginx
# Start nginx
sudo systemctl start nginx
# Check nginx logs (debug errors)
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
# Check which ports nginx is listening on
sudo netstat -tlnp | grep nginx
13. Complete Picture — What Lives Where
PRODUCTION SERVER
│
├── /etc/nginx/
│ ├── sites-available/myproject ← your nginx config
│ └── sites-enabled/myproject ← symlink (enables it)
│
├── /home/user/your-repo/ ← git cloned project
│ ├── react/
│ ├── nodejs/
│ └── docker-compose.yml
│
└── Docker containers running:
├── React → port 3000
├── Node → port 5000
└── Postgres → port 5432 (internal only)
INTERNET
↓
yourdomain.com → Server IP
↓
port 80 → Nginx → redirect to 443
port 443 → Nginx → routes to containers
↓ ↓
React Node → Postgres
port 3000 port 5000
14. Update Flow When You Change Code
# On production server
cd /home/user/your-repo
# Pull latest code
git pull origin main
# Rebuild and restart Docker containers
docker-compose up --build -d
# Nginx does NOT need to restart
# It keeps forwarding to same ports 3000 and 5000
# Docker handles the new code inside containers
Nginx config only changes if you add a new domain or new route. Code changes never touch Nginx.
No comments:
Post a Comment