ngx-php: running embedded PHP inside nginx instead of beside it
ngx-php - Embedded php7 or php8 scripting language for nginx module. Mainline development version of the ngx-php.
At a glance
- What is it?
- ngx-php is an nginx module that executes PHP 7 and PHP 8 code inside the worker process, so the script shares the request context and can use non-blocking I/O. The README is explicit that it is Linux only, that it does not replace php-fpm, and that global state is unsafe across requests.
- Who is it for?
- ngx-php fits a Linux operator who wants PHP inside nginx rather than behind it, and who needs the script to reach the request context or to use non-blocking I/O without a sidecar. It does not fit a hosting environment on Windows or macOS, and it does not fit an application that relies on shared global state between requests, since the README calls that unsafe.
- Can I use it commercially?
- Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 134 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
PHP in the worker process, not behind a FastCGI socket
ngx-php is an extension module of the nginx web server that implements embedded PHP 7 and PHP 8 scripting to process nginx locations and variables. The distinction from the usual arrangement is the whole point. With php-fpm, nginx proxies the request to a separate process over a socket, and with mod_php the interpreter is loaded into Apache. Here the script runs inside the nginx worker, which means it can read and write nginx variables directly and can issue I/O without blocking the worker. The README says the project draws on the design of ngx_lua, the OpenResty module, and is committed to providing non-blocking web services with performance advantages over php-cgi, mod_php, php-fpm and hhvm. It also says ngx-php does not want to replace anything, just wants to provide a solution, and that a legacy ngx_php5 branch exists holding earlier code practices.
The global state warnings are the most useful paragraph in the README
There is a section titled what is different with official PHP, and it is short and unflattering to conventional PHP habits. A global variable is unsafe in a per-request model. A static variable of a class is unsafe in a per-request model. Singleton mode should not be designed for. And the native IO function works fine but slows down nginx. All four follow from the architecture. Because the script executes inside a long-lived worker process rather than in a fresh interpreter per request, state that PHP programmers assume is reset between requests is not reset. A static counter increments across requests. A cached lookup in a global stays cached. The IO point is the flip side of the non-blocking design: a blocking read inside the worker stalls every other request that worker is handling, so the module gives you coroutine-style primitives instead and expects you to use them.
Building it means compiling PHP with embed and nginx with the module
The installation path is a source build, and it has three parts: PHP with the embed SAPI, nginx, and the module itself. The compile instructions download a PHP source tarball, configure it with --enable-embed, and make install, then clone the module and download nginx sources. Four environment variables tell the nginx configure step where PHP lives, PHP_CONFIG, PHP_BIN, PHP_INC and PHP_LIB, and the configure line adds the module twice, once for the bundled NDK under third_party and once for ngx-php itself, with a linker option pointing at the PHP library directory.
$ export PHP_CONFIG=/path/to/php/bin/php-config
$ export PHP_BIN=/path/to/php/bin
$ export PHP_INC=/path/to/php/include/php
$ export PHP_LIB=/path/to/php/libThe module depends on the NDK, the nginx development kit, and that dependency is why the two load_module lines in nginx.conf are mandatory.
load_module modules/ndk_http_module.so; load_module modules/ngx_http_php_module.so;
Ordering matters here: the NDK module has to be loaded first, and if you skip it the PHP module will fail to initialise.
content_by_php_block puts script inside a location
The nginx configuration syntax is the interface you will spend your time in, and the example config shows the pattern clearly.
location /php {
content_by_php_block {
echo "hello ngx-php";
}
}The content_by_php_block directive takes a block of PHP and runs it when the location matches. Alongside it, the README documents a set of nginx-facing functions for PHP: ngx_request_document_uri to read the request URI, ngx_query_args and ngx_post_args for the query string and the POST body, ngx_var_get to read a variable you set with the set directive, ngx_sleep to pause, and a socket API with ngx_socket_create, ngx_socket_connect, ngx_socket_send, ngx_socket_recv and ngx_socket_close. The socket functions are the ones that show the non-blocking model in practice, since the example sends an HTTP request with a yield on each step.
The Docker image compiles nginx and PHP into two Alpine stages
The Dockerfile is a good way to understand the build, because it shows the module compiled as a dynamic module rather than a static one. The first stage starts from nginx:stable-alpine, installs the build toolchain and php7-dev with php7-embed, then reads the nginx version from the base image, downloads the matching nginx source, and configures it with the base image's own configure arguments minus any dynamic module flags, adding the NDK and ngx-php as dynamic modules. It makes the build and copies out ndk_http_module.so and ngx_http_php_module.so into a modules directory. The second stage is again nginx:stable-alpine, this time installing only php7-embed, patching nginx.conf to include the modules directory, and writing a php.conf with the two load_module lines.
$ docker build -t nginx-php7 .
$ : "app.conf: Create nginx config"
$ docker run -p 80:80 -v $PWD/app.conf:/etc/nginx/conf.d/default.conf nginx-php7The pinned nginx:stable-alpine base and the runtime that carries only the compiled modules and php7-embed is a sensible split for image size.
Linux only, with a bounded version matrix
The requirements are three lines and they rule the project out for a lot of people. Linux only. PHP 7 through PHP 8.3. And nginx from 1.4.7 to 1.26.x. That is a wide nginx range, which reflects how stable the module interface has been, and a PHP range that stops at 8.3 rather than tracking the newest release. The macOS story is handled with a separate installation document in the docs directory rather than in the README, and the CentOS and RedHat 7 and Ubuntu sections both show a package route where the distro provides an nginx module package, with the Ubuntu route pulling PHP 7.4 packages from the ondrej PPA along with the embed library. The repository also has a Dockerfile at the root, a ChangeLog, a config directory, a src directory, a t directory and a utils directory, plus docs with Chinese-language installation notes for macOS.
Editorial conclusion
ngx-php fits a Linux operator who wants PHP inside nginx rather than behind it, and who needs the script to reach the request context or to use non-blocking I/O without a sidecar. It does not fit a hosting environment on Windows or macOS, and it does not fit an application that relies on shared global state between requests, since the README calls that unsafe. Verify first that your nginx and PHP versions fall inside the stated ranges, read the notes on global variables and static class properties before you port existing code, and test the non-blocking API on your own hardware, because the whole value proposition depends on it working as documented.
Frequently asked questions
What is ngx-php and how is it different from php-fpm?
It is an nginx extension module that runs embedded PHP 7 and PHP 8 script inside the nginx worker to process locations and variables, rather than proxying requests to a separate FastCGI process. The README says it draws on the design of ngx_lua and aims at non-blocking web services.
What are the requirements for ngx-php?
Linux only, PHP 7 through PHP 8.3, and nginx from 1.4.7 to 1.26.x. Installation is a source build of PHP with the embed SAPI plus an nginx compiled with the module and the bundled NDK, and the README also documents CentOS, Ubuntu, macOS and Docker routes.
Is it safe to use global variables in ngx-php?
No. The README lists what differs from official PHP and states that a global variable is unsafe in a per-request model, that a static variable of a class is unsafe in a per-request model, and that singleton mode should not be designed for. The native IO function works but slows down nginx, so non-blocking primitives are provided instead.
How do I run PHP in an nginx location with ngx-php?
Use the content_by_php_block directive inside a location block, and load both modules at the top of nginx.conf with load_module, with ndk_http_module.so first and ngx_http_php_module.so second. The module exposes nginx functions to PHP such as ngx_request_document_uri, ngx_query_args, ngx_post_args and ngx_var_get.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rryqszq4-ngx-php)Was this useful?