Giải mã lỗi
Bạn truy cập ứng dụng web của mình và thấy trang "404 Not Found" lạnh lùng. Tệp tin vẫn tồn tại trên ổ đĩa, nhưng Nginx lại từ chối phục vụ nó. Kiểm tra nhanh nhật ký lỗi tại /var/log/nginx/error.log sẽ thấy một thông báo đầy khó chịu:
FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream
Phía sau hậu trường
Lỗi này báo hiệu sự gián đoạn giao tiếp giữa Nginx và PHP-FPM. Nginx đóng vai trò là người gác cổng, nhận yêu cầu và chuyển nó đến bộ xử lý PHP. Tuy nhiên, PHP-FPM phản hồi "không tìm thấy" vì nó không thể xác định được đường dẫn tệp mà Nginx cung cấp. Thông thường, vấn đề này nằm ở một trong ba lỗ hổng cấu hình.
- Biến
SCRIPT_FILENAMEđược truyền tới PHP-FPM trỏ đến một đường dẫn không tồn tại. - Chỉ thị
rootbị đặt sai vị trí trong khối cấu hình. - Tiến trình PHP-FPM thiếu quyền cần thiết để đọc thư mục.
Các bước giải quyết chi tiết
1. Kiểm tra tham số SCRIPT_FILENAME
Thủ phạm phổ biến nhất là cấu hình sai fastcgi_param SCRIPT_FILENAME. Hãy mở tệp cấu hình trang web của bạn, thường nằm tại /etc/nginx/sites-available/example.com.
Tìm khối location PHP của bạn. Nó sẽ trông giống như thế này:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Cách khắc phục: Đảm bảo SCRIPT_FILENAME sử dụng $document_root$fastcgi_script_name. Nếu bạn đã viết cứng (hardcode) một đường dẫn như /var/www/html$fastcgi_script_name, hãy kiểm tra kỹ từng ký tự. Chỉ một lỗi chính tả nhỏ trong tên thư mục cũng sẽ kích hoạt lỗi 404.
2. Thoát khỏi bẫy chỉ thị Root
Đặt sai vị trí chỉ thị root là một sai lầm phổ biến. Nếu bạn định nghĩa root bên trong khối location /, khối PHP sẽ không được kế thừa nó. Điều này khiến biến $document_root bị trống khi Nginx chuyển yêu cầu cho PHP-FPM.
Tránh sai lầm này:
server {
listen 80;
server_name example.com;
location / {
root /var/www/my-app/public; # Sai: Phạm vi bị hạn chế
index index.php;
}
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
...
}
}
Cách làm đúng: Di chuyển chỉ thị root lên cấp server. Điều này đảm bảo nó áp dụng cho mọi khối location trong tệp.
server {
listen 80;
server_name example.com;
root /var/www/my-app/public; # Đúng: Phạm vi toàn cục
location / {
index index.php;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
3. Xử lý nghẽn cổ chai về quyền truy cập
PHP-FPM rất khắt khe về quyền truy cập. Nó thường chạy dưới danh nghĩa người dùng www-data hoặc php-fpm, chứ không phải người dùng đã tải tệp lên. Nếu worker PHP không thể "duyệt qua" cây thư mục, nó sẽ báo cáo script là không xác định (unknown).
Xác định người dùng PHP của bạn bằng lệnh này:
ps aux | grep php-fpm
Xác nhận rằng người dùng này có quyền đọc (read) các tệp PHP và quyền thực thi (execute) đối với mọi thư mục cha. Đối với thiết lập Ubuntu tiêu chuẩn, bạn có thể đặt lại quyền sở hữu và quyền truy cập một cách nhanh chóng:
sudo chown -R www-data:www-data /var/www/my-app
sudo find /var/www/my-app -type d -exec chmod 755 {} \;
sudo find /var/www/my-app -type f -exec chmod 644 {} \;
4. Chế ngự SELinux trên RHEL/CentOS
Trên các hệ thống dựa trên Red Hat, SELinux thường là "kẻ sát nhân thầm lặng". Nó có thể chặn Nginx ngay cả khi quyền Linux của bạn là 777 hoàn hảo. Hãy kiểm tra điều này bằng cách tạm thời chuyển sang chế độ permissive:
sudo setenforce 0
Nếu trang web của bạn hoạt động trở lại, SELinux chính là rào cản. Hãy khôi phục chế độ enforcement và áp dụng ngữ cảnh bảo mật chính xác cho thư mục web của bạn:
sudo setenforce 1
sudo chcon -Rt httpd_sys_content_t /var/www/my-app
Áp dụng các thay đổi
Đừng bao giờ khởi động lại Nginx mà không kiểm tra cú pháp trước. Một dấu chấm phẩy bị thiếu có thể làm toàn bộ máy chủ của bạn ngừng hoạt động.
sudo nginx -t
Nếu bài kiểm tra thành công, hãy tải lại các dịch vụ để áp dụng các bản sửa lỗi:
sudo systemctl reload nginx
sudo systemctl restart php8.2-fpm
Tải lại trình duyệt của bạn. Ứng dụng PHP bây giờ sẽ tải chính xác.
Mẹo chuyên nghiệp để xử lý sự cố
- Cẩn thận với Symlinks: Nếu bạn sử dụng các công cụ triển khai như Capistrano, hãy đảm bảo Nginx được phép đi theo các liên kết tượng trưng (symbolic links). Thiết lập
disable_symlinks off;trong cấu hình của bạn nếu cần. - Kiểm tra đường dẫn Socket: Xác minh rằng
fastcgi_passkhớp với tệp socket thực tế trong/etc/php/8.2/fpm/pool.d/www.conf. Sự không khớp về phiên bản (ví dụ: cấu hình ghi 8.1 nhưng bản 8.2 đã được cài đặt) là một nguyên nhân gây đau đầu thường gặp. - Độ chính xác của Document Root: Trong
fastcgi_paramcủa bạn, hãy tránh các dấu gạch chéo ở cuối nếu chỉ thịrootcủa bạn đã có sẵn một dấu. Dấu gạch chéo kép (ví dụ:/var/www//index.php) đôi khi có thể làm bối rối một số phiên bản PHP-FPM nhất định.

