Nginx
Web server & reverse proxy — load balancing, SSL termination, static file serving สำหรับ production
What I Can Do
- ตั้งค่า Nginx เป็น reverse proxy สำหรับ backend services
- Configure SSL/TLS termination ด้วย Let's Encrypt
- ออกแบบ load balancing สำหรับ multiple upstream servers
- Serve static files และ SPA (Single Page Application)
- Optimize performance ด้วย caching, compression, connection tuning
Commands I Use Daily
# ตรวจ config syntax ก่อน reload
nginx -t
# reload config โดยไม่ drop connections
nginx -s reload
# start / stop / restart
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
# ดู error log แบบ follow
tail -f /var/log/nginx/error.log
# ดู access log
tail -f /var/log/nginx/access.log
# ดู nginx version และ modules
nginx -VReverse Proxy
ใช้ Nginx รับ request จาก client แล้ว forward ไป backend service — client ไม่เห็น backend ตรงๆ, Nginx จัดการ SSL, caching, load balancing ให้
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:8080;
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;
}
}proxy_set_header สำคัญ — ถ้าไม่ set backend จะเห็น IP ของ Nginx แทน client จริง
Server Blocks (Virtual Hosts)
หนึ่ง Nginx serve ได้หลาย domains — แยก config เป็น server block ต่อ domain:
/etc/nginx/sites-available/— เก็บ config ทั้งหมด/etc/nginx/sites-enabled/— symlink เฉพาะที่ต้องการ enableserver_namematch domain — Nginx เลือก server block ที่ตรงกับ request
Location Blocks
กำหนด behavior ตาม URL path — match จาก specific ไป general:
location = /health— exact matchlocation ^~ /api/— prefix match (หยุดหา regex)location ~ \.php$— regex match (case-sensitive)location ~* \.(jpg|png)$— regex match (case-insensitive)location /— default prefix match
Load Balancing
กระจาย traffic ไปหลาย backend servers:
upstream backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080 backup;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}- round-robin — default, กระจายเท่ากัน
- least_conn — ส่งไป server ที่มี connections น้อยสุด
- ip_hash — ส่ง IP เดิมไป server เดิม (sticky sessions)
backup— ใช้เมื่อ servers อื่นล่มหมด
SSL/TLS Termination
Nginx จัดการ SSL แทน backend — backend รับแค่ HTTP:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:8080;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}ใช้ Certbot (Let's Encrypt) สำหรับ free SSL certificates — auto renew ด้วย cron
Static File Serving
Serve static files ตรงจาก Nginx — เร็วกว่าผ่าน application server:
server {
listen 80;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}try_files $uri $uri/ /index.html — สำคัญสำหรับ SPA (React, Vue) ที่ใช้ client-side routing
Gzip Compression
ลด response size 60-80% สำหรับ text-based content:
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;Caching
Proxy cache — cache response จาก upstream ลด load:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
}X-Cache-Status header บอก client ว่า response มาจาก cache (HIT) หรือ upstream (MISS)
Rate Limiting
จำกัด requests ป้องกัน abuse:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}rate=10r/s— 10 requests per second per IPburst=20— อนุญาต burst สูงสุด 20 requestsnodelay— process burst ทันทีไม่ queue
WebSocket Proxy
Nginx proxy WebSocket connections ต้อง upgrade header:
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
}proxy_read_timeout ต้องตั้งสูง — ไม่งั้น Nginx จะ timeout idle WebSocket connections
Security Headers
เพิ่ม security headers ที่ Nginx layer:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'" always;Access Control
จำกัด access ตาม IP หรือ basic auth:
location /admin {
allow 10.0.0.0/8;
deny all;
proxy_pass http://backend;
}
location /internal {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://backend;
}Nginx with Docker
# Dockerfile
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY dist/ /usr/share/nginx/html/
EXPOSE 80ใช้ nginx:alpine image — เล็ก (~40MB), มี Nginx พร้อมใช้
Performance Tuning
worker_processes auto;— ใช้ CPU cores ทั้งหมดworker_connections 1024;— connections per workerkeepalive_timeout 65;— reuse connectionssendfile on;— efficient file transfertcp_nopush on;— ส่ง headers + body รวมกันtcp_nodelay on;— ลด latency สำหรับ small packets
ปัญหาที่เจอบ่อย & วิธีแก้
502 Bad Gateway — upstream ไม่ตอบ
Nginx return 502 ทุก request
สาเหตุ: backend service ล่ม, proxy_pass URL ผิด, backend listen คนละ port, Docker network ไม่ตรงกัน
วิธีแก้:
- ตรวจ backend service ว่า running:
curl http://localhost:8080/healthจาก server ตรงๆ - ดู error log:
tail -f /var/log/nginx/error.log— จะบอกว่า connect ไป upstream ไหนแล้ว fail - ตรวจ port ให้ตรง: backend listen port เดียวกับที่
proxy_passชี้ไป - Docker: ตรวจว่า Nginx กับ backend อยู่ network เดียวกัน
413 Request Entity Too Large — upload ไม่ได้
Upload file แล้ว Nginx reject ด้วย 413
สาเหตุ: Nginx มี default client_max_body_size = 1MB — file ที่ใหญ่กว่าจะถูก reject ก่อนถึง backend
วิธีแก้:
- เพิ่ม
client_max_body_size 50m;ใน server หรือ location block - ตั้งให้เหมาะกับ use case:
10mสำหรับ images,100mสำหรับ video uploads - ตั้งที่
httpblock ถ้าต้องการ apply ทั้ง server
SPA routing ไม่ทำงาน — refresh แล้ว 404
เข้า /dashboard ตรงๆ หรือ refresh หน้าได้ 404
สาเหตุ: Nginx หา file /dashboard ไม่เจอเพราะ SPA มีแค่ index.html — ไม่มี try_files fallback
วิธีแก้:
- ใส่
try_files $uri $uri/ /index.html;ใน location block - Nginx จะ try หา file ก่อน ถ้าไม่เจอก็ serve
index.htmlให้ client-side router จัดการ
SSL certificate ไม่ renew — site ล่ม
Certificate หมดอายุแล้ว browser block access
สาเหตุ: Certbot auto-renew ไม่ทำงาน, cron job ไม่ได้ตั้ง, renew สำเร็จแต่ไม่ได้ reload Nginx
วิธีแก้:
- ตรวจ cron:
sudo crontab -lดูว่ามี certbot renew หรือไม่ - ตั้ง cron ให้ renew + reload:
0 0 * * * certbot renew --quiet && nginx -s reload - ทดสอบ renew:
sudo certbot renew --dry-run - ตรวจ certificate expiry:
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
WebSocket ตัดทุก 60 วินาที
WebSocket connection ถูก close หลัง idle ไม่กี่นาที
สาเหตุ: proxy_read_timeout default = 60 วินาที — ถ้าไม่มี data ส่งภายใน 60 วินาที Nginx จะ close connection
วิธีแก้:
- เพิ่ม
proxy_read_timeout 86400s;(24 ชั่วโมง) สำหรับ WebSocket location - ตรวจว่า set
proxy_http_version 1.1;และUpgrade/Connectionheaders ครบ - implement ping/pong ที่ application level เป็น keep-alive เพิ่มเติม
Config syntax ถูกแต่ไม่ทำงานตามที่คิด
nginx -t ผ่านแต่ behavior ไม่ตรง
สาเหตุ: location block priority ไม่ตรงที่คิด (exact > prefix > regex > default), ลืม reload หลังแก้ config, มี config ซ้ำใน sites-enabled หลายไฟล์ conflict กัน
วิธีแก้:
- ใช้
nginx -T(ตัวใหญ่) ดู full merged config ที่ Nginx เห็นจริง - ทดสอบด้วย
curl -iดู response headers ว่ามาจาก location ไหน - ตรวจ
sites-enabledว่ามี server block ซ้ำกันไหม —ls -la /etc/nginx/sites-enabled/ - อย่าลืม
nginx -s reloadหลังแก้ config ทุกครั้ง
Related Skills
- Docker — containerize Nginx + backend services
- Kong Gateway — API gateway ที่ทำงานร่วมกับ Nginx
- Linux — server ที่ run Nginx
- AWS — deploy Nginx บน EC2
- Gin — Go backend หลัง Nginx reverse proxy