Managing PHP Web Servers
Last updated April 10, 2025
Table of Contents
Heroku supports Apache HTTPD 2.4 and Nginx as dedicated web servers. For testing purposes, users can also use PHP’s built-in web server, although it’s not recommended. To see available web server versions, see Heroku PHP Support Reference.
In the absence of a Procfile
entry for the “web” dyno type, the Apache Web server will be used together with the PHP runtime.
Apache
Apache interfaces with PHP-FPM via FastCGI using mod_proxy_fcgi
.
To start Apache together with PHP-FPM and correct settings, use the heroku-php-apache2
script:
web: heroku-php-apache2
By default, the root folder of your project will be used as the document root. To use a subdirectory, you can pass the name of a subfolder as the argument to the boot script, for example “public_html”:
web: heroku-php-apache2 public_html/
You can use regular .htaccess
files to customize Apache’s behavior, for example for URL rewriting. For additional details on this and other options to customize settings for Apache, refer to the corresponding Dev Center article.
Nginx
Nginx interfaces with PHP-FPM via FastCGI.
To start Nginx together with PHP-FPM and correct settings, use the heroku-php-nginx
script:
web: heroku-php-nginx
By default, the root folder of your project will be used as the document root. To use a subdirectory, you can pass the name of a subfolder as the argument to the boot script, for example “public_html”:
web: heroku-php-nginx public_html/
For additional details on different ways of customizing settings for Nginx, refer to the corresponding Dev Center article.
PHP Built-in Web server
For testing purposes, you can start PHP’s built-in Web server using the php -S
command. This command requires an argument that specifies what interface and port to bind to for handling requests.
The interface to use depends on the generation of your app. The port is dynamic, and available in an environment variable named $PORT
, which can be referenced in the command string.
It’s important to bind to all IP interfaces, and not e.g. localhost
, otherwise Heroku’s routing won’t be able to forward requests to the web server!
You can pass an alternative document root using the -t
option, or specify a a router script to process requests as an argument. For details, refer to the PHP project’s documentation for the built-in Web server.
Cedar
The Cedar generation of the Heroku platform uses IPv4. A web process must bind to “any” interface using the IPv4 address “0.0.0.0
”.
Use the following Procfile
entry for the built-in PHP web server on a Cedar app:
web: php -S "0.0.0.0:${PORT}"
To use a subdirectory of your app as the document root, for example public_html
, specify it using the -t
option:
web: php -S "0.0.0.0:${PORT}" -t public_html/
Fir
The Fir generation of the Heroku platform uses IPv6. A web process must bind to “any” interface using the IPv6 shorthand address “::
”.
IPv6 addresses use colons (“:
”) as the group separator. Colons are also used, for example, to separate the host and port parts in URLs, or anywhere an address:port
notation is used, such as in the -S
option of php
. In these cases, IPv6 addresses are wrapped in square brackets.
Many command shells treat square brackets as special characters, so such an address must be wrapped in quotation marks.
Since the port number a Heroku app must bind to is available in the $PORT
environment variable, double quotation marks are used to allow the variable to expand.
Use the following Procfile
entry for the built-in PHP web server on a Cedar app:
web: php -S "[::]:${PORT}"
To use a subdirectory of your app as the document root, for example public_html
, specify it using the -t
option:
web: php -S "[::]:${PORT}" -t public_html/