How does apache serve php?
Skip to content
Title: Configuring an Apache/PHP Application Server We are setting up an Apache/PHP application server using the minimal number of
modules necessary. A bare bones Apache server is suitable for delivering static files. More complex applications rely on dynamic content. This requires an extension of the server. A very fast and secure application server can be implemented using suEXEC, an external FastCGI daemon and PHP. This is by far not the only option and also likely not the most widespread one in a corporate
environment. But is a very simple architecture perfectly suited for a test system. We’ll configure the web server to start off with, aware of the fact that it is not yet capable of running in this configuration. Based on the minimal web server described in Tutorial 2, we’ll configure a very simple application server in the
conf/httpd.conf_fastcgid file. I will no longer be discussing the overall configuration, but will instead only be focusing on the differences from Tutorial 2. There are three new modules: Added to the suEXEC and FCGI modules is the Mime module, which enables us to assign the .php file suffix to the FCGI daemon. It is assigned using the AddHandler directive. The /apache/htdocs directory now needs the
additional ExecCGI option. And finally, the FCGIWrapper. This is the connection between the web server and the FCGI daemon yet to be configured. Once the first request using the .php suffix is received by the web server, the server calls a wrapper script, starting the FCGI daemon, which from this time on handles the PHP requests. FastCGI is a method for executing dynamic program code from a web server. It is a very
fast method which for the most part leaves the server untouched and runs the application on a separate daemon. To increase the speed, FastCGI provides multiple instances of this daemon, allowing requests to be processed without having to wait. In practice, this is a promising gain in performance and, more importantly, an architecture that saves memory, as will be discussed in more detail below. We now have to compile two missing modules and deploy other components for the FCGI daemon. Let’s start with the suEXEC module. An Apache web server was compiled in Tutorial 1. However, although the --enable-mods-shared=all option was used, suexec has not been compiled yet. It seems, the module is so special that it can’t be compiled as a default module, although it is present in the source code. The web server
configured in Tutorial 2 runs as user www-data or, depending on configuration, as any other dedicated user. We would like to further restrict our dynamic application to have the separate daemon run as an additional, separate user that is introduced in one of the next steps. The suEXEC module makes this possible for us. It is not absolutely required. But it adds a bit more security with little extra effort. Let’s enter the directory with the Apache source code and compile the server once more.
Besides configure, which we are familiar with, three options have been added for handling suexec. Enable-suexec is self-explanatory, with-suexec-caller we tell the conscientious module that only the user www-data is to be given permission to access the program behind the module. We are after all telling the module where scripts being called are located. For simplicity’s sake let’s use the existing bin directory. suexec is however a bit fussy and we are unable to use the symlink. So it will have to be the fully qualified path. If successfully configured, the command line above will start the compiler and after being successfully concluded will install the newly compiled server. By the way, if you make a mistake in the configuration above and want to assign suexec different compiler constants, you’ll first have to clean out the compiler environment before compiling again. The new options will otherwise be ignored. We can do this via the make clean command in front of configure or by manually deleting the files support/suexec, support/suexec.lo and support/suexec.o, which is faster, because the whole web server no longer has to be built from scratch. Step 3: Downloading and compiling the FastCGI moduleThe FastCGI module is managed by Apache. But it is not part of the normal source code for the web server. So, let’s download the source code for the additional module and verify the loaded checksum over an encrypted connection.
We again expect an OK. When it is correctly returned, it’s time for unpacking, compiling and installing.
The configure command has a slightly different format here, because the FCGI module is a module dependent on Apache. That’s why we are using APXS, the Apache Expansion Tool, part of the server compiled in Tutorial 1. Unfortunately, make install will partly destroy some of the ownerships we have set. They will have to be adjusted afterwards.
The Apache user also needs access to a directory for him to create sockets, enabling communication with the FCGI daemon. We’ll create the directory and transfer ownership to it directly.
Step 4: Installing and preconfiguring PHPUp till now we have been compiling all of the software piece by piece. But for the entire PHP stack a limit has been reached. No one should be prevented from compiling PHP on his own, but we are concentrating on the web server here and for this reason will be using this piece of software from the Linux distribution. In Debian/Ubuntu the package we need is php7.0-cgi, which comes along with php7.0-common. Properly configuring PHP is a broad topic and I recommend consulting the relevant pages, because an improperly configured installation of PHP may pose a serious security problem. I don’t wish to give you any more information at this point, because it takes us away from our actual topic, which is a simple application server. For operation on the internet, i.e. no longer in a lab-like setup, it is highly recommended to become familiar with the relevant PHP security settings. Step 5: Creating the CGI userAbove it has already been discussed that we are planning to start a separate daemon to process PHP requests. This daemon should be started via suexec and run as separate user. We create the user as follows:
It can be expected for a warning to appear concerning the presence of the /apache/htdocs directory. We can ignore it. Step 6: Creating a PHP wrapper scriptIt is normal to use a wrapper script for PHP and FCGI to work together. We already set this up in the Apache configuration above. The web server will invoke only the script, while the script takes care of everything else. We place the script as intended in /apache/bin/php-fcgi-starter/php-fcgi-starter. The subdirectory isn’t needed, because suexec requires the directory to be owned by the preconfigured user and we don’t want to assign ./bin completely to the new user. So, let’s create the subdirectory:
We now have to put a starter script in this directory. Since we have already assigned fcgi-php to the user, the root user will have to create the script. Or be copied by him to this location. Creating a script in a directory that we no longer own is challenging. We’ll solve this with a trick using cat and a subshell. Here’s the trick, followed by the script. (Input in cat is ended via CTRL-D).
What are we defining here? We are telling PHP where to find its configuration, setting the maximum number of requests for an FCGI to 5,000 (after which it is replaced by a fresh process), defining the number of process children to 5 and executing PHP at the end. Now don't forget to assign the script to the FCGI user and make it executable: Step 7: Creating a PHP test pageTo finish things off, we should now create a simple PHP-based test page: /apache/htdocs/info.php. Step 8: Trying it outThat was everything. We can now start our web server and try it out.
Our test script is available at http://localhost/info.php. phpinfo gives you a comprehensive status report in your browser. If an error message results from starting the server or invoking the URL, the server’s error log or the separate suexec log in _logs/suexeclog may prove helpful. Errors are typically related to ownership of and permission to access directories and files. Here again is a summary of the relevant files and their owners:
Of note is the suid bit on the suexec binary. Step 9 (Goodie): A little performance testCompared to Apache with integrated PHP, the application server built here is very high performance. A little performance test can illustrate this. We start our web server in daemon mode and use ApacheBench to put it to the test it with 5 users. The -l option is new. It instructs the tool to ignore deviations in the length of the responses. This is because the page is generated dynamically and the content, as well as its length, will of course be a bit different now and then. We again quit the server following the performance test.
In most cases ab has the following output:
That‘s 389 dynamic requests per second. Which is a lot. Especially considering that the result is from a small test computer. On a modern production-size server performance many times this can be achieved. What’s remarkable isn’t the speed of the system, it’s memory usage. Unlike an application server with integrated PHP module, we have separated the PHP stack here. This gives us an Apache web server able to use Event MPM. In an integrated setup we would have to use the Prefork MPM, which works with memory-intensive server processes and not server threads. And each of these processes would then have to load the PHP module, regardless of the fact that most requests are normally attributed to static application components such as images, CSS, JavaScripts, etc. On my test system each Prefork Apache process, including PHP, brings a resident size of 6 MB. An event process with only 4 MB means a substantial difference. And outside of this, the number of external FCGI processes will remain significantly smaller. NewsletterDid you enjoy this tutorial? If so, why don't you subscribe to our newsletter to learn about new content on this site?References
License / Copying / Further useThis work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Changelog
How does Apache run PHP?Apache normally serves files by fetching the file and sending the stream down the HTTP connection. With PHP, however, Apache fetches the file, pipes it into the PHP binary, and sends the output stream from the command down the HTTP connection.
Does Apache handle PHP?Apache does not natively support PHP scripts without a special module. The module that tells Apache how to handle PHP scripts is referred to as a PHP handler. Without a properly configured module, Apache will just send you the PHP file as a download since it doesn't know what else to do.
How does PHP run on server?If a PHP file is given on the command line when the web server is started it is treated as a "router" script. The script is run at the start of each HTTP request. If this script returns false , then the requested resource is returned as-is. Otherwise the script's output is returned to the browser.
How does browser run PHP?Your browser can handle HTML on its own, but it has to make a request to a web server to deal with PHP scripts. That server can take your PHP scripts and run them, and then take the response and send it back to your browser. Your browser can then understand and handle the response.
|