PHP - SAPI
- -

개요
PHP 애플리케이션은 같은 코드베이스라도 항상 같은 방식으로 실행되지 않는다. 웹 요청은 보통 PHP-FPM worker가 처리하고, php artisan 같은 명령은 CLI 프로세스가 처리한다. 로컬 개발에서 사용하는 php artisan serve는 또 다른 실행 방식인 PHP built-in server를 사용한다.
이 차이를 이해하려면 먼저 SAPI를 분리해서 봐야 한다. SAPI는 PHP 엔진이 외부 세계와 만나는 실행 인터페이스다. 즉 PHP 코드 자체가 달라지는 것이 아니라, PHP 엔진에 요청을 어떻게 전달하고 결과를 어디로 내보낼지가 달라진다.
1. SAPI란?
SAPI는 PHP 문맥에서 Server API, 또는 Server Application Programming Interface로 설명된다. 이름에 server가 들어가지만 웹 서버 전용이라는 뜻은 아니다. CLI, FPM, CGI, built-in server, phpdbg 모두 PHP의 SAPI다.
PHP 실행은 대략 이렇게 나뉜다.
입력 환경
→ SAPI
→ PHP 엔진 / Zend Engine
→ PHP 코드 실행
→ SAPI를 통해 결과 반환
SAPI는 다음을 결정한다.
- 입력을 어디서 받을지: HTTP 요청, 터미널 인자, FastCGI payload 등
- 출력을 어디로 보낼지: HTTP response, stdout, debugger 등
$_SERVER,php://input, header 처리 방식을 어떻게 구성할지- 프로세스 수명이 요청 단위인지, 명령 단위인지, 장기 상주인지
그래서 Laravel 코드가 같아도 실행 컨텍스트는 달라진다.
웹 요청 → FPM/FastCGI SAPI
php artisan 명령 → CLI SAPI
php artisan serve → built-in web server / cli-server SAPI
테스트 커버리지 → phpdbg SAPI
2. CGI
CGI(Common Gateway Interface)는 웹 서버가 외부 프로그램을 실행해 동적 응답을 만드는 오래된 인터페이스다.
Browser
→ Web Server
→ 요청마다 php-cgi 프로세스 실행
→ PHP script 실행
→ 응답 반환
→ 프로세스 종료
CGI의 핵심 특징은 요청마다 외부 프로그램 프로세스를 새로 만든다는 점이다. 웹 서버는 요청 정보를 환경변수와 표준 입력으로 넘기고, 외부 프로그램은 표준 출력으로 HTTP 헤더와 본문을 돌려준다.
구조는 단순하지만 비용이 크다.
- 요청마다 프로세스 생성 비용이 든다.
- Laravel 같은 프레임워크는 매 요청마다 부트스트랩 비용이 크다.
- 트래픽이 늘면 프로세스 생성/종료 자체가 병목이 된다.
그래서 현대 PHP 운영 환경에서 CGI를 직접 쓰는 경우는 드물다.
3. FastCGI
FastCGI는 CGI의 가장 큰 문제였던 요청마다 프로세스를 새로 만드는 비용을 줄이기 위해 나온 별도 인터페이스/프로토콜이다.
Browser
→ Nginx / Apache
→ FastCGI protocol
→ 이미 떠 있는 PHP 프로세스
→ PHP script 실행
→ 응답 반환
CGI와 달리 PHP 프로세스를 미리 띄워두고 재사용한다. 웹 서버는 매 요청마다 새 프로세스를 실행하지 않고, 이미 살아 있는 FastCGI 프로세스에 요청을 전달한다.
다만 FastCGI 자체는 “요청 전달 방식”에 가깝다. 운영에서는 프로세스 수 조절, 죽은 프로세스 재시작, graceful reload, slow log, max requests 같은 관리 기능이 필요하다. PHP에서 이 역할을 맡는 대표 구현이 PHP-FPM이다.
4. FPM
FPM(FastCGI Process Manager)은 PHP용 FastCGI 프로세스 매니저다. 웹 서버가 직접 PHP 코드를 실행하는 것이 아니라, FPM worker에게 FastCGI 요청을 넘긴다.
Browser
→ Nginx
→ FastCGI
→ php-fpm master
→ php-fpm worker
→ Laravel public/index.php
→ 응답 반환
FPM의 역할은 PHP worker pool을 운영하는 것이다.
- worker 프로세스를 미리 띄워둔다.
- 요청이 들어오면 놀고 있는 worker에게 배정한다.
- worker 수를
pm.max_children등으로 제한한다. - 느린 요청, timeout, 재시작, 로그 등을 관리한다.
- 요청이 끝나면 worker는 다음 요청을 받을 수 있다.
중요한 점은 FPM worker 하나가 한 번에 요청 하나를 처리한다는 것이다. 응답이 끝나기 전까지 그 worker는 다른 요청을 받을 수 없다. 그래서 오래 걸리는 작업을 웹 요청 안에서 처리하면 worker가 묶이고, worker pool이 고갈될 수 있다.
큐를 쓰는 이유도 여기에 있다. 요청에 꼭 필요한 작업만 FPM worker가 처리하고, 메일 발송·파일 변환·외부 API 처리 같은 무거운 작업은 CLI worker로 넘긴다.
5. CLI
CLI(Command Line Interface)는 터미널, cron, Supervisor, systemd 등에서 php 실행 파일을 직접 실행하는 방식이다.
php artisan queue:work
php artisan migrate
php script.php
구조는 FPM과 다르다.
Shell / cron / Supervisor
→ php CLI 바이너리
→ artisan 또는 PHP script 실행
→ 종료
또는 queue:work처럼 장기 실행될 수도 있다.
Supervisor
→ php artisan queue:work
→ Laravel 부트스트랩
→ Job 처리 루프
→ 여러 Job 처리 후 재시작
CLI 프로세스는 FPM worker를 사용하지 않는다. php artisan queue:work, php artisan schedule:run, php artisan migrate는 모두 FPM pool과 별개의 PHP 프로세스다.
따라서 FPM의 웹 timeout에는 묶이지 않지만, 대신 장기 프로세스 특유의 문제가 생긴다.
- 메모리 누수가 누적될 수 있다.
- 싱글톤, static 상태가 Job 사이에 남을 수 있다.
- 코드 배포 후 재시작이 필요하다.
--max-time,--max-jobs,--memory같은 제한으로 주기적 재활용이 필요하다.
6. CLI server
CLI server는 PHP가 제공하는 개발용 built-in web server다. Laravel의 php artisan serve는 내부적으로 이 서버를 실행한다.
php artisan serve
실제로는 대략 이런 형태다.
php -S 127.0.0.1:8000 server.php
구조는 CGI도 FPM도 아니다.
Browser
→ php -S 프로세스
→ PHP built-in web server
→ Laravel public/index.php
→ 응답 반환
CGI처럼 요청마다 php-cgi 프로세스를 새로 띄우지 않는다. FPM처럼 Nginx가 FastCGI로 worker pool에 요청을 넘기는 구조도 아니다. PHP 프로세스 자체가 간단한 HTTP 서버 역할을 한다.
운영용으로 적합하지 않은 이유는 운영 서버로써 필요한 기능이 부족하기 때문이다.
- 기본적으로 개발 편의성에 초점을 둔 서버다.
- 정교한 worker/process 관리가 없다.
- Nginx/Apache 수준의 정적 파일 처리, buffering, reverse proxy, TLS 운영 기능이 없다.
- 장애 복구, 튜닝, 관측성이 제한적이다.
- 일반적인 운영 트래픽을 전제로 설계되지 않았다.
OPcache 같은 opcode cache는 설정에 따라 CLI server에서도 사용할 수 있다. 다만 개발 서버에서는 코드 변경이 즉시 반영되는 편이 중요하고, 운영 수준의 캐시·프로세스 관리까지 붙일 바에는 Nginx + FPM 구조를 쓰는 것이 맞다.
그래서 php artisan serve는 로컬 개발용으로 보는 것이 정확하다.
7. 정리
같은 Laravel 애플리케이션도 실행 주체에 따라 성격이 완전히 달라진다.
| 실행 방식 | 대표 명령/구조 | 용도 | 특징 |
|---|---|---|---|
| CGI | Web Server → php-cgi |
과거 방식 | 요청마다 프로세스 생성 |
| FastCGI | Web Server → FastCGI process | 요청 전달 방식 | 프로세스 재사용 |
| FPM | Nginx → PHP-FPM worker | 운영 웹 요청 | PHP FastCGI worker pool 관리 |
| CLI | php artisan ... |
명령어, 큐, 스케줄 | FPM과 독립된 PHP 프로세스 |
| CLI server | php -S, php artisan serve |
로컬 개발 서버 | CGI/FPM이 아닌 PHP 내장 HTTP 서버 |
운영 Laravel 기준으로 가장 중요한 구분은 이것이다.
사용자 웹 요청 → PHP-FPM worker
큐/스케줄/명령어 → PHP CLI process
로컬 개발 서버 → PHP built-in server
php artisan serve는 CGI가 아니라 built-in server를 사용한다.php artisan queue:work 같은 CLI 명령은 FPM worker를 사용하지 않는다.FPM은 웹 요청을 처리하기 위한 PHP FastCGI worker pool이고, CLI는 터미널이나 프로세스 매니저가 PHP 바이너리를 직접 실행하는 별도 실행 경로다.
8. 참고자료
SAPI / PHP_SAPI
- PHP 공식 문서:
php_sapi_name()
현재 PHP가 사용하는 Server API, 즉 SAPI 이름을 반환한다. 예시 값으로cli,cli-server,fpm-fcgi,cgi-fcgi,apache2handler,phpdbg,embed등이 제시되어 있다. - PHP 공식 문서:
PHP_SAPI상수
현재 PHP 빌드의 Server API를 나타내는 상수.
- PHP 공식 문서:
CLI
- PHP 공식 문서: Using PHP from the command line
CLI SAPI의 목적은 PHP로 shell application을 개발/실행하는 것이며, CLI와 CGI는 서로 다른 SAPI라고 설명한다. - PHP 공식 문서: Command line options
php -f,php -r,php -S등 CLI 옵션 설명.-S <addr>:<port>가 built-in web server 실행 옵션이다.
- PHP 공식 문서: Using PHP from the command line
CGI
- RFC 3875: The Common Gateway Interface CGI Version 1.1
CGI를 HTTP 서버 아래에서 외부 프로그램을 실행하기 위한 인터페이스로 정의한다. - PHP 공식 문서: CGI and command line setups
PHP가 기본적으로 CLI와 CGI 프로그램으로 빌드될 수 있고, CGI processing에 사용될 수 있음을 설명한다. - PHP 공식 문서: Installed as CGI binary
CGI 방식으로 PHP를 설치했을 때의 보안 고려사항.
- RFC 3875: The Common Gateway Interface CGI Version 1.1
FastCGI
- FastCGI 원문 스펙: FastCGI Specification
FastCGI를 CGI의 open extension으로 설명하고, CGI와 달리 long-lived application process를 지원한다고 설명한다. - Nginx 공식 문서:
ngx_http_fastcgi_module
Nginx가 FastCGI server로 요청을 전달하는fastcgi_pass,fastcgi_param,fastcgi_read_timeout등을 설명한다.
- FastCGI 원문 스펙: FastCGI Specification
PHP-FPM
- PHP 공식 문서: FastCGI Process Manager FPM
FPM은 PHP의 주요 FastCGI 구현이며, heavy-loaded sites에 유용한 advanced process management, worker pool, slowlog, dynamic/ondemand/static child spawning 등을 제공한다고 설명한다. - PHP 공식 문서:
fastcgi_finish_request()
응답을 flush한 뒤에도 시간이 오래 걸리는 작업을 계속할 수 있는 FPM 관련 함수. 단, 워커 점유 관점에서는 주의가 필요하다.
- PHP 공식 문서: FastCGI Process Manager FPM
Apache module / mod_php
- PHP 공식 문서: Apache 2.x on Unix systems
--with-apxs2,LoadModule php_module modules/libphp.so,SetHandler application/x-httpd-php등을 통해 PHP를 Apache SAPI module로 붙이는 방식을 설명한다. - PHP 공식 문서: Installed as an Apache module
PHP가 Apache 모듈로 실행될 때 Apache 사용자 권한을 상속한다는 점을 설명한다.
- PHP 공식 문서: Apache 2.x on Unix systems
Built-in web server / CLI server
- PHP 공식 문서: Built-in web server
CLI SAPI가 built-in web server를 제공하며,php -S localhost:8000으로 실행한다. 개발/테스트용이며 public network에서 쓰지 말라고 명시한다. 기본적으로 single-threaded process라는 설명도 있다. - Laravel 공식 소스:
ServeCommand.phpserve명령의 설명은 “Serve the application on the PHP development server”이고, 실제serverCommand()가php_binary(),-S,host:port, router script를 반환한다. 즉php artisan serve는 PHP built-in server 래퍼다. - PHP 공식 문서: OPcache runtime configuration
opcache.enable_cli가 CLI 버전의 PHP에서 opcode cache를 켤 수 있는 설정임을 설명한다. 따라서 “CLI server는 캐시가 절대 없다”보다는 “기본/일반 개발 설정에서는 운영용 캐시·프로세스 관리 구조가 아니다”가 정확하다.
- PHP 공식 문서: Built-in web server
phpdbg
- PHP 공식 문서: Interactive PHP Debugger
phpdbg는 SAPI module로 구현된 PHP 디버깅 플랫폼이며 step debugging, breakpoint, opcode 출력 등을 제공한다.
- PHP 공식 문서: Interactive PHP Debugger
소중한 공감 감사합니다