Apache httpd 는 .php 파일을 그냥 두면 정적 파일로 내려보낸다. 실행하려면 PHP 해석기를 붙여야 하고, 붙이는 방식이 둘이었다.
| 방식 | 구조 | 현재 상태 |
|---|---|---|
| mod_php | httpd 프로세스 안에서 PHP 를 해석한다 | RHEL 9 · Rocky 9 · Alma 9 에서 패키지가 없다[1] |
PHP-FPM + mod_proxy_fcgi |
별도 프로세스에 FastCGI 로 넘긴다 | 현행 방식 |
RHEL 8 에서 이미 기본값이 PHP-FPM 으로 바뀌었고 RHEL 9 에서는 mod_php 가 아예 빠졌다. dnf install mod_php 가 No match for argument: mod_php 로 끝나는 것은 저장소 설정 문제가 아니라 패키지가 없기 때문이다.
sudo dnf install -y httpd php php-cli php-common php-fpm php-mbstring php-pdo php-mysqlnd php-gd php-xml php-opcache
sudo systemctl enable --now php-fpm httpd
mod_proxy_fcgi 는 httpd 패키지에 들어 있다. 적재됐는지 확인한다.
httpd -M | grep -E 'proxy_module|proxy_fcgi_module'
RHEL 계열 기본값은 유닉스 소켓이다. 같은 호스트 안이면 소켓이 TCP 보다 낫다.
; /etc/php-fpm.d/www.conf
[www]
user = apache
group = apache
listen = /run/php-fpm/www.sock
listen.owner = apache
listen.group = apache
listen.mode = 0660
컨테이너처럼 /run 이 매번 새로 만들어지는 환경이나, httpd 와 PHP-FPM 을 다른 컨테이너로 나눈 구성에서는 TCP 로 연다.
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
listen.allowed_clients 는 TCP 로 열 때만 의미가 있다. 다른 컨테이너에서 붙는 구성이라면 이 값을 지우거나 상대 주소를 넣어야 한다.
listen 에 적은 형태와 반드시 짝이 맞아야 한다. 유닉스 소켓일 때.
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</FilesMatch>
DirectoryIndex index.php index.html
TCP 일 때.
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
httpd 와 PHP-FPM 을 다른 컨테이너로 나눴다면 localhost 가 아니라 상대 컨테이너 이름을 적는다. httpd 컨테이너 안의 localhost 에는 PHP 가 없다.
<FilesMatch \.php$>
SetHandler "proxy:fcgi://php:9000"
</FilesMatch>
이 구성에서는 두 컨테이너가 같은 경로에 같은 문서 루트를 마운트해야 한다. PHP-FPM 은 요청받은 경로를 자기 파일시스템에서 다시 여는데, 경로가 다르면 File not found 가 난다.
한글이 깨지는 것을 막으려면 세 군데를 UTF-8 로 맞춘다.
AddDefaultCharset UTF-8
; /etc/php.ini
default_charset = "UTF-8"
HTML 문서에도 <meta charset="UTF-8"> 을 둔다. 데이터베이스까지 이어진다면 MySQL · MariaDB 쪽은 utf8mb4 로 맞춘다.
echo '<?php phpinfo();' | sudo tee /var/www/html/info.php
curl -sI http://localhost/info.php | head -3
Content-Type: text/html 이 나오면 실행된 것이다. 확인이 끝나면 info.php 는 지운다. PHP 버전과 적재 모듈, 경로가 그대로 드러난다.
브라우저가 .php 를 내려받으려 하면 요청이 PHP-FPM 까지 가지 않았다는 뜻이다. 위에서부터 확인한다.
httpd -M | grep proxy_fcgi # 모듈이 적재됐는가
httpd -t -D DUMP_INCLUDES # 핸들러를 넣은 파일이 실제로 읽히는가
grep -R 'SetHandler' /etc/httpd/conf.d/
<FilesMatch> 를 <VirtualHost> 안에 넣었는데 요청이 다른 VirtualHost 로 갔거나, conf.d 에 둔 파일이 Include 범위 밖이면 설정이 없는 것과 같다.
[proxy_fcgi:error] AH01079: failed to make connection to backend: 127.0.0.1
"GET /test.php HTTP/1.1" 503
httpd 는 설정대로 넘기려 했는데 받는 쪽이 없다. 원인은 셋 중 하나다.
ps -ef | grep php-fpm 또는 systemctl status php-fpm 으로 본다.listen 주소와 SetHandler 주소가 다르다. 소켓으로 듣는데 TCP 로 보내는 조합이 가장 흔하다.PHP-FPM 쪽 로그는 따로 본다.
tail -f /var/log/php-fpm/error.log /var/log/php-fpm/www-error.log
PHP 연동과 무관한 설정 오류일 때가 많다. 화면에는 아무것도 안 나오므로 반드시 에러 로그를 본다.
tail -n 50 /var/log/httpd/error_log
docker logs --tail 50 web
자주 나오는 원인은 다음과 같다.
.htaccess 에 Options 를 썼는데 상위에서 AllowOverride None 이라 거부됐다.FollowSymLinks 가 없다..htaccess 를 비우고 재시작해 증상이 사라지는지부터 가른다.
"The mod_php module provided with PHP for use with the Apache HTTP Server has been removed." RHEL 9 는 httpd 2.4.62 를 제공하고 PHP 는 php-fpm 으로 실행한다 — 2026-09-20 확인. https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/deploying_web_servers_and_reverse_proxies/setting-apache-http-server_deploying-web-servers-and-reverse-proxies ↩︎