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 ทำได้ไม่ดี:
- SSL/TLS termination — Nginx จัดการ HTTPS เก่ง app ไม่ต้องรู้เรื่อง cert
- Static file — Nginx serve ไฟล์ static เร็วกว่า Node.js หลายสิบเท่า
- Concurrency — Nginx รับ connection พร้อมกันได้เป็นแสน Node.js เธรดเดียวรับได้น้อยกว่า
- Load balancing — กระจาย traffic ไปหลาย instance ได้
- Gzip / Brotli — บีบ response ก่อนส่ง ลด bandwidth
- Rate limiting — กัน abuse ได้ง่าย
- 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