DevOps & Infrastructure

Nginx Reverse Proxy

ตั้งค่า Proxy Server สำหรับ หลาย Applications

คู่มือสอนขั้นตอนการตั้งค่า Nginx Reverse Proxy สำหรับ Node.js, Python, และ Static Files พร้อม SSL/TLS และ Security Best Practices

Ubuntu
Nginx
Node.js
Python

Reverse Proxy คืออะไร?

Reverse Proxy คือ server ที่อยู่ระหว่าง client และ backend servers ทำหน้าที่เป็น gateway สำหรับรับ requests และส่งต่อไปยัง server จริง Nginx เป็นหนึ่งใน reverse proxy ที่ได้รับความนิยมสูงเพราะ:

  • Load Balancing: กระจาย traffic ไปยังหลาย server
  • SSL Termination: จัดการ HTTPS ที่ proxy layer
  • Caching: เก็บ static content เพื่อลด load
  • Security: ซ่อน IP ของ backend servers

สถาประกอบ Reverse Proxy

Internet Nginx Reverse Proxy App 1 App 2 App 3 🔒 SSL/TLS

สิ่งที่ต้องเตรียม

Server Requirements

  • Ubuntu 20.04 LTS หรือใหม่กว่า
  • Minimum 1GB RAM (2GB แนะนำ)
  • Sudo หรือ root access
  • Domain name ที่ตั้ง DNS แล้ว

Network Requirements

  • Port 80 (HTTP) และ 443 (HTTPS) เปิด
  • Static IP หรือ DNS pointing ถูกต้อง
  • Firewall rules อนุญาตให้ traffic

ขั้นตอนการติดตั้ง Nginx

ขั้นตอนที่ 1: อัปเดต System

อัปเดต package lists และ upgrade packages ทั้งหมด

sudo apt update
sudo apt upgrade -y

ขั้นตอนที่ 2: ติดตั้ง Nginx

ติดตั้ง Nginx จาก repository ของ Ubuntu

sudo apt install nginx -y

ขั้นตอนที่ 3: ตรวจสอบและเริ่ม Nginx

ตรวจสอบสถานะ Nginx และเริ่ม service

sudo systemctl enable nginx
sudo systemctl start nginx

# ตรวจสอบสถานะ
sudo systemctl status nginx

ขั้นตอนที่ 4: อนุญาต Firewall

อนุญาต traffic ผ่าน port 80 และ 443

# อนุญาต HTTP และ HTTPS
sudo ufw allow 'Nginx Full'

# ตรวจสอบสถานะ firewall
sudo ufw status

ตรวจสอบ: เปิด browser และไปที่ http://your-server-ip ควรเห็นหน้า "Welcome to Nginx"

ตัวอย่างการตั้งค่า

Node.js Application

ตั้งค่า proxy สำหรับ Node.js app ที่รันบน port 3000

/etc/nginx/sites-available/nodejs-app
server { listen 80; server_name example.com www.example.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_cache_bypass $http_upgrade; } }

เคล็ดลับ: สำหรับ WebSocket (Socket.io) ต้องเพิ่ม proxy_set_header สำหรับ Upgrade และ Connection เพื่อให้ real-time connection ทำงานได้

Python Flask Application

ตั้งค่า proxy สำหรับ Flask app ที่รันบน port 5000

/etc/nginx/sites-available/flask-app
server { listen 80; server_name flask.example.com; location / { proxy_pass http://127.0.0.1:5000; 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; } location /static { alias /var/www/flask-app/static; expires 30d; add_header Cache-Control "public, immutable"; } }

Static Files

ตั้งค่าสำหรับ serve static files (HTML, CSS, JS, Images)

/etc/nginx/sites-available/static-site
server { listen 80; server_name static.example.com; root /var/www/static-site; index index.html; # Enable gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1000; # Cache static assets location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 1y; add_header Cache-Control "public, immutable"; } location / { try_files $uri $uri/ /index.html; } }

Docker Compose Setup

Node.js Backend

สร้าง Node.js backend พร้อม health check endpoint

mkdir -p nginx-proxy/backend && cd nginx-proxy/backend
cat > package.json << 'EOF'
{"name": "nginx-proxy-backend",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
EOF

npm install
const express = require('express');
const app = express();
const port = 3000;

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'healthy' });
});

// Main endpoint
app.get('/', (req, res) => {
  res.json({ message: 'Hello from Backend!' });
});

app.listen(port, '0.0.0.0', () => {
  console.log(`Backend running on port ${port}`);
});

Docker Compose Configuration

ตั้งค่า docker-compose.yml สำหรับ Nginx + Backend

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "3000:3000"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

รัน Docker Compose: docker-compose up -d

Load Balancing

กระจาย traffic ไปยังหลาย backend servers ด้วย Load Balancing algorithms ต่างๆ

Nginx Load Balancing Algorithms

