PHP-FPM이란 | PHP-FPM 설치 및 설정

PHP-FPM은 웹 서버가 넘긴 PHP 요청을 미리 띄워 둔 워커 프로세스가 받아 처리하는 FastCGI 프로세스 관리자입니다. Apache가 운영되고 있는 AlmaLinux 9 서버에서 설치 여부와 사이트 계정별 풀·소켓 설정을 확인하고, 설정 검사와 상태 확인까지 실제 출력으로 정리했습니다.
Apache는 mod_php로 PHP를 직접 실행할 수도 있지만 PHP-FPM에 넘기면 웹 서버와 PHP가 분리됩니다. Nginx는 PHP를 직접 실행하지 못해 PHP-FPM 같은 FastCGI 프로세스에 넘깁니다. 그래서 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에 포함되었습니다.
PHP-FPM은 워커 묶음인 풀(pool)마다 정한 개수의 워커를 미리 띄워 두고, 웹 서버가 소켓으로 넘긴 요청을 빈 워커가 받아 처리한 뒤 다음 요청을 기다립니다. 그림과 CSS 같은 정적 파일은 웹 서버가 직접 응답하고 PHP 파일만 PHP-FPM으로 넘어갑니다. 웹 서버가 소켓에 요청을 넘기는 방법만 다르며, Apache는 mod_proxy_fcgi 모듈을, Nginx는 fastcgi_pass 설정을 사용합니다.
2️⃣ PHP-FPM 설치: 패키지 확인과 dnf 설치
RHEL 계열 서버에 dnf로 PHP를 설치했다면 php-fpm 패키지가 함께 설치되어 있습니다. rpm으로 설치 여부부터 확인합니다. PHP 설치 과정은 록키 리눅스 APM 설치와 같습니다.
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 = 18ondemand 모드는 요청이 올 때만 워커를 띄우고 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 전체 설정인 php.ini에서 정하며, 운영하는 사이트에 맞춰 워커 수와 함께 조정합니다.
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는 mod_proxy_fcgi 모듈로 PHP 파일 요청을 풀의 소켓에 넘깁니다. VirtualHost 안의 FilesMatch에 SetHandler 한 줄을 넣으며, 사이트마다 그 계정의 소켓을 적습니다.
# 사이트 계정마다 VirtualHost 하나 · SetHandler 에 그 계정의 소켓(SetHandler 대신 ProxyPassMatch 로도 연결 가능)
<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는 그 계정의 웹 루트이며, Options의 -Indexes는 폴더 목록이 브라우저에 노출되는 것을 막습니다.
🔲 소켓 권한 설정
풀을 시작하면 listen.owner·listen.group·listen.mode 값으로 소켓이 만들어지며, 권한이 맞는지 ls로 확인합니다.
ls -l /run/php-fpm/합계 4
srw-rw---- 1 siteuser_a nobody 0 10월 22 23:34 siteuser_a.sock
-rw-r--r-- 1 root root 7 10월 26 03:00 php-fpm.pid
srw-rw---- 1 siteuser_b nobody 0 10월 22 23:34 siteuser_b.sock
srw-rw----+ 1 root root 0 10월 22 23:34 www.sock권한이 어긋나 웹 서버가 소켓을 열지 못하면 방문자는 503 오류를 받으며, 재시작 없이 바로 맞출 때는 chown과 chmod로 소유자와 권한을 지정합니다.
사용자와 그룹을 콜론으로 구분하는 지금 문법입니다.
chown siteuser:nobody /run/php-fpm/siteuser.sock소유자를 바꾼 뒤 권한을 660으로 맞춥니다.
chmod 660 /run/php-fpm/siteuser.sock사용자와 그룹을 점으로 구분하는 옛 문법이며, AlmaLinux 9의 chown에서도 그대로 실행됩니다.
chown siteuser.nobody /run/php-fpm/siteuser.sock소유자를 바꾼 뒤 권한을 660으로 맞춥니다.
chmod 660 /run/php-fpm/siteuser.sock두 문법의 결과는 같으며, 어느 쪽을 사용해도 소켓의 소유자가 siteuser, 그룹이 nobody로 바뀝니다.
🔲 Nginx 연동: fastcgi_pass 설정
Nginx는 server 블록 안 PHP 파일 location에서 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-fpmVirtualHost를 고쳤으면 Apache도 재시작합니다.
systemctl restart httpd서버를 다시 켰을 때 자동으로 실행되도록 enable로 등록합니다.
systemctl enable php-fpm등록 여부는 is-enabled로 확인합니다.
systemctl is-enabled php-fpmenabledstatus로 풀마다 워커가 떠 있는지 확인합니다.
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"
10월 26 03:00:01 server.example.com systemd[1]: Reloading The PHP FastCGI Process Manager...
10월 26 03:00:01 server.example.com systemd[1]: Reloaded The PHP FastCGI Process Manager.Status 줄의 active와 idle이 지금 처리 중인 워커와 쉬는 워커이며, CGroup에는 풀 이름별로 워커가 나열됩니다. 출력의 호스트 이름과 풀 이름은 예시 값으로 바꿨습니다.
🔢 FAQ & 추천 콘텐츠
ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.