PHP built-in web server

December 12, 2018 by Stefan Huber

PHP comes with a built-in web server for local development. The web server can be started and stopped via command line and has some basic configuration options.

Basic usage

After a successful installation of PHP the php command should be available on the terminal. This can be tested with a simple version check:

php --version

If PHP is installed correctly a version statement should be printed out on the terminal. For starting the built-in web server the S command option can be used. The option require the address and port as arguments. E.g. on localhost port 8080 the web server can be started with the following command:

php -S localhost:8080

The S option alone will take the current working directory as the webroot. This can be changed with the t option. E.g. if /var/www/demo should be the webroot the command can be used as follows:

php -S localhost:8080 -t /var/www/demo

The PHP interpreter is configured with a global php.ini file which holds all configuration options. For specifically overriding certain options for testing purposes or similar a php.ini file can be attached, which would override options from the global ini file. The example below would start the web server with a php.ini file from the current working directory.

php -S localhost:8080 -c php.ini

All files ending with a .php suffix will be processed as PHP code. The rest are served as files like on a normal web server. The built-in webserver can be stopped with the Ctrl-C shortcut.

Route file

Additionally, a route file can be attached to the web server. This can be used for url-rewriting or mocking certain requests. The route file is basically just a php script which either returns false if the request should be processed normally or otherwise provide an alternative response. The command for starting the web server with a route file looks like this:

php -S localhost:8080 -t /var/www/demo route.php

The command above would reference a route file named route.php inside the current working directoy. The following example of a route file would return a sample image (sample.png) for all image requests. All other requests are processed normally.


if ($_SERVER["REQUEST_URI"] != "/sample.png" &&
    preg_match('/\.(?:png|jpeg|jpg|gif)$/', $_SERVER["REQUEST_URI"])) { 
	header("Location: /sample.png");
} else {
	return false;

The route file can make the built-in web server act like a reverse proxy and internally request another resource e.g. from an external server. In the following example all requests to an api endpoint are rewritten to a different external api. The response is returned and for the client it looks like as if the request was handled by the built-in web server.


if (preg_match('/^\/api//', $_SERVER["REQUEST_URI"]) {
	$external_uri = '' . substr($_SERVER["REQUEST_URI"], 5);
	$method = $_SERVER['REQUEST_METHOD'];
	$opts = [
        "http" => [
            "method" => $method,
            "header" => "Content-type: application/json\r\n" ,
            "content" => file_get_contents('php://input')
    $context = stream_context_create($opts);
    header('Content-type: application/json');
	echo file_get_contents($uri, false, $context);
} else {
	return false;


When the built-in web server is started a log output is attached to the standard output of the terminal. By using the error_log function with message type 4 log statements can be printed out there. E.g. a route file with the following contents would print all Cookie headers from the request. This can be a useful feature for monitoring and debugging an application in development.

error_log(print_r(getallheaders()['Cookie'], true), 4);
return false;


The built-in web server for PHP is a helpful tool for setting up a development environment quickly. It offers options like attaching a route file or printing log statements to the standard output, which are quite useful during development. Together with SQLite PHP can be effectively used as is for local development. Personally, I think instead of using things like XAMPP, MAMP or WampServer the built-in web server should be preferred.

© 2020, Stefan Huber