Nginx รองรับ algorithms สำหรับ load balancing:

round-robin

กระจาย requests แบบ rotation

least_conn

ส่งไป server ที่มี connections น้อยที่สุด

ip_hash

ใช้ client IP เป็น key (session sticky)

# Upstream block สำหรับ Load Balancing
upstream backend {
    least_conn;

    server backend1:3000 weight=3;
    server backend2:3001 weight=2;
    server backend3:3002 weight=1 backup;
    
    keepalive 32;
}

server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        
        # Health check
        proxy_next_upstream_timeout 5s;
        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;
    }
}

Weight Parameters

weight=3 - Traffic 60%
weight=2 - Traffic 30%
backup - Server standby

Keepalive

keepalive 32
รักษา connections เปิดไว้เพื่อลด latency

ตั้งค่า SSL/TLS ด้วย Let's Encrypt

การใช้ Certbot (Let's Encrypt)

รับ SSL certificate ฟรีและอัตโนมีด้วย Certbot

1. ติดตั้ง Certbot

sudo apt install certbot python3-certbot-nginx -y

2. รับ SSL Certificate

sudo certbot --nginx -d example.com -d www.example.com

Certbot จะอัตโนมีแก้ config ของ Nginx ให้

3. ตรวจสอบ Auto Renewal

# ตรวจสอบ timer
sudo systemctl status certbot.timer

# Test renewal
sudo certbot renew --dry-run

หมายเหตุ: Certificate ของ Let's Encrypt มีอายุ 90 วัน แต่ Certbot จะตั้งค่า auto-renewal ให้อัตโนมี

Docker SSL Setup

ใช้ Certbot ใน Docker container สำหรับรับ SSL certificate

docker run --rm -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/lib/letsencrypt:/var/lib/letsencrypt \
  -p 80:80 -p 443:443 \
  certbot/certbot certonly --standalone \
  -d example.com -d www.example.com \
  --agree-tos --no-eff-email --maintain-email \
  --email your@email.com
# Docker Compose สำหรับ Certbot
services:
  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot-config:/etc/letsencrypt
      - ./certbot-logs:/var/log/letsencrypt
      - ./certbot-webroot:/var/www/html
    ports:
      - "80:80"
    command: >
      certonly --standalone
      --agree-tos --no-eff-email
      -d example.com -d www.example.com

Advanced Security Features

Rate Limiting

จำกัด rate ของ requests สำหรับป้องกัน DDoS

# Rate limit zone - 10 requests per second per IP
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

# Connection limit
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $server_name zone=per_server:10m;

server {
    location / {
        limit_req zone=one burst=20 nodelay;
        limit_conn addr 10;

        # Rate limit response
        limit_req_status 429;
        limit_req_log /var/log/nginx/ratelimit.log;
    }
}

Security Headers

เพิ่ม security headers สำหรับป้องกัน XSS, Clickjacking

server {
    # XSS Protection
    add_header X-XSS-Protection "1; mode=block" always;

    # Prevent MIME type sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # Prevent clickjacking
    add_header X-Frame-Options "SAMEORIGIN" always;

    # Referrer Policy
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # CSP (Content Security Policy)
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
}

Connection Limits

จำกัด connections และ timeouts

worker_processes auto;
worker_connections 1024;
worker_rlimit_nofile 4096;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    # Connection limits
    client_max_body_size 10M;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k;

    # Timeouts
    client_body_timeout 60s;
    client_header_timeout 60s;
    send_timeout 60s;
    keepalive_timeout 65s;
    keepalive_requests 100;
}

IP Whitelisting

อนุญาต access จาก IP ที่ระบุเท่านั้น

allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;

location /admin {
    # Allow only from specific IPs
    allow 192.168.1.100;
    allow 192.168.1.101;
    deny all;

    # Admin endpoints here
    proxy_pass http://backend:8080;
}

Security Best Practices

Disable Server Tokens

# ซ่อน version ของ Nginx server_tokens off;

Limit Request Size

# จำกัดขนาด request client_max_body_size 10M;

Security Headers

add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; add_header X-XSS-Protection "1; mode=block";

Rate Limiting

# จำกัด rate ของ requests limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; limit_req zone=one burst=20 nodelay;

การแก้ปัญหา

502 Bad Gateway

Backend server ไม่ทำงานหรือ port ผิด

# ตรวจสอบ backend service
sudo systemctl status nodejs-app

# ตรวจสอบ port
sudo netstat -tlnp | grep :3000

Permission Denied

Nginx ไม่มี permission อ่านไฟล์

# ตรวจสอบ user ของ Nginx
ps aux | grep nginx

# เปลี่ยน permission
sudo chown -R www-data:www-data /var/www/your-app

Config Test

ตรวจสอบความถูกต้องของ config ก่อน restart

# ทดสอบ config
sudo nginx -t

# Reload config (ไม่หยุด service)
sudo systemctl reload nginx