At some point in your life as a professional working on the Web, you’re going to have to work with scripting languages. I know it’s a pain in the butt, but I resisted it as long as possible. But I eventually gave in, and so will you (cue dramatic music).
It’s really not as bad as it seems. I started on my journey toward scripting languages with server-side includes (SSI), a feature of Apache that lets you break HTML documents down into components that could be included by the server, similar to how modern templating systems like Twig or Smarty work. I’d been developing websites the old-old fashioned way, by editing individual HTML documents and uploading them to the web server. It was brutal, grueling work that caused me hours of grief whenever any changes needed to be made to the look and feel of a website. SSI allowed me to configure specific header and footer files and place them in a central location; this freed up my content from the presentation and made global look/feel updates quick and painless since I was now only editing a single global document.
As PHP grew in popularity and templating systems started gaining traction, the world moved on from SSI, which is no longer commonly used. Where SSI allowed me to separate my content from its presentation, PHP gave me the freedom to separate my content from its source. Scripting languages like PHP allow you to generate content dynamically, retrieve information from and store it on a database, accept and process user information, and even tell you when there’s something wrong with the website itself.
In this book, I focus on configuring Apache for two scripting languages: PHP and server-side JavaScript using the Node.js framework.
JavaScript has rapidly grown as a server-side language through the Node.js and React frameworks. Although it’s the language of choice for a fraction of sites compared to PHP, it’s being used by some notable folks, including Twitter, Spotify, The New York Times, and the Daily Mail.1 Many boot camps and web-development schools now prioritize teaching their students JavaScript over PHP.
Apache has also added support for several programming languages, such as Python, Ruby, C# (through the Mono framework), Lua, Perl, R, and TCL. But, as these aren’t as frequently used, I’ll leave it to other authors to give you a hand setting them up.
PHP
PHP has been around for a long time and is now a robust language. As of this writing, 78% of websites are built using a form of PHP, including Facebook, Instagram, Wikipedia, and Slack.2 Because it has been around for so long, it has gained a solid reputation among web developers as a reliable, stable, and fast language. It’s well established as a scripting language for the Web and will most likely be the language you encounter, especially if you are working with a CMS such as WordPress, Drupal, or Craft CMS.
Installing PHP
If you’re using XAMPP on Windows, congratulations, you’re done! You can move on to this chapter’s “Configuring PHP” section. XAMPP installs PHP alongside Apache and takes care of the configuration for you. It might still be useful to read through this section, however, if you want to make changes to PHP’s settings.
For the rest of you, I’m to walk through installing and configuring PHP on Apache, as it’s not included in a basic Apache installation. But no fear! It’s not hard!
Installing PHP on macOS
Apple used to include a default installation of PHP as a part of macOS. Unfortunately, as of macOS 12.0 Monterey, this is no longer the case. So, first things first. You need to get PHP installed! Like installing Apache, let’s use Homebrew to get PHP on our system.
This installs the most recent stable version of PHP on your system. As of this writing, that’s PHP 8.0.12. If you need an older PHP version for your projects, you can specify this as part of the install command with the @ modifier. For example, WordPress and Craft CMS both require PHP 7.4 and are not fully stable on PHP 8 (as of the writing of this book).
Installing PHP on Linux
This installs PHP and configures it for Apache, including editing the Apache configuration files for you to point to the correct location. At the end of the installation process, you are given the location of PHP’s configuration files. Jot these down in your notebook, so you can refer to them later (generally, they are stored in /etc/php by version number; for example, /etc/php/7.4/). Jot this directory down in your notepad. You’ll use this later. It’s worth noting that there are two configuration files to keep track of—one for the terminal (CLI) and another for Apache.
Configuring Apache for PHP
Now that you have PHP installed, you need to configure Apache to properly handle requests that need PHP to function. If you are using XAMPP on Windows, you can skip this section, as PHP is already configured in Apache.
On macOS and Linux, Apache is not automatically configured to support PHP, even when installing both. You need to configure Apache yourself using the following guides.
On macOS
Like other scripting languages, Apache supports PHP through an Apache module. In your httpd.conf, look for the “Dynamic Shared Object (DSO) Support” section. This is the section Apache uses to load libraries for additional functionality.
As of PHP 8, the module name no longer refers to the version of PHP installed. For the preceding, replace php7_module with php_module and libphp7.so with libphp.so.
This instructs Apache to first look for a file named index.php when a directory is requested, and if no index.php file is found, to next look for index.html as a fallback. If neither file is found, Apache returns an error or shows a directory listing if the <Directory> section sets Indexes as an Option (see Chapter 2 for more information on this).
File Extension Alternatives
Extension | Description |
---|---|
.phar | PHP Archive. It allows a PHP application and its supporting files (such as CSS and images) to be bundled as a single archive file. |
.phtml | Used when there is little or no data logic. These files tend to focus on presentation instead of providing functionality. It’s a very old file extension used in PHP 2.x and not very common in modern applications. |
.phps | PHP Source files. These are not functional PHP files and are intended to only display the included PHP source code as HTML. |
.phar
.php
.phtml
The second section prevents Apache from rendering files with the .phps file extension. Files with this extension contain PHP code but are intended to be displayed as plain text. This isn’t recommended, so I suggest keeping this section in.
.phar
.php
.phps
.phtml
This instructs Apache to load the file’s contents as part of its configuration.
On Linux
The PHP install script you ran on Ubuntu creates two configuration files in /etc/apache2/mods-available: php7.4.load and php7.4.conf. For Apache to include these files in its configuration, you must ensure they are set up in /etc/apache2/mods-enabled/. This can be accomplished by either copying the files or creating a symbolic link (the preferred method).
Configuring PHP
Now that you have PHP installed and set up within Apache, you should take some time to update the standard configuration. This includes making configuration changes for things such as upload file size and memory usage and enabling some extensions that will be useful for later development.
Updating Default Configuration
By default, the configuration for PHP is pretty decent. You don’t have to make any changes to start developing locally, but I recommend making the following changes to provide a more flexible development environment.
Whenever you change the configuration values or add new directives in your php.ini configuration file, you need to restart Apache for the changes to take effect.
Increasing the Memory Usage Limit
When using a development environment, you don’t need to be as concerned about memory usage as you would be in a staging or production environment. PHP is configured by default to use 128 MB of memory for any script’s execution.
If you are working with code that heavily uses data or complex data models, you may want to increase the amount of memory used to help debug your code.
This will, to no surprise, increase the amount of memory available to a script to 1 GB. I wouldn’t recommend going this high, as this can cause problems when moving to production. You should instead try reducing the amount of memory your script takes up. I recommend starting with 128 MB and increasing if you see memory errors in your error logs.
Increasing the Upload File Size
The default upload limit in PHP is 2 MB, which often doesn’t work well for projects such as content management systems. As such, you want to increase the maximum allowed file size for uploading by editing the upload_max_filesize directive.4
You can, of course, edit this as you see fit.
Configuring Noisy Error Reporting
Production servers are generally configured to disable or heavily minimize error reporting so that log files do not grow too large. But this also means that valuable troubleshooting data is lost.
Since you’re setting up a development environment, you want as much error reporting as possible. This creates “noisy” error logs, which means more information is available to help debug our programming problems.
First, you need to ensure that error reporting is turned on. Open your php.ini and search for the following: display_errors.5 This directive controls whether errors are reported to the page when viewing a script in the browser. By default, this is set to On, but it is often changed to Off for production so that errors are not displayed to the end user, which might create confusion.
Next, let’s configure PHP’s level of logging when encountering problems. This is configured through the error_reporting directive.6
If you have installed PHP 8, you can safely ignore this section. PHP 7, however, is configured to record all errors except notices, coding standards warnings, or code that will be deprecated in future versions of PHP. This is great for production, where you only want to report when something fatal happens.
This configures PHP to report any warnings, errors, and notices it encounters when attempting to execute a script.
Increasing Max Execution Time
Most servers running websites are purpose-built for that role. The resources available are dedicated to Apache, and whatever scripting languages are used. Often, even database services are set up on separate servers.
If you’re setting up Apache on your laptop or desktop, that is not the case. Apache, databases, and scripting languages will all compete for resources alongside your editing environment, communications tools, and browsers, which means that scripts take a little longer to run than they would on a dedicated or virtual server.
If you find that your PHP scripts are failing with a timeout error, then you need to adjust your timeout through the max_execution_time directive. This directive defines how long PHP waits, in seconds, until stopping the execution of the script. By default, this is set to 30 seconds, which is fine for most operations. However, if you are working with a lot of data or a lot of operations at once or are pulling data from an external source, you may want to increase this amount. Open the php.ini used by Apache, and search for the max_execution_time directive.
Installing PHP Extensions
For Windows users who have installed XAMPP, installing PHP extensions that are not included with XAMPP is a bit of a tricky affair. Best to put this book down for a moment and hit up your favorite search engine if you need to install a non-standard PHP extension.
Like Apache, PHP adds functionality through a module-based system. In PHP, these are known as extensions. There are extensions available for caching, connecting to databases, manipulating graphics files, and parsing data.
cURL
GD Graphics Library
MySQLi (or MariaDB)
PDO::MySQL
To install an extension, open php.ini and search for the “Dynamic Extensions” section. Here, you see a list of extensions commented out with a semi-colon, such as ;extension=curl.
cURL
GD Graphics Library
JSON (included in PHP 8, but a separate extension in earlier versions of PHP 7)
MBString
PDO::MySQL
Recommended php.ini
The following is an example of php.ini’s contents. Several additional PHP directives can be included in this file, but the following should be configured as part of any PHP installation. I included a description of what each directive does, along with recommended values.
Any time you make changes to your PHP configuration, you need to restart Apache.
Testing It Out
This contains a wealth of information about your PHP configuration, including its version, installed extensions, and the Apache DocumentRoot. It’s extremely useful as a troubleshooting tool in development environments.
Configuring Node.js on Apache
When I wrote the first edition of this book in 2004, PHP was an up-and-coming scripting language that was beginning to eat into the dominance of Perl, which was the more prevalent language for building dynamic, functional websites at the time. Writing this chapter in 2022, I feel a bit of deja vu as I discuss Node.js and PHP. PHP is still, by far, the more prevalent scripting language for building web applications and websites, but Node.js is starting to eat away at that.
Node.js applications operate differently from PHP-based ones; where PHP-based sites require a web server such as Apache or nginx to handle the traffic, Node.js applications are built to be self-sufficient applications in their own right, managing network traffic and requests internally. When setting up a Node.js application for production, they’re often set up as system services so that the Node.js application restarts when the system is hosted on reboots.
This starts up a server built into the node application, which listens for connections on a specified port, such as 3000, waiting for users to access the application.
And, for the most part, this is fine for development. However, you might want something running a bit more permanently, where you don’t have to keep a terminal window up and running, ensuring that the node application isn’t interrupted. You might also want to run multiple Node.js applications without memorizing what port each is running on.
This is where Apache can become very useful. You can combine Apache’s virtual hosts with its ability to act as a reverse proxy or gateway server.
Configuring Your Node.js Application for Apache
Node applications are not, by their nature, persistent. Each Node application runs as its own runtime executable, separate from the server it is deployed to. On the one hand, this is extremely convenient, as you do not necessarily need to configure a full web server to deploy your Node application. However, it also means that your Node application is only accessible so long as that runtime is active. You must manually restart it if it’s interrupted for any reason, including a reboot.
Installing pm2
To be always available, you need to run the Node application as a service. There are a couple of options to do this, but the simplest is to use PM2, a process manager for Node.js applications that allows you to easily turn them into services.
You may need to run this as sudo on Linux
This installs PM2 globally.
Configuring the Application
This very simple program listens for a connection on port 3000 and outputs “Hello world!” in response. You’re not going to win any awards, but it’ll do for our example.
You can test to make certain that things are working by typing node app.js, then visiting http://localhost:3000/ in your browser.
Adding Your Application as a Service
Configuring Apache’s Reverse Proxy
Here’s where the magic comes in. By combining what you’ve learned about virtual hosts with a feature in Apache that lets you configure it as a gateway for other services, you can create an always-up development service that allows for memorable domain names instead of remembering a set of cryptic port numbers for your Node.js applications.
The full documentation for Apache’s reverse proxy is at https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html if you are interested in learning more. However, you should only need what’s on the following pages for this use.
Enabling Apache’s Proxy Modules
Apache’s reverse proxy functionality is handled through two modules: mod_proxy and mod_http. These need to be enabled in your Apache installation to set up a persistent Node.js site.
On macOS and Windows
Test your configuration and restart Apache for the changes to take effect.
On Linux
Open a terminal and navigate to /etc/apache2/mods-enabled.
This adds in a call to the LoadModule directive for the mod_proxy.so and mod_proxy_http modules in Apache. You’ll configure these later in your virtual host configuration.
Test your configuration and restart Apache for the changes to take effect.
Creating a Virtual Host Configuration
Testing It Out
Configuring React Apps on Apache
If you’re building a React application and want to use Apache’s virtual hosts to allow for simplified domain names, you have two options.
First, follow the directions for Node.js applications, and configure Apache as a reverse proxy that accesses the Node Express server included in your React application.
Alternatively, you can configure Apache to point DocumentRoot to your React application’s public folder. If you follow this path, ensure that Apache is configured to use gzip compression. To do so, you want to enable the mod_deflate module in Apache.
Summing It Up
Phew! You made it. You learned about configuring Apache to support PHP and Node.js in this chapter. For PHP, you now know how to install and configure PHP and then configure Apache to support it. Node.js was a little trickier, but you learned how to support a persistent virtual domain that connects to the Node.js server through a proxy.
The next chapter discusses one of the most important aspects of Apache’s configuration: setting it up for secure communications on the web.