← กลับ
NginxInfrastructureServer

Nginx Reverse Proxy คืออะไร ทำไมต้องใช้?

Nginx ไม่ใช่แค่เสิร์ฟ static files ใช้เป็นด่านหน้ารับ traffic ครบทั้ง SSL, cache, rate limit ในไฟล์เดียว

2026-01-18อ่าน 6 นาทีใหม่

Reverse Proxy คืออะไร

ปกติ flow เวลาเปิดเว็บ:

Client → Server (Node.js port 3000)

แต่ในชีวิตจริง production แทบทุก server มี layer Nginx อยู่ตรงกลาง:

Client → Nginx (port 443) → Node.js (port 3000)

Nginx ตรงนี้ทำหน้าที่ "rerouting" request จาก client ไปยัง backend service จริง — เลยเรียกว่า reverse proxy (ตรงข้ามกับ forward proxy ที่ client ใช้ไป hide ตัวเอง)

ทำไมไม่ให้ Node.js รับ request โดยตรง

ทำได้แต่ไม่แนะนำ เพราะ Nginx ทำสิ่งที่ Node.js ทำได้ไม่ดี:

  1. SSL/TLS termination — Nginx จัดการ HTTPS เก่ง app ไม่ต้องรู้เรื่อง cert
  2. Static file — Nginx serve ไฟล์ static เร็วกว่า Node.js หลายสิบเท่า
  3. Concurrency — Nginx รับ connection พร้อมกันได้เป็นแสน Node.js เธรดเดียวรับได้น้อยกว่า
  4. Load balancing — กระจาย traffic ไปหลาย instance ได้
  5. Gzip / Brotli — บีบ response ก่อนส่ง ลด bandwidth
  6. Rate limiting — กัน abuse ได้ง่าย
  7. Hide backend — ผู้โจมตีไม่รู้ว่า backend คืออะไรอยู่ port ไหน

ตัวอย่างเทียบ: ถ้าให้ Node.js serve เว็บ static อย่างเดียวรับได้ ~5,000 req/s; ใช้ Nginx serve ไฟล์เดียวกันได้ ~50,000 req/s

ติดตั้ง Nginx

# Ubuntu / Debian
sudo apt update
sudo apt install -y nginx

# start
sudo systemctl enable --now nginx

# เช็คว่ารันแล้ว
sudo systemctl status nginx
curl http://localhost

ไฟล์ config สำคัญ:

  • /etc/nginx/nginx.conf — global config
  • /etc/nginx/sites-available/ — เก็บ config แต่ละ site
  • /etc/nginx/sites-enabled/ — symlink ของ site ที่เปิดใช้
  • /var/log/nginx/ — log

Config พื้นฐานสำหรับ Node.js app

สร้าง /etc/nginx/sites-available/myapp:

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    # max upload size
    client_max_body_size 10M;

    # ส่ง access log
    access_log /var/log/nginx/myapp.access.log;
    error_log /var/log/nginx/myapp.error.log;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # header ที่ backend ควรรู้
        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;

        # support websocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;

        # timeout
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }
}

เปิดใช้ + reload:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default  # ถ้ามี default site เก่า

# ทดสอบ syntax ก่อน reload เสมอ
sudo nginx -t

# reload โดยไม่ตัด connection
sudo systemctl reload nginx

SSL ฟรีด้วย Certbot

sudo apt install -y certbot python3-certbot-nginx

# ออก cert + แก้ config ให้ใช้ HTTPS อัตโนมัติ
sudo certbot --nginx -d myapp.com -d www.myapp.com

หลังรัน config จะถูกแก้เป็นแบบนี้:

server {
    listen 443 ssl http2;
    server_name myapp.com;

    ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;

    # ... ส่วนเดิม
}

# redirect HTTP → HTTPS
server {
    listen 80;
    server_name myapp.com www.myapp.com;
    return 301 https://$host$request_uri;
}

Certbot จะตั้ง systemd timer ให้ renew auto ทุก 60 วัน — ตรวจสอบด้วย:

sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run

Cache static files

ใส่ใน server block:

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
    proxy_pass http://127.0.0.1:3000;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

วิธีนี้ browser cache ไฟล์ไว้ 30 วัน แต่ proxy ยังส่งไป Node.js ดังนั้นไฟล์ที่อัพเดทจะใช้ filename hash ใหม่ (เช่น app.f9a2b3c.js)

ถ้าอยากให้ Nginx cache ตัวเอง (ไม่ผ่าน Node.js เลย) ต้องตั้ง proxy_cache_path ใน nginx.conf + proxy_cache ใน location

Gzip / Brotli compression

/etc/nginx/nginx.conf มี gzip enabled by default แต่อาจไม่ได้เปิดทุกอย่าง:

# ใน http block
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
    text/plain
    text/css
    text/javascript
    application/javascript
    application/json
    application/xml
    image/svg+xml;

Brotli บีบดีกว่า gzip 15-25% แต่ต้องลง module เพิ่ม:

sudo apt install -y libnginx-mod-brotli

แล้วเพิ่มใน config:

brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;

Rate limiting

ใส่ใน http block (/etc/nginx/nginx.conf):

# zone ขนาด 10MB เก็บ IP, จำกัด 10 req/s ต่อ IP
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

ใช้ใน location:

location /api/ {
    # อนุญาต burst 20 ก่อนเริ่ม limit
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://127.0.0.1:3000;
}

location /login {
    # login limit เข้มกว่า กัน brute force
    limit_req zone=login burst=3 nodelay;
    proxy_pass http://127.0.0.1:3000;
}

Load balancing หลาย instance

ถ้ามี Node.js หลาย instance:

upstream nodejs_app {
    least_conn;  # ส่งไป instance ที่มี active connection น้อยสุด
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    # หรือไปอีก server
    # server 10.0.0.5:3000;
}

server {
    location / {
        proxy_pass http://nodejs_app;
    }
}

algorithm ที่เลือกได้:

  • default (round-robin) — สลับ instance ไปเรื่อย
  • least_conn — ส่งไปตัวที่ load น้อยสุด
  • ip_hash — IP เดียวกันไปหา instance เดียวกันเสมอ (sticky session)

Security headers

เพิ่มใน server block:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

ทดสอบที่ securityheaders.com ใส่ domain ดูคะแนน

คำสั่งที่ใช้บ่อย

# ทดสอบ syntax (ทำเสมอก่อน reload)
sudo nginx -t

# reload โดยไม่ตัด connection
sudo systemctl reload nginx

# restart (ตัด connection)
sudo systemctl restart nginx

# ดู error log real-time
sudo tail -f /var/log/nginx/error.log

# ดู access log
sudo tail -f /var/log/nginx/access.log

# ดู process
ps aux | grep nginx

ปัญหาที่เจอบ่อย

502 Bad Gateway = Nginx เชื่อมต่อ backend ไม่ได้

  • ตรวจสอบว่า Node.js รันอยู่: pm2 list
  • ตรวจ port ว่า listen อยู่จริง: ss -tlnp | grep 3000

413 Request Entity Too Large = upload ไฟล์ใหญ่

  • เพิ่ม client_max_body_size ใน server block

504 Gateway Timeout = backend ตอบช้า

  • เพิ่ม proxy_read_timeout
  • หรือดู log backend ว่าทำไมช้า

WebSocket ใช้ไม่ได้ = ขาด upgrade header

  • ตรวจสอบมี proxy_set_header Upgrade $http_upgrade;

สรุป

Nginx เป็น layer ที่ราคาแทบ 0 (ไม่กิน RAM, ไม่กิน CPU) แต่ให้ feature ที่ production grade ครบ — security, performance, scalability

ตั้งครั้งเดียวใช้ได้ตลอด ไม่ต้องไปจ่าย Cloudflare Pro หรือ load balancer ของ cloud

← ดูบทความอื่น