บทความนี้เราจะมาทำ Reverse Proxy ด้วย Nginx กัน
โปรเจกต์ของผม frontend deploy ด้วย Vercel ได้ https://uprodd.vercel.app อันนี้ง่าย จบแล้ว อ่าน deploy FE ส่วน backend deploy บน AWS EC2 แบบ VPS อ่าน deploy BE
สิ่งที่ผมได้คือ http://เลขไอพี:5000 ซึ่งก็คือ API ของผมนั่นเอง ผมต้องเปิดพอร์ต 5000 ให้ frontend เข้ามาเรียกได้ ซึ่งไม่ค่อยแนะนำเท่าไหร่
สิ่งที่ผมจะทำคือให้เรียก API ผ่าน http://เลขไอพี/ แทน ปกติแล้ว / ควรเป็นหน้าเว็บ และ /api ควรเป็น API เผื่ออนาคตจะ deploy frontend ไว้ที่ server เดียวกัน แต่ในบทความนี้ผมจะให้ / เป็นของ API ไปก่อน
ทำไมน่ะเหรอ? ก็เพราะมันทำได้ไงล่ะ hahaha
อันนี้คือจะให้เห็นว่า Nginx สามารถกำหนดให้ชี้ไปไหนก็ได้
1. Login เข้า server
ssh -i "ชื่อไฟล์.pem" ec2-user@เลขไอพี 2. เช็กเวอร์ชัน Linux
cat /etc/os-release | grep PRETTY ของผมเป็น Amazon Linux 2023 ซึ่งใช้ dnf ในการติดตั้งโปรแกรม
3. ติดตั้ง Nginx
sudo dnf install -y nginx Nginx จะติดตั้งตัวโปรแกรมและสร้างโฟลเดอร์ตั้งค่าไว้ที่ /etc/nginx/ ให้เอง
sudo systemctl enable --now nginx เปิดใช้งาน Nginx ทันที และตั้งให้ทำงานเองทุกครั้งที่เปิดเครื่อง
4. สร้างไฟล์ตั้งค่า
sudo tee /etc/nginx/conf.d/upro-api.conf > /dev/null <<'EOF' # จำกัดจำนวน request กันยิงถล่ม limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/s; server { listen 80 default_server; server_name ใส่IPเรา; server_tokens off; # ซ่อนเวอร์ชัน Nginx client_max_body_size 10m; # จำกัดขนาด upload add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "no-referrer" always; # กันบอทที่สแกนหา .env .git location ~ /\. { return 404; } location / { limit_req zone=api_limit burst=40 nodelay; proxy_pass http://127.0.0.1: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; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 10s; proxy_read_timeout 60s; } } EOF แบบง่าย ๆ คำสั่งนี้คือ สร้างไฟล์ upro-api.conf (ตั้งชื่ออะไรก็ได้ ขอให้ลงท้ายด้วย .conf) ไว้ในโฟลเดอร์ /etc/nginx/conf.d/ ที่ Nginx สร้างไว้ให้ โดยเอาข้อความทั้งหมดจนถึงคำว่า EOF ไปเป็นเนื้อหาไฟล์
ให้นึกภาพว่า Nginx เป็น ยามหน้าบ้าน ส่วน API ที่พอร์ต 5000 เป็น เจ้าของบ้านที่อยู่ข้างใน
ข้างล่างนี้คือเนื้อหาไฟล์เดียวกัน แต่ใส่คำอธิบายไว้ทุกบรรทัด เอาไว้อ่านทำความเข้าใจ ตอนสร้างจริงใช้ฉบับข้างบนก็พอ
# ── กฎกลาง: ตั้งโควตาก่อน ── # จำว่าแต่ละ IP ยิงมากี่ครั้ง ให้ได้ไม่เกิน 20 ครั้งต่อวินาที # จองหน่วยความจำ 10 MB ไว้จด (จดได้ราวแสนกว่า IP) limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/s; server { # ยามยืนเฝ้าประตูพอร์ต 80 (HTTP) # default_server = ถ้าคำขอไม่ตรงกับ server อื่น ให้มาที่นี่ listen 80 default_server; # ใช้กับคนที่เข้ามาทาง IP นี้ (ยังไม่มีโดเมน) server_name ใส่IPเรา; # ไม่บอกคนนอกว่าใช้ Nginx เวอร์ชันไหน คนร้ายจะได้หาช่องโหว่ยากขึ้น server_tokens off; # อัปโหลดไฟล์ได้ไม่เกิน 10 MB ต่อครั้ง เกินนี้ไม่รับ client_max_body_size 10m; # ── ส่งคำเตือนความปลอดภัยไปให้เบราว์เซอร์ ── # ห้ามเบราว์เซอร์เดาชนิดไฟล์เอง (กันไฟล์ปลอมตัว) add_header X-Content-Type-Options "nosniff" always; # ห้ามเว็บอื่นเอาหน้าเราไปฝังใน iframe (กันหลอกให้กด) add_header X-Frame-Options "DENY" always; # เวลากดลิงก์ออกไปเว็บอื่น ไม่ต้องบอกว่ามาจากหน้าไหน add_header Referrer-Policy "no-referrer" always; # ── ด่านที่ 1: ไล่บอทที่มาหาไฟล์ลับ ── # ใครขอ path ที่มีจุดนำหน้า เช่น /.env หรือ /.git # ให้ตอบว่า "ไม่มีหน้านี้" (404) location ~ /\. { return 404; } # ── ด่านที่ 2: คำขอทั่วไปทั้งหมด ── location / { # ใช้โควตา 20 ครั้งต่อวินาทีที่ตั้งไว้ข้างบน # ยอมให้พุ่งเกินได้อีก 40 ครั้ง (เช่นตอนเปิดหน้าเว็บที่เรียกหลายอย่างพร้อมกัน) # เกินจากนั้นปฏิเสธทันที limit_req zone=api_limit burst=40 nodelay; # ★ หัวใจของ Reverse Proxy ★ # ส่งคำขอต่อไปให้ API ที่อยู่ในเครื่องเดียวกัน พอร์ต 5000 proxy_pass http://127.0.0.1:5000; # คุยกับ API ด้วย HTTP เวอร์ชัน 1.1 proxy_http_version 1.1; # ── แนบข้อมูลของผู้ใช้จริงไปให้ API ── # (ไม่งั้น API จะเห็นทุกคนเป็น "ยาม" คือ 127.0.0.1 หมด) # ผู้ใช้พิมพ์ชื่อเว็บอะไรเข้ามา proxy_set_header Host $host; # IP จริงของผู้ใช้ proxy_set_header X-Real-IP $remote_addr; # เส้นทาง IP ที่ผ่านมาทั้งหมด proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # ผู้ใช้เข้ามาด้วย http หรือ https proxy_set_header X-Forwarded-Proto $scheme; # ── เวลารอ ── # ต่อหา API ไม่ติดภายใน 10 วินาที ให้ยกเลิก proxy_connect_timeout 10s; # รอ API ตอบได้นานสุด 60 วินาที proxy_read_timeout 60s; } } จะเห็นว่าเรากำหนดได้ทั้งว่าจะชี้ไปทางไหน และตั้งกฎให้คนที่เข้ามาเรียก API ของเราได้ด้วย
5. ตรวจไฟล์ แล้วสั่งให้ Nginx ใช้ค่าใหม่
sudo nginx -t && sudo systemctl reload nginx nginx -t เช็กว่าไฟล์ตั้งค่าเขียนถูกไหม ถ้าผ่านค่อย reload ให้ Nginx อ่านค่าใหม่ โดยไม่ต้องปิดเว็บ
6. ทดสอบ
curl -I http://localhost/ ลองยิงเข้า / ที่เครื่องตัวเอง คำขอจะผ่าน Nginx แล้วถูกส่งต่อไปที่ API พอร์ต 5000
API ของเราใช้งานผ่าน Nginx ได้แล้ว
7. ปิดพอร์ต 5000
ตอนนี้พอร์ต 5000 ที่เคยเปิดไว้ต้องปิดได้แล้ว เพราะทุกคนต้องเข้าผ่านพอร์ต 80/443 เท่านั้น ถึงตอนนี้จะยังไม่ได้จดโดเมนก็ตาม แต่ใน EP นี้อยากให้เห็นการตั้งค่า Nginx แบบง่าย ๆ ก่อน งั้นไปปิดพอร์ตกัน
กดที่ Security Group ID ของเรา

แก้ rule ที่เคยเป็นพอร์ต 5000 ให้เป็นพอร์ต 80 ตามรูป ตอนนี้ที่เปิดไว้คือ
- 22 สำหรับ SSH
- 80 สำหรับ HTTP
- 443 สำหรับ HTTPS (เปิดเผื่อไว้ตอนมีโดเมน)
ปิดแค่ที่ Security Group นะ ตัว API ยังรันอยู่ที่พอร์ต 5000 เหมือนเดิม แค่คนข้างนอกเข้าตรงไม่ได้แล้ว แต่ Nginx ที่อยู่เครื่องเดียวกันยังส่งต่อไปได้ปกติ
ตอนนี้เข้าแบบ :5000 ไม่ได้แล้ว ต้องเรียก http://เลขไอพี/ แทน อย่าลืมไปแก้ URL ของ API ฝั่ง frontend ให้ตัด :5000 ออกด้วย

หน้าเว็บดึงข้อมูลได้ปกติ แค่นี้ก็เรียบร้อยแล้ว ได้โดเมนเมื่อไหร่เดี๋ยวมาทำ HTTPS ต่อนะครับ








