PHP-FPM là gì | Cài đặt và cấu hình PHP-FPM
PHP-FPM là trình quản lý tiến trình FastCGI, trong đó các tiến trình worker được khởi động sẵn sẽ nhận các yêu cầu PHP mà web server chuyển sang rồi xử lý. Trên máy chủ AlmaLinux 9 chạy Apache, bài này kiểm tra xem đã cài chưa và cách thiết lập pool cùng socket theo từng trang web, rồi đi tiếp đến kiểm tra cấu hình và kiểm tra trạng thái bằng kết quả thực tế.
Apache cũng có thể chạy PHP trực tiếp bằng mod_php, nhưng nếu giao cho PHP-FPM thì web server và PHP được tách riêng. Nginx không chạy PHP trực tiếp được nên chuyển yêu cầu sang một tiến trình FastCGI như PHP-FPM. Vì vậy một PHP-FPM có thể gắn với Apache hoặc Nginx đều được. Phần thiết lập pool và cấu trúc socket bên dưới áp dụng nguyên vẹn khi bạn kết nối PHP-FPM với Nginx.
1️⃣ PHP-FPM là gì: khác biệt giữa CGI và FastCGI
CGI (Common Gateway Interface) là cách chuẩn để web server chạy một chương trình bên ngoài nhằm tạo nội dung động, và mỗi khi có yêu cầu thì chương trình được khởi động lại từ đầu. Chi phí tạo và xóa tiến trình cho từng yêu cầu cứ dồn lại, nên truy cập càng tăng thì máy chủ phản hồi càng chậm.
FastCGI loại bỏ chi phí này bằng cách khởi động sẵn chương trình và xử lý các yêu cầu nối tiếp nhau. Đó là khác biệt giữa việc bật tắt máy tính mỗi lần dùng và việc dùng ngay một máy tính đã bật sẵn. PHP-FPM (FastCGI Process Manager) là trình quản lý chạy PHP qua FastCGI, và được tích hợp trong PHP từ phiên bản 5.3.3.
Với mỗi pool, tức một nhóm worker, PHP-FPM khởi động sẵn số worker đã định; một worker đang rảnh nhận yêu cầu mà web server chuyển qua socket, xử lý xong rồi chờ yêu cầu tiếp theo. Tệp tĩnh như hình ảnh và CSS do web server trả lời trực tiếp, chỉ tệp PHP mới được chuyển sang PHP-FPM. Điểm khác nhau chỉ là cách web server chuyển yêu cầu vào socket: Apache dùng mô-đun mod_proxy_fcgi, còn Nginx dùng thiết lập fastcgi_pass.
2️⃣ Cài đặt PHP-FPM: kiểm tra gói và cài bằng dnf
Nếu bạn cài PHP bằng dnf trên máy chủ họ RHEL thì gói php-fpm đã được cài cùng. Hãy kiểm tra bằng rpm xem đã cài chưa. Quy trình cài PHP giống như trong bài Cài đặt APM trên Rocky Linux.
rpm -qa | grep php-fpmphp-fpm-8.3.36-1.module_php.8.3.el9.remi.x86_64Nếu kết quả trống thì chưa cài, hãy cài bằng dnf.
dnf -y install php-fpmCài xong, hãy chạy lại đúng lệnh rpm đó để kiểm tra tên gói có hiện ra không.
3️⃣ Thiết lập PHP-FPM: pool www.conf, socket, chế độ tĩnh và động
Có hai tệp cấu hình: cấu hình chung [/etc/php-fpm.conf] và cấu hình pool [/etc/php-fpm.d/www.conf]. Trong pool mặc định www.conf, các dòng cần xem trước là listen và pm, và giá trị ngay sau khi cài như sau.
grep -E '^(listen|pm) ' /etc/php-fpm.d/www.conflisten = /run/php-fpm/www.sock
pm = dynamiclisten là nơi web server chuyển yêu cầu vào, và giá trị mặc định của bản 8.3 là Unix socket [/run/php-fpm/www.sock]. Giá trị mặc định của các bản cũ, [127.0.0.1:9000], nhận yêu cầu qua cổng TCP. Trong cùng một máy chủ, socket nhẹ hơn vì không phải qua bước kết nối cổng, và với listen.owner cùng listen.group bạn có thể giới hạn quyền truy cập như quyền tệp.
🔲 Thiết lập chế độ tĩnh và chế độ động
pm là cách khởi động worker, và được đặt là một trong ba giá trị: static, dynamic hoặc ondemand. Chế độ tĩnh luôn giữ chạy sẵn số worker ghi trong pm.max_children, và thiết lập bên dưới giữ 100 worker.
pm = static
pm.max_children = 100Chế độ động là mặc định và tăng giảm số worker theo lượng yêu cầu. Thiết lập bên dưới khởi động 12 worker lúc đầu, giữ số worker rảnh từ 6 đến 18 và tăng tối đa đến 120.
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18Chế độ ondemand chỉ khởi động worker khi có yêu cầu và kết thúc chúng sau khi hết pm.process_idle_timeout, nên hợp với trang web ít truy cập và không hợp với trang web nhiều truy cập.
Ba chế độ khác nhau ở thời điểm khởi động worker và cách tăng giảm số lượng.
| Chế độ | Cách khởi động worker | Trang web phù hợp |
|---|---|---|
| static (tĩnh) | Luôn giữ chạy sẵn số worker ghi trong pm.max_children | Trang web nhiều truy cập |
| dynamic (động) | Mặc định · tăng giảm trong khoảng pm.start_servers, pm.min_spare_servers và pm.max_spare_servers theo lượng yêu cầu | Trang web có lượng truy cập lên xuống |
| ondemand | Chỉ khởi động khi có yêu cầu và kết thúc sau khi hết pm.process_idle_timeout | Trang web ít truy cập |
max_children được định bằng cách chia bộ nhớ máy chủ cho bộ nhớ một worker dùng. Dù cảnh báo chạm [max_children] có dồn lại, cũng đừng nâng ngay mà trước hết dùng log để lọc ra những yêu cầu đã làm đầy worker.
Giới hạn bộ nhớ và tải lên được đặt trong php.ini, cấu hình chung của PHP, và được điều chỉnh cùng số worker cho phù hợp với trang web bạn vận hành.
memory_limit = 1024M
post_max_size = 128M
upload_max_filesize = 128MBa giá trị này là mức bộ nhớ tối đa một tập lệnh PHP được dùng và dung lượng tệp có thể tải lên một lần, và chỉ có hiệu lực sau khi khởi động lại PHP-FPM.
🔲 Thiết lập pool theo từng tài khoản trang web
Khi có nhiều trang web, đừng dùng chung một www.conf mà hãy tạo tệp pool cho từng tài khoản rồi tách tài khoản chạy và socket. PHP của một trang web không đọc được tệp của tài khoản khác, và số worker cũng được định theo từng trang web.
vi /etc/php-fpm.d/siteuser.confTrong tệp ghi tên pool, tài khoản chạy, đường dẫn socket và số worker.
[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 và listen.group là chủ sở hữu và nhóm của tệp socket, và PHP-FPM tạo socket bằng các giá trị này khi khởi động. Nếu web server chạy bằng tài khoản nobody thì ghi listen.group là nobody, còn nếu là tài khoản apache thì ghi apache, để web server mở được socket.
listen.owner = siteuser
listen.group = nobody
listen.mode = 0660Ba dòng này có trong mọi tệp pool, và sau khi đổi giá trị phải khởi động lại để socket được tạo lại với quyền mới.
🔲 Thiết lập slowlog
slowlog là tệp ghi lại vị trí đang chạy của những yêu cầu mất nhiều thời gian hơn request_slowlog_timeout, và nếu giá trị là 0 thì không ghi. Khi tìm nguyên nhân của yêu cầu chậm, hãy bật bằng cách đặt thời gian theo giây như 3s.
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 0Tệp được ghi giữ lại đường dẫn tập lệnh của yêu cầu chậm và hàm đang chạy lúc đó, nhờ vậy bạn biết plugin hay đoạn mã nào đã làm mất thời gian.
4️⃣ Kết nối Apache: thiết lập VirtualHost và quyền của socket
Apache chuyển yêu cầu tệp PHP vào socket của pool bằng mô-đun mod_proxy_fcgi. Bạn đặt một dòng SetHandler trong FilesMatch bên trong VirtualHost, và với mỗi trang web ghi socket của tài khoản đó.
# Mỗi tài khoản trang web một VirtualHost · ghi socket của tài khoản đó vào SetHandler (có thể kết nối bằng ProxyPassMatch thay cho 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 và Directory là thư mục gốc web của tài khoản đó, và -Indexes trong Options ngăn danh sách thư mục hiện ra trên trình duyệt.
🔲 Thiết lập quyền của socket
Khi pool khởi động, socket được tạo bằng các giá trị listen.owner, listen.group và listen.mode, và bạn kiểm tra bằng ls xem quyền đã đúng chưa.
ls -l /run/php-fpm/tổng 4
srw-rw---- 1 siteuser_a nobody 0 Th10 22 23:34 siteuser_a.sock
-rw-r--r-- 1 root root 7 Th10 26 03:00 php-fpm.pid
srw-rw---- 1 siteuser_b nobody 0 Th10 22 23:34 siteuser_b.sock
srw-rw----+ 1 root root 0 Th10 22 23:34 www.sockNếu quyền không khớp và web server không mở được socket thì khách truy cập nhận lỗi 503; để sửa ngay mà không khởi động lại, hãy chỉ định chủ sở hữu và quyền bằng chown và chmod.
Đây là cú pháp hiện tại, phân tách người dùng và nhóm bằng dấu hai chấm.
chown siteuser:nobody /run/php-fpm/siteuser.sockSau khi đổi chủ sở hữu, hãy đặt quyền là 660.
chmod 660 /run/php-fpm/siteuser.sockĐây là cú pháp cũ, phân tách người dùng và nhóm bằng dấu chấm, và chown trên AlmaLinux 9 vẫn chạy được nguyên như vậy.
chown siteuser.nobody /run/php-fpm/siteuser.sockSau khi đổi chủ sở hữu, hãy đặt quyền là 660.
chmod 660 /run/php-fpm/siteuser.sockKết quả của hai cú pháp là như nhau; dùng cách nào thì chủ sở hữu của socket cũng thành siteuser và nhóm thành nobody.
🔲 Kết nối Nginx: thiết lập fastcgi_pass
Trong Nginx, location dành cho tệp PHP bên trong khối server chuyển yêu cầu vào socket của cùng pool bằng fastcgi_pass.
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm/siteuser.sock;
}Nếu Nginx chạy bằng tài khoản nginx thì phải ghi listen.group trong tệp pool là nginx thì mới mở được socket.
5️⃣ Kiểm tra cấu hình và khởi động lại: php-fpm -t và systemctl
Sau khi đổi cấu hình, đừng khởi động lại ngay mà hãy kiểm tra cú pháp bằng php-fpm -t trước. Nếu tệp pool có lỗi gõ, khi khởi động lại toàn bộ PHP-FPM sẽ sập và mọi trang web đều nhận lỗi 503.
php-fpm -t[26-Oct-2026 17:33:45] NOTICE: configuration file /etc/php-fpm.conf test is successfulNếu kiểm tra đạt, thông báo [test is successful] hiện ra cùng đường dẫn tệp cấu hình, rồi bạn áp dụng thay đổi vào PHP-FPM. Thay đổi cần tạo lại socket, như đường dẫn socket hay listen.owner, được áp dụng bằng restart. Nếu trên máy chủ đang vận hành bạn chỉ đổi những giá trị như số worker thì áp dụng bằng reload.
systemctl restart php-fpmNếu bạn đã sửa VirtualHost thì khởi động lại cả Apache.
systemctl restart httpdĐăng ký bằng enable để dịch vụ tự chạy khi máy chủ bật lại.
systemctl enable php-fpmKiểm tra đã đăng ký chưa bằng is-enabled.
systemctl is-enabled php-fpmenabledDùng status để kiểm tra worker có đang chạy ở từng pool không.
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"
Th10 26 03:00:01 server.example.com systemd[1]: Reloading The PHP FastCGI Process Manager...
Th10 26 03:00:01 server.example.com systemd[1]: Reloaded The PHP FastCGI Process Manager.Ở dòng Status, active và idle là các worker đang xử lý yêu cầu và các worker đang rảnh, còn CGroup liệt kê worker theo tên pool. Tên máy chủ và tên pool trong kết quả đã được thay bằng giá trị ví dụ.
🔢 FAQ & nội dung đề xuất
Cache
Cache: định nghĩa và mọi lĩnh vực có dùng cache
Giải thích theo từng lĩnh vực cấu trúc mà yêu cầu trúng cache không bao giờ đến được worker PHP-FPM.
Máy chủ cache
Cài đặt và thiết lập Varnish Cache trên Apache và Nginx
Quá trình cài đặt đặt máy chủ cache phía trước web server để giảm chính các yêu cầu PHP.
Linux
Lệnh Linux: phân loại 15 nhóm
Bảng phân loại lệnh thành 15 nhóm, gồm cả rpm, grep và systemctl được dùng trong bài này.
ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.