Cài đặt và Cấu hình Apache HTTP Server với PHP-FPM trên CentOS Stream 9: Thực chiến tối ưu hiệu năng

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Bối cảnh và Tại sao cần Apache + PHP-FPM trên CentOS Stream 9

Khi xây dựng web server, chúng ta thường gặp bài toán khó: làm sao để cân bằng giữa hiệu năng cao và tính ổn định? Apache HTTP Server, với lịch sử phát triển lâu đời và độ tin cậy đã được kiểm chứng, vẫn là lựa chọn hàng đầu của nhiều người. Tuy nhiên, với các ứng dụng PHP hiện đại, việc sử dụng trực tiếp module mod_php của Apache đôi khi không phải là cách tối ưu nhất về hiệu năng lẫn bảo mật.

Đây là lúc PHP-FPM (FastCGI Process Manager) phát huy vai trò. PHP-FPM hoạt động như một tiến trình độc lập, quản lý các “worker” PHP riêng biệt.

Khi Apache nhận được yêu cầu xử lý file PHP, nó sẽ chuyển tiếp yêu cầu đó đến PHP-FPM. Cơ chế này không chỉ giúp tách biệt hoàn toàn tiến trình web server và PHP, tăng cường bảo mật (mỗi website có thể chạy dưới một user PHP-FPM riêng), mà còn cải thiện hiệu năng đáng kể, đặc biệt với các ứng dụng PHP “nặng” hoặc khi lượng truy cập lớn, ví dụ một trang thương mại điện tử với hàng ngàn lượt truy cập mỗi phút.

Về CentOS Stream 9, cá nhân mình đánh giá đây là một bước đi thú vị từ Red Hat. Mình từng “vật lộn” khi chuyển đổi một số server CentOS 7 sang AlmaLinux 9, nên rất hiểu những khác biệt giữa các phiên bản.

Việc chọn CentOS Stream 9 cho các hệ thống mới, theo mình, giúp bạn tiếp cận các tính năng mới sớm hơn mà vẫn giữ được sự ổn định và tương thích với hệ sinh thái RHEL. Đây là lựa chọn lý tưởng cho môi trường phát triển và thử nghiệm trước khi triển khai chính thức. Nó giúp chúng ta chủ động làm quen với những thay đổi sắp tới, tránh tình trạng bị động như khi CentOS 8 đột ngột kết thúc vòng đời.

Cài đặt các thành phần cần thiết

Trước khi bắt đầu, hãy cập nhật hệ thống để đảm bảo mọi gói phần mềm đều mới nhất, tránh các lỗi xung đột:


sudo dnf update -y

Cài đặt Apache HTTP Server

Trên CentOS Stream 9, Apache HTTP Server được gọi là httpd. Việc cài đặt rất đơn giản:


sudo dnf install httpd -y
sudo systemctl enable --now httpd
sudo systemctl status httpd

Sau khi cài đặt, kiểm tra trạng thái dịch vụ. Nếu bạn thấy active (running), nghĩa là mọi thứ đã sẵn sàng. Đừng quên mở port 80 (HTTP) và 443 (HTTPS) trên firewall để web server có thể hoạt động:


sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Cài đặt PHP-FPM

CentOS Stream 9 cung cấp PHP trong kho gói mặc định, nhưng thường không phải là phiên bản mới nhất hoặc không đầy đủ các extension cần thiết. Để có phiên bản PHP-FPM và các extension cập nhật nhất, mình thường sử dụng repository EPEL và Remi.


sudo dnf install epel-release -y
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm -y

Sau khi thêm kho gói Remi, bạn có thể xem danh sách các phiên bản PHP hiện có. Hiện tại, PHP 8.2 và 8.3 là những phiên bản phổ biến:


sudo dnf module list php

Để cài đặt PHP 8.2 (chẳng hạn), bạn cần kích hoạt module tương ứng và cài đặt PHP-FPM cùng các extension quan trọng. Mình thường cài đặt các module sau: php-cli, php-mysqlnd, php-gd, php-xml, php-mbstring, php-fpm, php-opcache, php-json.


sudo dnf module enable php:remi-8.2 -y
sudo dnf install php-fpm php-cli php-mysqlnd php-gd php-xml php-mbstring php-opcache php-json -y

Cuối cùng, kích hoạt và kiểm tra trạng thái của PHP-FPM:


sudo systemctl enable --now php-fpm
sudo systemctl status php-fpm

