PHP-FPM คืออะไร | ติดตั้งและตั้งค่า PHP-FPM
PHP-FPM คือตัวจัดการโปรเซส FastCGI ที่ให้โปรเซสเวิร์กเกอร์ซึ่งเปิดรอไว้ล่วงหน้ารับคำขอ PHP ที่เว็บเซิร์ฟเวอร์ส่งต่อมาแล้วประมวลผลให้ คู่มือนี้ตรวจบนเซิร์ฟเวอร์ AlmaLinux 9 ที่รัน Apache ว่าติดตั้งไว้หรือยัง และตั้งค่าพูลกับซ็อกเก็ตแยกตามไซต์อย่างไร จากนั้นต่อไปถึงการทดสอบการตั้งค่าและการตรวจสถานะด้วยผลลัพธ์จริง
Apache สั่งรัน PHP โดยตรงผ่าน mod_php ได้เช่นกัน แต่ถ้าส่งต่อให้ PHP-FPM เว็บเซิร์ฟเวอร์กับ PHP จะแยกจากกัน ส่วน Nginx รัน PHP โดยตรงไม่ได้ จึงส่งคำขอต่อให้โปรเซส FastCGI อย่าง PHP-FPM ด้วยเหตุนี้ PHP-FPM ตัวเดียวจึงต่อกับ Apache หรือ Nginx ก็ได้ การตั้งค่าพูลและโครงสร้างซ็อกเก็ตด้านล่างใช้ได้เหมือนเดิมเมื่อคุณเชื่อม PHP-FPM กับ Nginx
1️⃣ PHP-FPM คืออะไร: ความต่างระหว่าง CGI กับ FastCGI
CGI (Common Gateway Interface) เป็นวิธีมาตรฐานที่เว็บเซิร์ฟเวอร์ใช้รันโปรแกรมภายนอกเพื่อสร้างเนื้อหาไดนามิก และจะเริ่มโปรแกรมใหม่ทุกครั้งที่มีคำขอเข้ามา ต้นทุนของการสร้างและลบโปรเซสทุกคำขอสะสมไปเรื่อย ๆ ยิ่งมีผู้เข้าใช้มากเซิร์ฟเวอร์ก็ยิ่งตอบสนองช้าลง
FastCGI ตัดต้นทุนนี้ด้วยการเปิดโปรแกรมรอไว้ล่วงหน้าแล้วประมวลผลคำขอต่อเนื่องกันไป เหมือนความต่างระหว่างการเปิดปิดคอมพิวเตอร์ทุกครั้งที่ใช้ กับการใช้คอมพิวเตอร์ที่เปิดค้างไว้ได้ทันที PHP-FPM (FastCGI Process Manager) คือตัวจัดการที่รัน PHP ผ่าน FastCGI และรวมอยู่ใน PHP ตั้งแต่เวอร์ชัน 5.3.3
PHP-FPM เปิดเวิร์กเกอร์ตามจำนวนที่กำหนดรอไว้ล่วงหน้าในแต่ละพูล ซึ่งเป็นกลุ่มของเวิร์กเกอร์ เวิร์กเกอร์ที่ว่างจะรับคำขอที่เว็บเซิร์ฟเวอร์ส่งผ่านซ็อกเก็ต ประมวลผล แล้วรอคำขอถัดไป ไฟล์สแตติกอย่างรูปภาพและ CSS เว็บเซิร์ฟเวอร์ตอบเอง มีเพียงไฟล์ PHP เท่านั้นที่ส่งต่อให้ PHP-FPM สิ่งที่ต่างกันมีแค่วิธีที่เว็บเซิร์ฟเวอร์ส่งคำขอเข้าซ็อกเก็ต โดย Apache ใช้โมดูล mod_proxy_fcgi ส่วน Nginx ใช้การตั้งค่า fastcgi_pass
2️⃣ ติดตั้ง PHP-FPM: ตรวจแพ็กเกจและติดตั้งด้วย dnf
ถ้าคุณติดตั้ง PHP ด้วย dnf บนเซิร์ฟเวอร์ตระกูล RHEL แพ็กเกจ php-fpm จะถูกติดตั้งมาด้วยแล้ว ให้ตรวจด้วย rpm ก่อนว่าติดตั้งไว้หรือไม่ ขั้นตอนติดตั้ง PHP เหมือนกับ การติดตั้ง APM บน Rocky Linux ทุกประการ
rpm -qa | grep php-fpmphp-fpm-8.3.36-1.module_php.8.3.el9.remi.x86_64ถ้าผลลัพธ์ว่างเปล่า แปลว่ายังไม่ได้ติดตั้ง ให้ติดตั้งด้วย dnf
dnf -y install php-fpmเมื่อติดตั้งเสร็จ ให้ตรวจอีกครั้งด้วยคำสั่ง rpm เดิมว่าชื่อแพ็กเกจแสดงออกมาหรือไม่
3️⃣ ตั้งค่า PHP-FPM: พูล www.conf ซ็อกเก็ต และโหมดสแตติกกับไดนามิก
ไฟล์ตั้งค่ามีสองไฟล์ คือการตั้งค่าโดยรวม [/etc/php-fpm.conf] และการตั้งค่าพูล [/etc/php-fpm.d/www.conf] บรรทัดที่ควรดูก่อนในพูลเริ่มต้น www.conf คือ listen กับ pm และค่าหลังติดตั้งใหม่ ๆ เป็นดังนี้
grep -E '^(listen|pm) ' /etc/php-fpm.d/www.conflisten = /run/php-fpm/www.sock
pm = dynamiclisten คือจุดที่เว็บเซิร์ฟเวอร์ส่งคำขอเข้ามา และค่าเริ่มต้นของเวอร์ชัน 8.3 คือยูนิกซ์ซ็อกเก็ต [/run/php-fpm/www.sock] ค่าเริ่มต้นของเวอร์ชันเก่าอย่าง [127.0.0.1:9000] รับคำขอผ่านพอร์ต TCP ภายในเซิร์ฟเวอร์เดียวกัน ซ็อกเก็ตเบากว่าเพราะไม่ต้องผ่านขั้นตอนเชื่อมต่อพอร์ต และใช้ listen.owner กับ listen.group จำกัดการเข้าถึงได้เหมือนสิทธิ์ของไฟล์
🔲 ตั้งค่าโหมดสแตติกและโหมดไดนามิก
pm คือวิธีเปิดเวิร์กเกอร์ และกำหนดเป็นหนึ่งในสามแบบ คือ static, dynamic หรือ ondemand โหมดสแตติกจะเปิดเวิร์กเกอร์ตามจำนวนที่เขียนไว้ใน pm.max_children ค้างไว้ตลอด และการตั้งค่าด้านล่างคงเวิร์กเกอร์ไว้ 100 ตัว
pm = static
pm.max_children = 100โหมดไดนามิกเป็นค่าเริ่มต้น และเพิ่มลดจำนวนเวิร์กเกอร์ตามปริมาณคำขอ การตั้งค่าด้านล่างเปิดไว้ 12 ตัวตอนเริ่ม คงเวิร์กเกอร์ที่ว่างไว้ระหว่าง 6 ถึง 18 ตัว และเพิ่มได้สูงสุด 120 ตัว
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18โหมด ondemand เปิดเวิร์กเกอร์เฉพาะตอนที่มีคำขอเข้ามา และปิดเมื่อพ้น pm.process_idle_timeout จึงเหมาะกับไซต์ที่มีผู้เข้าน้อย และไม่เหมาะกับไซต์ที่มีผู้เข้าบ่อย
ทั้งสามโหมดต่างกันที่จังหวะการเปิดเวิร์กเกอร์และวิธีเพิ่มลดจำนวน
| โหมด | วิธีเปิดเวิร์กเกอร์ | ไซต์ที่เหมาะ |
|---|---|---|
| static (สแตติก) | เปิดเวิร์กเกอร์ตามจำนวนที่เขียนไว้ใน pm.max_children ค้างไว้ตลอด | ไซต์ที่มีผู้เข้าบ่อย |
| dynamic (ไดนามิก) | ค่าเริ่มต้น · เพิ่มลดภายใน pm.start_servers, pm.min_spare_servers และ pm.max_spare_servers ตามปริมาณคำขอ | ไซต์ที่ปริมาณผู้เข้าขึ้นลง |
| ondemand | เปิดเฉพาะตอนที่มีคำขอเข้ามา และปิดเมื่อพ้น pm.process_idle_timeout | ไซต์ที่มีผู้เข้าน้อย |
ค่า max_children กำหนดโดยนำหน่วยความจำของเซิร์ฟเวอร์ไปหารด้วยหน่วยความจำที่เวิร์กเกอร์หนึ่งตัวใช้ แม้คำเตือนว่าถึง [max_children] จะสะสมก็อย่าเพิ่งปรับขึ้นทันที ให้ ดูจากล็อกก่อนว่าคำขอแบบใดทำให้เวิร์กเกอร์เต็ม.
หน่วยความจำและขีดจำกัดการอัปโหลดกำหนดใน php.ini ซึ่งเป็นการตั้งค่าโดยรวมของ PHP และปรับพร้อมกับจำนวนเวิร์กเกอร์ให้เหมาะกับไซต์ที่คุณดูแล
memory_limit = 1024M
post_max_size = 128M
upload_max_filesize = 128Mค่าทั้งสามคือเพดานหน่วยความจำที่สคริปต์ PHP หนึ่งตัวใช้ได้ กับขนาดไฟล์ที่อัปโหลดได้ในครั้งเดียว และจะมีผลหลังรีสตาร์ต PHP-FPM เท่านั้น
🔲 ตั้งค่าพูลแยกตามบัญชีของไซต์
ถ้ามีหลายไซต์ อย่าใช้ www.conf ไฟล์เดียวร่วมกัน ให้สร้างไฟล์พูลแยกตามบัญชีแล้วแยกบัญชีที่ใช้รันกับซ็อกเก็ตออกจากกัน PHP ของไซต์หนึ่งจะอ่านไฟล์ของอีกบัญชีไม่ได้ และจำนวนเวิร์กเกอร์ก็กำหนดแยกตามไซต์
vi /etc/php-fpm.d/siteuser.confในไฟล์ให้เขียนชื่อพูล บัญชีที่ใช้รัน เส้นทางของซ็อกเก็ต และจำนวนเวิร์กเกอร์
[siteuser]
user = siteuser
group = nobody
listen = /run/php-fpm/siteuser.sock
listen.owner = siteuser
listen.group = nobody
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
chdir = /home/siteuser/wwwlisten.owner กับ listen.group คือเจ้าของและกลุ่มของไฟล์ซ็อกเก็ต และ PHP-FPM สร้างซ็อกเก็ตด้วยค่านี้ตอนเริ่มทำงาน ถ้าเว็บเซิร์ฟเวอร์รันด้วยบัญชี nobody ให้ใส่ listen.group เป็น nobody ถ้าเป็นบัญชี apache ให้ใส่ apache เพื่อให้เว็บเซิร์ฟเวอร์เปิดซ็อกเก็ตได้
listen.owner = siteuser
listen.group = nobody
listen.mode = 0660สามบรรทัดนี้ต้องมีในไฟล์พูลทุกไฟล์ และหลังเปลี่ยนค่าต้องรีสตาร์ตเพื่อให้ซ็อกเก็ตถูกสร้างใหม่ด้วยสิทธิ์ใหม่
🔲 ตั้งค่า slowlog
slowlog คือไฟล์ที่บันทึกตำแหน่งที่กำลังรันของคำขอที่ใช้เวลานานกว่า request_slowlog_timeout และถ้าค่าเป็น 0 จะไม่บันทึก เมื่อต้องการหาสาเหตุของคำขอที่ช้า ให้เปิดโดยกำหนดเป็นหน่วยวินาที เช่น 3s
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 0ไฟล์ที่บันทึกไว้จะเก็บเส้นทางสคริปต์ของคำขอที่ช้าและฟังก์ชันที่รันอยู่ในขณะนั้น จึงตรวจได้ว่าปลั๊กอินหรือโค้ดตัวไหนที่ใช้เวลานาน
4️⃣ เชื่อมกับ Apache: ตั้งค่า VirtualHost และสิทธิ์ของซ็อกเก็ต
Apache ส่งคำขอไฟล์ PHP เข้าซ็อกเก็ตของพูลด้วยโมดูล mod_proxy_fcgi ให้ใส่บรรทัด SetHandler หนึ่งบรรทัดใน FilesMatch ภายใน VirtualHost และเขียนซ็อกเก็ตของบัญชีนั้นสำหรับแต่ละไซต์
# หนึ่ง VirtualHost ต่อหนึ่งบัญชีไซต์ · ใส่ซ็อกเก็ตของบัญชีนั้นใน SetHandler (ใช้ ProxyPassMatch เชื่อมแทน SetHandler ก็ได้)
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /home/siteuser/www
<Directory /home/siteuser/www>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/siteuser.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>DocumentRoot กับ Directory คือเว็บรูทของบัญชีนั้น และ -Indexes ใน Options ป้องกันไม่ให้รายการโฟลเดอร์ปรากฏในเบราว์เซอร์
🔲 ตั้งค่าสิทธิ์ของซ็อกเก็ต
เมื่อเริ่มพูล ซ็อกเก็ตจะถูกสร้างด้วยค่า listen.owner, listen.group และ listen.mode และให้ตรวจด้วย ls ว่าสิทธิ์ถูกต้อง
ls -l /run/php-fpm/รวม 4
srw-rw---- 1 siteuser_a nobody 0 ต.ค. 22 23:34 siteuser_a.sock
-rw-r--r-- 1 root root 7 ต.ค. 26 03:00 php-fpm.pid
srw-rw---- 1 siteuser_b nobody 0 ต.ค. 22 23:34 siteuser_b.sock
srw-rw----+ 1 root root 0 ต.ค. 22 23:34 www.sockถ้าสิทธิ์ไม่ตรงและเว็บเซิร์ฟเวอร์เปิดซ็อกเก็ตไม่ได้ ผู้เข้าชมจะเจอข้อผิดพลาด 503 หากต้องการแก้ทันทีโดยไม่รีสตาร์ต ให้กำหนดเจ้าของและสิทธิ์ด้วย chown และ chmod
นี่คือไวยากรณ์ปัจจุบันที่คั่นผู้ใช้กับกลุ่มด้วยเครื่องหมายทวิภาค
chown siteuser:nobody /run/php-fpm/siteuser.sockหลังเปลี่ยนเจ้าของแล้ว ให้ปรับสิทธิ์เป็น 660
chmod 660 /run/php-fpm/siteuser.sockนี่คือไวยากรณ์เก่าที่คั่นผู้ใช้กับกลุ่มด้วยจุด และ chown บน AlmaLinux 9 ก็ยังรันได้ตามเดิม
chown siteuser.nobody /run/php-fpm/siteuser.sockหลังเปลี่ยนเจ้าของแล้ว ให้ปรับสิทธิ์เป็น 660
chmod 660 /run/php-fpm/siteuser.sockผลลัพธ์ของสองไวยากรณ์เหมือนกัน ใช้แบบไหนเจ้าของซ็อกเก็ตก็เปลี่ยนเป็น siteuser และกลุ่มเปลี่ยนเป็น nobody
🔲 เชื่อมกับ Nginx: ตั้งค่า fastcgi_pass
ใน Nginx location ของไฟล์ PHP ภายในบล็อก server ส่งคำขอเข้าซ็อกเก็ตของพูลเดียวกันด้วย fastcgi_pass
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm/siteuser.sock;
}ถ้า Nginx รันด้วยบัญชี nginx ต้องเขียน listen.group ในไฟล์พูลเป็น nginx จึงจะเปิดซ็อกเก็ตได้
5️⃣ ทดสอบการตั้งค่าและรีสตาร์ต: php-fpm -t กับ systemctl
หลังเปลี่ยนการตั้งค่า อย่าเพิ่งรีสตาร์ตทันที ให้ตรวจไวยากรณ์ด้วย php-fpm -t ก่อน ถ้าไฟล์พูลมีคำพิมพ์ผิด PHP-FPM ทั้งตัวจะล้มตอนรีสตาร์ตและทุกไซต์จะได้ 503
php-fpm -t[26-Oct-2026 17:33:45] NOTICE: configuration file /etc/php-fpm.conf test is successfulถ้าผ่านการตรวจ จะแสดงข้อความ [test is successful] พร้อมเส้นทางของไฟล์ตั้งค่า จากนั้นจึงนำการเปลี่ยนแปลงไปใช้กับ PHP-FPM การเปลี่ยนที่ต้องสร้างซ็อกเก็ตใหม่ เช่น เส้นทางซ็อกเก็ตหรือ listen.owner ให้ใช้ restart ถ้าบนเซิร์ฟเวอร์ที่กำลังใช้งานคุณเปลี่ยนแค่ค่าอย่างจำนวนเวิร์กเกอร์ ให้ใช้ reload
systemctl restart php-fpmถ้าแก้ VirtualHost ให้รีสตาร์ต Apache ด้วย
systemctl restart httpdลงทะเบียนด้วย enable เพื่อให้รันอัตโนมัติเมื่อเปิดเซิร์ฟเวอร์ใหม่
systemctl enable php-fpmตรวจว่าลงทะเบียนแล้วหรือไม่ด้วย is-enabled
systemctl is-enabled php-fpmenabledตรวจด้วย status ว่ามีเวิร์กเกอร์ทำงานอยู่ในแต่ละพูล
systemctl status php-fpm● php-fpm.service - The PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; preset: disabled)
Active: active (running) since x
Process: 3934033 ExecReload=/bin/kill -USR2 $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1333314 (php-fpm)
Status: "Processes active: 4, idle: 21, Requests: x, slow: 0, Traffic: x"
Tasks: x
Memory: x
CPU: x
CGroup: /system.slice/php-fpm.service
├─ 41920 "php-fpm: pool siteuser_a"
├─ 94143 "php-fpm: pool siteuser_b"
├─1333314 "php-fpm: master process (/etc/php-fpm.conf)"
├─3934078 "php-fpm: pool www"
└─4009016 "php-fpm: pool siteuser_a"
ต.ค. 26 03:00:01 server.example.com systemd[1]: Reloading The PHP FastCGI Process Manager...
ต.ค. 26 03:00:01 server.example.com systemd[1]: Reloaded The PHP FastCGI Process Manager.ในบรรทัด Status ค่า active กับ idle คือเวิร์กเกอร์ที่กำลังประมวลผลคำขออยู่ตอนนี้และเวิร์กเกอร์ที่ว่าง ส่วน CGroup แสดงรายการเวิร์กเกอร์แยกตามชื่อพูล ชื่อโฮสต์และชื่อพูลในผลลัพธ์ถูกเปลี่ยนเป็นค่าตัวอย่าง
🔢 FAQ & เนื้อหาแนะนำ
แคช
แคช: ความหมายและทุกด้านที่ใช้การแคช
อธิบายแยกตามด้านว่าทำไมคำขอที่เจอแคชจึงไม่ไปถึงเวิร์กเกอร์ PHP-FPM
เซิร์ฟเวอร์แคช
ติดตั้งและตั้งค่า Varnish Cache บน Apache และ Nginx
ขั้นตอนติดตั้งที่วางเซิร์ฟเวอร์แคชไว้หน้าเว็บเซิร์ฟเวอร์เพื่อลดคำขอ PHP เอง
Linux
คำสั่ง Linux: 15 หมวดหมู่
ตารางที่จัดคำสั่งเป็น 15 หมวด รวมถึง rpm, grep และ systemctl ที่ใช้ในบทความนี้
ℹ️ ประกาศเรื่องลิงก์แอฟฟิลิเอต
เนื้อหาของเว็บไซต์นี้มีลิงก์แอฟฟิลิเอต หากผู้เข้าชมซื้อสินค้าหรือบริการผ่านลิงก์เหล่านี้ เว็บไซต์นี้จะได้รับค่าคอมมิชชันจากผู้ขาย ในกระบวนการนี้ ราคาที่ผู้ซื้อจ่าย(ราคาจะลดลงเมื่อมีโปรโมชัน↓)จะไม่สูงขึ้นแต่อย่างใด ราคา ส่วนลด และข้อมูลสต็อกที่แสดงเป็นข้อมูล ณ เวลาที่เขียนและอาจต่างจากความเป็นจริง โปรดตรวจสอบกับผู้ขายอีกครั้งก่อนซื้อ การเลือกและการประเมินสินค้าเขียนตามเกณฑ์ของเราเอง และการได้รับค่าคอมมิชชันหรือไม่ไม่มีผลต่อลำดับการแนะนำหรือเนื้อหาการประเมิน