
Nginx เป็น Web Server ที่นิยมมากที่สุดสำหรับ VPS เพราะใช้ทรัพยากรน้อยและรองรับ Concurrent Connections ได้สูง บทความนี้รวบรวม Configuration สำหรับ PHP และ WordPress บน Ubuntu ครอบคลุมตั้งแต่ Server Block พื้นฐานจนถึง Gzip, Cache Header และการตั้ง SSL ด้วย Let's Encrypt
ติดตั้ง Nginx และ PHP-FPM
sudo apt update
sudo apt install -y nginx php8.3-fpm php8.3-mysql php8.3-curl \
php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-redis
# เปิดใช้งาน
sudo systemctl enable nginx php8.3-fpm
sudo systemctl start nginx php8.3-fpm
Server Block สำหรับ PHP ทั่วไป
sudo nano /etc/nginx/sites-available/mysite.com
server {
listen 80;
server_name mysite.com www.mysite.com;
root /var/www/mysite.com/public;
index index.php index.html;
# Access & Error log
access_log /var/log/nginx/mysite.com.access.log;
error_log /var/log/nginx/mysite.com.error.log;
# PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}
# Deny .htaccess
location ~ /\.ht { deny all; }
# Static files cache
location ~* \.(jpg|jpeg|png|webp|gif|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
sudo ln -s /etc/nginx/sites-available/mysite.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Server Block สำหรับ WordPress
server {
listen 80;
server_name wordpress.example.com;
root /var/www/wordpress;
index index.php;
# WordPress Permalink support
location / {
try_files $uri $uri/ /index.php?$args;
}
# Deny sensitive files
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
location ~* \.(txt|log|conf|bak)$ { deny all; }
# PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
# Static files cache
location ~* \.(css|js|jpg|jpeg|png|webp|gif|ico|svg|woff2|ttf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
log_not_found off;
}
}
ทำความเข้าใจ Server Block ทีละบรรทัด
หัวใจของการตั้งค่า Nginx บน VPS คือ Server Block (เทียบได้กับ VirtualHost ของ Apache) แต่ละ Directive ในบล็อกนี้ทำหน้าที่เฉพาะตัว การเข้าใจว่าแต่ละบรรทัดทำอะไรช่วยให้คุณแก้ปัญหาได้เร็วและปรับแต่งได้ตรงจุด ไม่ใช่แค่ก๊อปวางแล้วหวังให้มันทำงาน ต่อไปนี้คือความหมายของ Directive หลักที่ใช้กับเว็บ PHP และ WordPress
| Directive | หน้าที่ |
|---|---|
listen 80; | บอกให้ Nginx รับ Request ที่พอร์ต 80 (HTTP) — Certbot จะเพิ่มพอร์ต 443 (HTTPS) ให้ภายหลัง |
server_name | ระบุโดเมนที่บล็อกนี้รับผิดชอบ ใส่ได้ทั้ง domain หลักและ www หรือหลายโดเมนคั่นด้วยช่องว่าง |
root | โฟลเดอร์จริงบนดิสก์ที่เก็บไฟล์เว็บ เช่น /var/www/mysite.com/public |
index | ไฟล์เริ่มต้นเมื่อเรียกโฟลเดอร์ — สำหรับ PHP ต้องมี index.php นำหน้าเสมอ |
try_files | ลองหาไฟล์ตามลำดับ ถ้าไม่เจอให้ส่งต่อไป index.php — เป็นหัวใจของ Pretty URL |
fastcgi_pass | ส่งไฟล์ .php ไปประมวลผลที่ PHP-FPM ผ่าน Unix socket |
เมื่อมี Request เข้ามา Nginx จะหาว่า server_name ตรงกับบล็อกไหน จากนั้นใช้ root เป็นฐานในการหาไฟล์ ถ้าเป็นไฟล์ Static (รูป, CSS, JS) จะส่งกลับตรง ๆ แต่ถ้าเป็น .php จะถูกส่งต่อไป PHP-FPM ผ่าน fastcgi_pass แล้วรับผลลัพธ์กลับมาส่งให้ผู้ใช้ การแยกหน้าที่แบบนี้เองที่ทำให้ Nginx เสิร์ฟไฟล์ Static ได้เร็วมากโดยไม่ต้องปลุก PHP ทุกครั้ง
ตั้งค่า WordPress Permalink และ Pretty URL บน Nginx
ปัญหาที่พบบ่อยที่สุดเมื่อย้าย WordPress มาอยู่บน Nginx คือ หน้าแรกเปิดได้แต่หน้าอื่นขึ้น 404 ทั้งหมด สาเหตุคือ Nginx ไม่มี .htaccess เหมือน Apache จึงไม่รู้จัก Permalink แบบ "Post name" (เช่น /category/my-post/) เราต้องบอก Nginx เองด้วย try_files ให้ส่ง Request ที่หาไฟล์จริงไม่เจอไปยัง index.php เพื่อให้ WordPress จัดการ Routing เอง
# บล็อกหลักที่ทำให้ Permalink ทำงาน
location / {
try_files $uri $uri/ /index.php?$args;
}
บรรทัดนี้หมายความว่า: ลองหาไฟล์ตรงตาม URI ก่อน ($uri) ถ้าไม่เจอลองเป็นโฟลเดอร์ ($uri/) ถ้ายังไม่เจออีกให้ส่งทุกอย่างไป index.php พร้อม Query string เดิม (?$args) จากนั้นเข้าไปที่ WordPress > Settings > Permalinks เลือกรูปแบบ "Post name" แล้วกด Save ได้เลย ไม่ต้องสร้างไฟล์ rewrite อื่น
หากใช้ WordPress แบบ Multisite (Subdirectory) ต้องเพิ่ม Rule พิเศษให้รองรับโครงสร้างไซต์ย่อย:
# สำหรับ WordPress Multisite (subdirectory)
if (!-e $request_filename) {
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
rewrite ^(/[^/]+)?(/wp-.*) $2 last;
rewrite ^(/[^/]+)?(/.*\.php) $2 last;
}
หลังแก้ Config ทุกครั้งอย่าลืมรัน sudo nginx -t เพื่อตรวจ Syntax ก่อน Reload เสมอ มิฉะนั้นถ้า Config ผิดแล้ว Reload ไปทั้งเว็บจะล่ม
ตั้งค่า Gzip Compression
เพิ่มใน /etc/nginx/nginx.conf ในบล็อก http { }:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
image/svg+xml
font/woff2;
การเปิด Gzip ช่วยลดขนาดไฟล์ HTML, CSS และ JavaScript ลงได้ 60-80% ก่อนส่งถึงเบราว์เซอร์ ทำให้หน้าเว็บโหลดเร็วขึ้นชัดเจนโดยเฉพาะบนเครือข่ายมือถือและช่วยให้คะแนน PageSpeed ดีขึ้นด้วย ค่า gzip_comp_level 6 เป็นจุดสมดุลที่ดีระหว่างอัตราการบีบอัดกับการใช้ CPU — ตั้งสูงเกิน 6 จะกิน CPU เพิ่มแต่ลดขนาดไฟล์ได้น้อยลงมาก ส่วน gzip_min_length 256 ป้องกันไม่ให้ Nginx เสียเวลาบีบไฟล์เล็ก ๆ ที่ไม่คุ้ม ข้อควรระวังคือ Gzip ไม่ควรเปิดกับไฟล์รูปภาพอย่าง JPG หรือ PNG เพราะถูกบีบอัดมาแล้ว การบีบซ้ำจะกินทรัพยากรเปล่าโดยไม่ได้ลดขนาดเพิ่ม จึงควรระบุเฉพาะ Content-Type ที่เป็นข้อความตามตัวอย่างข้างต้นเท่านั้น
เปิด Browser Cache และตั้ง client_max_body_size
นอกจาก Gzip แล้ว สองสิ่งที่ขาดไม่ได้บน VPS ที่รัน WordPress คือ Cache Header สำหรับไฟล์ Static และ การขยายขนาดไฟล์อัปโหลดสูงสุด โดย default Nginx จำกัด Body ของ Request ไว้แค่ 1MB ทำให้อัปโหลดรูปหรือปลั๊กอินใหญ่ ๆ ไม่ได้และขึ้น error 413 Request Entity Too Large
# ตั้งใน server { } หรือ http { }
# ขยายขนาดไฟล์อัปโหลดสูงสุดเป็น 64MB
client_max_body_size 64M;
# Browser cache สำหรับไฟล์ static (cache ฝั่งผู้ใช้ 1 ปี)
location ~* \.(css|js|jpg|jpeg|png|webp|gif|ico|svg|woff2|ttf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
log_not_found off;
}
ค่า expires 1y คู่กับ Cache-Control "public, immutable" บอกเบราว์เซอร์ให้เก็บไฟล์ Static ไว้ในเครื่องนาน 1 ปี ผู้ใช้ที่กลับมาเยี่ยมซ้ำจะไม่ต้องโหลดไฟล์เดิมใหม่ ลดภาระเซิร์ฟเวอร์และทำให้หน้าเว็บเด้งขึ้นทันที ถ้าใช้ WordPress ควรตั้ง client_max_body_size ให้สอดคล้องกับ upload_max_filesize และ post_max_size ใน php.ini ด้วย ไม่งั้นค่าที่เล็กกว่าจะเป็นตัวจำกัดจริง
ข้อควรรู้: ถ้าต้องการ Cache แบบเต็มหน้า (Full-Page Cache) เพื่อให้ WordPress เร็วระดับ Static สามารถใช้ FastCGI Cache ของ Nginx ร่วมกับ fastcgi_cache_path ได้ แต่สำหรับเว็บส่วนใหญ่ Browser Cache + ปลั๊กอิน Cache อย่าง WP Super Cache ก็เพียงพอแล้ว
เพิ่ม SSL ด้วย Let's Encrypt (Certbot)
# ติดตั้ง certbot
sudo apt install -y certbot python3-certbot-nginx
# ขอ Certificate
sudo certbot --nginx -d mysite.com -d www.mysite.com
# ตั้ง Auto-renewal
sudo systemctl status certbot.timer
Certbot จะแก้ไข Nginx Config อัตโนมัติเพิ่ม SSL directives และ Redirect HTTP → HTTPS
ตรวจสอบ SSL Config: หลังติดตั้ง SSL ให้รัน sudo nginx -t เพื่อตรวจ Syntax แล้วทดสอบที่ SSL Checker เพื่อดูว่า Certificate ถูกต้อง
ตั้งค่า Security Headers
เพิ่มใน Server Block เพื่อเพิ่มความปลอดภัยและ Score จาก Security Scanner:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
ปรับ PHP-FPM Pool สำหรับ Performance
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
; ปรับตาม RAM ของ VPS
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500
sudo systemctl restart php8.3-fpm
Rule of Thumb: ตั้ง pm.max_children ประมาณ (RAM ทั้งหมด - 512MB สำหรับ OS) / RAM ต่อ PHP Process โดยทั่วไป PHP-FPM ใช้ RAM ต่อ Process ประมาณ 30-50MB ดังนั้นบน VPS 2GB ควรตั้งได้ประมาณ 20-30 children
ทดสอบ Config ด้วย nginx -t และ Reload + ปัญหาที่พบบ่อย
ก่อน Reload Nginx ทุกครั้ง ต้องทดสอบ Config ก่อนเสมอ ด้วยคำสั่ง nginx -t ซึ่งจะตรวจ Syntax ทั้งหมดโดยไม่กระทบเว็บที่กำลังรันอยู่ ถ้าผ่านจะขึ้นข้อความ syntax is ok และ test is successful จากนั้นค่อย Reload ซึ่งต่างจาก Restart ตรงที่ Reload จะโหลด Config ใหม่โดยไม่ตัดการเชื่อมต่อที่กำลังทำงานอยู่ ทำให้เว็บไม่ล่มแม้แต่วินาทีเดียว
# 1. ทดสอบ syntax ของ config ทั้งหมด
sudo nginx -t
# 2. ถ้าผ่าน reload โดยไม่ตัด connection
sudo systemctl reload nginx
# 3. ดู error log แบบ real-time เมื่อมีปัญหา
sudo tail -f /var/log/nginx/error.log
# 4. เช็คสถานะ service
sudo systemctl status nginx php8.3-fpm
เมื่อตั้งค่า Nginx บน VPS จริงมักเจอปัญหาซ้ำ ๆ ไม่กี่อย่าง ตารางด้านล่างรวบรวม Error ที่พบบ่อยพร้อมวิธีแก้ที่ตรงจุด:
| อาการ / Error | สาเหตุและวิธีแก้ |
|---|---|
| 502 Bad Gateway | PHP-FPM ไม่ทำงานหรือ path ของ socket ผิด เช็คว่า fastcgi_pass ตรงกับ socket จริง (php8.3-fpm.sock) และรัน systemctl status php8.3-fpm |
| 404 ทุกหน้ายกเว้นหน้าแรก | ขาด try_files $uri $uri/ /index.php?$args; ในบล็อก location / ของ WordPress |
| 413 Request Entity Too Large | ไฟล์อัปโหลดใหญ่เกิน default 1MB เพิ่ม client_max_body_size 64M; |
| 403 Forbidden | สิทธิ์ไฟล์ผิด ตั้ง owner เป็น www-data และ permission โฟลเดอร์ 755 ไฟล์ 644 |
| ไฟล์ .php ดาวน์โหลดแทนรัน | ขาดบล็อก location ~ \.php$ หรือ PHP-FPM ไม่ได้ติดตั้ง ตรวจ config และติดตั้ง php-fpm |
หลักการแก้ปัญหาที่ดีที่สุดคือ ดู Error Log เป็นอันดับแรกเสมอ เพราะ Nginx จะบันทึกสาเหตุที่แท้จริงไว้ใน /var/log/nginx/error.log และ PHP-FPM ใน /var/log/php8.3-fpm.log การคาดเดาโดยไม่ดู Log มักทำให้เสียเวลา การมี Full Root Access บน VPS ทำให้คุณเข้าถึง Log เหล่านี้ได้เต็มที่ ต่างจาก Shared Hosting ที่มักถูกจำกัด
คำถามที่พบบ่อย (FAQ)
Nginx กับ Apache ต่างกันอย่างไร ควรใช้ตัวไหนบน VPS?
Nginx ใช้สถาปัตยกรรมแบบ Event-driven จัดการ Connection จำนวนมากพร้อมกันได้โดยใช้ RAM น้อย จึงเหมาะกับ VPS ที่ทรัพยากรจำกัดและเว็บที่มีทราฟฟิกสูง ส่วน Apache ยืดหยุ่นเรื่อง .htaccess และ Module มากกว่า แต่กิน RAM มากกว่าเมื่อ Connection เยอะ สำหรับ VPS ที่รัน PHP/WordPress เราแนะนำ Nginx + PHP-FPM เพราะให้ Performance ต่อ RAM ที่ดีกว่า
ต้องติดตั้ง PHP-FPM แยกหรือไม่ ในเมื่อ Nginx รัน PHP ไม่ได้เอง?
ใช่ Nginx ไม่ได้ประมวลผล PHP ในตัวเองเหมือนที่ Apache ทำได้ผ่าน mod_php จึงต้องติดตั้ง php-fpm แยกแล้วให้ Nginx ส่งไฟล์ .php ไปประมวลผลผ่าน fastcgi_pass วิธีนี้กลับเป็นข้อดี เพราะแยกหน้าที่ชัดเจน ปรับ Pool ของ PHP-FPM ได้อิสระและจัดการ Resource ได้ดีกว่า
ทำไมแก้ Config แล้วเว็บไม่เปลี่ยน?
สาเหตุที่พบบ่อยคือยังไม่ได้ Reload Nginx หลังแก้ไฟล์ ต้องรัน sudo nginx -t && sudo systemctl reload nginx เสมอ อีกกรณีคือเบราว์เซอร์ Cache ไฟล์เก่าไว้ ลองเปิดแบบ Incognito หรือล้าง Cache ดู และถ้าใช้ปลั๊กอิน Cache ใน WordPress อย่าลืม Purge Cache ด้วย
VPS ขนาดเท่าไรถึงพอสำหรับ WordPress + Nginx?
เว็บ WordPress ทั่วไปที่มีทราฟฟิกปานกลางสามารถรันได้สบายบน VPS ขนาด 2GB RAM ขึ้นไป โดย Nginx + PHP-FPM ใช้ RAM อย่างมีประสิทธิภาพ ถ้าเพิ่ง เริ่มต้นหรือเป็นเว็บเล็ก VPS Ubuntu ของ AsiaGB เริ่มต้น 500 บาท/เดือน พร้อม Full Root Access ก็เพียงพอสำหรับติดตั้ง Nginx, PHP-FPM และ WordPress ครบชุด
ต้องการ VPS ที่ตั้งค่า Nginx ได้เต็มรูปแบบ?
VPS Linux Ubuntu เริ่มต้น 500 บาท/เดือน Full Root Access ตั้งค่า Nginx, PHP-FPM, WordPress และทุก Stack ที่ต้องการได้อิสระ
ดูแพ็กเกจ VPS