Friday, September 18, 2026

Nginx flow on production

 

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