Cấu hình chi tiết Apache để làm việc với PHP-FPM

Đây là bước then chốt, nơi chúng ta sẽ “kết nối” Apache và PHP-FPM với nhau.

Cấu hình Apache Virtual Host

Chúng ta cần tạo một Virtual Host để phục vụ website của bạn. Mình khuyên bạn nên tạo file cấu hình riêng cho mỗi Virtual Host trong thư mục /etc/httpd/conf.d/. Ví dụ, với một trang web tên miền example.com:


sudo vi /etc/httpd/conf.d/example.com.conf

Nội dung file example.com.conf sẽ tương tự như sau:


<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/public_html

    <Directory /var/www/example.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # Kích hoạt ProxyPassMatch để chuyển các yêu cầu PHP sang PHP-FPM
    # PHP-FPM thường lắng nghe trên cổng 9000 hoặc qua Unix socket.
    # CentOS Stream 9 mặc định dùng Unix socket: /run/php-fpm/www.sock
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
    </FilesMatch>

    ErrorLog /var/log/httpd/example.com_error.log
    CustomLog /var/log/httpd/example.com_access.log combined
</VirtualHost>

Để bạn dễ hình dung, chúng ta cùng giải thích dòng SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/":

  • proxy:unix:/run/php-fpm/www.sock: Apache sẽ sử dụng module mod_proxy_fcgi để kết nối tới PHP-FPM thông qua Unix socket tại đường dẫn /run/php-fpm/www.sock. Đây là phương pháp vừa hiệu quả vừa bảo mật hơn so với việc dùng cổng TCP truyền thống.
  • fcgi://localhost/: Đây là thành phần cực kỳ quan trọng giúp PHP-FPM xác định đúng thư mục gốc (document root) của request. Khi PHP-FPM nhận yêu cầu, nó sẽ dựa vào phần này để thiết lập chính xác biến môi trường SCRIPT_FILENAME.

Tiếp theo, tạo thư mục DocumentRoot và phân quyền chuẩn xác:


sudo mkdir -p /var/www/example.com/public_html
sudo chown -R apache:apache /var/www/example.com
sudo chmod -R 755 /var/www/example.com

Kiểm tra cú pháp cấu hình Apache và khởi động lại dịch vụ để áp dụng thay đổi:


sudo apachectl configtest
sudo systemctl restart httpd

Cấu hình PHP-FPM Pool

PHP-FPM có một pool mặc định tên là www. Với các thiết lập đơn giản, bạn hoàn toàn có thể sử dụng pool này. File cấu hình của nó nằm tại /etc/php-fpm.d/www.conf.

Hãy kiểm tra giá trị của dòng listen trong file www.conf:


grep "listen =" /etc/php-fpm.d/www.conf

Nếu kết quả là listen = /run/php-fpm/www.sock, thì cấu hình Apache bên trên của chúng ta đã chính xác. Trong trường hợp bạn thấy cổng TCP (ví dụ listen = 127.0.0.1:9000), bạn sẽ cần điều chỉnh dòng SetHandler trong cấu hình Apache thành "proxy:fcgi://127.0.0.1:9000" để phù hợp.

Ngoài ra, bạn nên tinh chỉnh các tham số dưới đây để tối ưu hiệu năng và tránh phát sinh lỗi trong quá trình hoạt động:

  • usergroup: Đặt cả hai là apache. Điều này giúp PHP-FPM chạy dưới cùng user với Apache, giải quyết triệt để các vấn đề về quyền truy cập file, đặc biệt khi tương tác với các file do Apache tạo ra.
  • Các tham số quản lý tiến trình (pm.*):
    • pm = dynamic: Đây là chế độ mặc định và phù hợp cho phần lớn các trường hợp sử dụng.
    • pm.max_children: Đây là số lượng tiến trình con PHP-FPM tối đa được phép chạy. Bạn cần cân nhắc kỹ dựa trên dung lượng RAM của server. Một nguyên tắc nhỏ là: chia tổng RAM dành riêng cho PHP cho dung lượng RAM trung bình mà một tiến trình PHP tiêu thụ (ví dụ, nếu bạn dành 2GB RAM cho PHP và mỗi tiến trình PHP dùng khoảng 40MB, bạn có thể đặt pm.max_children khoảng 50).
    • pm.start_servers, pm.min_spare_servers, pm.max_spare_servers: Các tham số này giúp FPM tự động điều chỉnh số lượng tiến trình để “scale” theo tải, đảm bảo server không bị quá tải nhưng vẫn phản hồi nhanh chóng.

Ví dụ điều chỉnh trong file /etc/php-fpm.d/www.conf (chỉ sửa những dòng cần thiết):


listen = /run/php-fpm/www.sock
listen.owner = apache
listen.group = apache
listen.mode = 0660

user = apache
group = apache

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

Sau khi hoàn tất thay đổi, hãy khởi động lại PHP-FPM để các cấu hình mới có hiệu lực:


sudo systemctl restart php-fpm

Cấu hình SELinux

CentOS Stream 9 kích hoạt SELinux theo mặc định. Đây là một lớp bảo mật mạnh mẽ, nhưng đôi khi có thể gây trở ngại cho người mới. Để Apache và PHP-FPM giao tiếp được với nhau qua Unix socket, chúng ta phải đảm bảo SELinux cho phép kết nối này.

Nếu bạn gặp lỗi “Permission denied” trong log của Apache khi cố gắng kết nối với PHP-FPM, hãy kiểm tra log của SELinux. Thông thường, bạn sẽ cần tạo một chính sách tùy chỉnh để cho phép tương tác này:


sudo ausearch -c 'httpd' --raw | sudo audit2allow -M my-httpd
sudo semodule -i my-httpd.pp

Trong trường hợp cần khắc phục sự cố nhanh chóng (chỉ dành cho môi trường thử nghiệm!), bạn có thể tạm thời chuyển SELinux sang chế độ Permissive:


sudo setenforce 0

Để quay lại chế độ Enforcing khi đã khắc phục xong: sudo setenforce 1. Lưu ý, việc tắt SELinux không được khuyến nghị cho môi trường production.

Kiểm tra và Monitoring

Sau khi đã cài đặt và cấu hình xong, việc xác minh mọi thứ hoạt động suôn sẻ là vô cùng quan trọng.

Kiểm tra hoạt động PHP

Hãy tạo một file PHP đơn giản trong thư mục DocumentRoot của Virtual Host:


sudo vi /var/www/example.com/public_html/info.php

Nội dung file info.php:


<?php
phpinfo();
?>

Mở trình duyệt và truy cập http://example.com/info.php. Nếu bạn thấy trang thông tin PHP xuất hiện, đặc biệt là mục “Server API” hiển thị “FPM/FastCGI”, xin chúc mừng! Apache và PHP-FPM đã phối hợp thành công.

Kiểm tra Logs

Khi gặp sự cố, các file log chính là người bạn thân thiết nhất của bạn. Đừng quên kiểm tra những file log sau đây:

  • Log của Apache: /var/log/httpd/error_log/var/log/httpd/example.com_error.log (đối với Virtual Host cụ thể).
  • Log của PHP-FPM: /var/log/php-fpm/www-error.log (hoặc file log tương ứng với pool bạn đang sử dụng).

Sử dụng lệnh tail -f để xem log theo thời gian thực khi bạn truy cập website, điều này giúp bạn phát hiện lỗi ngay lập tức:


sudo tail -f /var/log/httpd/example.com_error.log
sudo tail -f /var/log/php-fpm/www-error.log

Monitoring cơ bản

Để duy trì hiệu năng ổn định, bạn cần theo dõi sát sao tài nguyên hệ thống như CPU, RAM, và I/O, đặc biệt khi website chịu tải cao. Các công cụ như htop, glances, hoặc sar sẽ cung cấp cái nhìn tổng quan hữu ích. Một điểm cần lưu ý là số lượng tiến trình php-fpm đang chạy, điều này giúp bạn điều chỉnh các tham số pm.* sao cho phù hợp với tài nguyên server và lượng truy cập thực tế.


htop

Nếu bạn thấy các tiến trình PHP-FPM liên tục bị kill rồi khởi động lại, hoặc website xuất hiện các lỗi 50x, đây là dấu hiệu rõ ràng cho thấy bạn cần điều chỉnh giá trị pm.max_children hoặc xem xét lại việc sử dụng bộ nhớ của từng tiến trình PHP.

Việc thiết lập Apache với PHP-FPM trên CentOS Stream 9 có vẻ phức tạp lúc đầu, nhưng với sự tỉ mỉ trong từng bước cấu hình, bạn sẽ đạt được sự ổn định và hiệu năng vượt trội cho các ứng dụng web PHP. Chúc bạn thành công với dự án của mình!

Share: