© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
D. J. HarknessApache Essentialshttps://doi.org/10.1007/978-1-4842-8324-0_4

4. Scripting Languages

Darren James Harkness1  
(1)
Port Coquitlam, BC, Canada
 

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.

Open your terminal application and type the following.
brew install php

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).

To install PHP 7.4, your command would be the following.
brew install [email protected]
Like the install, this throws a bunch of text onto your screen. That’s OK. we’re just concerned with the end bit in the Caveats section, paying attention to the full path for the php7_module. and the path for the PHP configuration files (usually in /usr/local/etc/php/). Homebrew also reminds you of what needs to be configured in Apache. But don’t worry. I cover that in the “Configuring PHP” section of this chapter. Jot these down in your notebook, however. You’ll need these paths later.
==> Caveats
To enable PHP in Apache add the following to httpd.conf and restart Apache:
    LoadModule php7_module /usr/local/opt/[email protected]/lib/httpd/modules/libphp7.so
    <FilesMatch .php$>
        SetHandler application/x-httpd-php
    </FilesMatch>
Finally, check DirectoryIndex includes index.php
    DirectoryIndex index.php index.html
The php.ini and php-fpm.ini file can be found in:
    /usr/local/etc/php/7.4/
[email protected] is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have [email protected] first in your PATH, run:
  echo 'export PATH="/usr/local/opt/[email protected]/bin:$PATH"' >> ~/.profile
  echo 'export PATH="/usr/local/opt/[email protected]/sbin:$PATH"' >> ~/.profile
For compilers to find [email protected] you may need to set:
  export LDFLAGS="-L/usr/local/opt/[email protected]/lib"
  export CPPFLAGS="-I/usr/local/opt/[email protected]/include"
To restart [email protected] after an upgrade:
  brew services restart [email protected]
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/[email protected]/sbin/php-fpm --nodaemonize
==> Summary
&#x1F37A;  /usr/local/Cellar/[email protected]/7.4.27: 498 files, 72.3MB

Installing PHP on Linux

Installing PHP for Apache on Linux is a pleasure if you use a distribution with package management, such as Ubuntu. To install the latest stable PHP and a default configuration for Apache, simply open a terminal and type the following.
sudo apt-get install libapache2-mod-php

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.

At the end of this section, add the following line, replacing 7.4 with the version you have installed (e.g., [email protected] for PHP 8.1). The path for this module file is what you jotted down from Brew’s Caveats section in the previous installation step.
LoadModule php7_module /usr/local/opt/[email protected]/lib/httpd/modules/libphp7.so
Note

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.

That load the PHP module when Apache starts up. However, you still need to configure Apache to understand when to invoke the PHP module. First, you need to add index.php as a valid index file that Apache should load when requesting a directory. Search for the DirectoryIndex directive and replace it with the following.
DirectoryIndex index.php index.html

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).

Next, you need to configure Apache’s handling of PHP files. In general, PHP files use the .php file extension. However, some alternatives are used alongside it, as listed in Table 4-1.
Table 4-1

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.

This configuration can be added by creating a new file in the extra directory called httpd-php.conf. Put the following in this file.
<FilesMatch ".+.ph(ar|p|tml)$">
    SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+.phps$">
    SetHandler application/x-httpd-php-source
    # Deny access to raw php sources by default
    # To re-enable it's recommended to enable access to the files
    # only in specific virtual host or directory
    Require all denied
</FilesMatch>
# Deny access to files without filename (e.g. '.php')
<FilesMatch "^.ph(ar|p|ps|tml)$">
    Require all denied
</FilesMatch>
This is a bit more than what’s recommended after installing PHP using Homebrew but offers a bit more security and stability. The first section of this configuration configures Apache to invoke the PHP module for any files that use the following extensions.
  • .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.

Finally, the last section denies access to a set of dot files (files with an extension but no filename). Generally, you should deny access to such files because they could contain secure or sensitive information.
  • .phar

  • .php

  • .phps

  • .phtml

Once you have saved the httpd-php.conf file, you need to go back to your httpd.conf and let Apache know to include its contents as part of its configuration. At the bottom of httpd.conf, enter the following (replacing php7_module with php_module for PHP 8.x installations).
<IfModule php7_module>
Include /usr/local/etc/httpd/extra/httpd-php.conf
</IfModule>

This instructs Apache to load the file’s contents as part of its configuration.

Once all this is complete, you can check the config using the following.
apachectl configtest
Then restart Apache through the following command.
brew services restart httpd

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).

To create a symbolic link, open your terminal and navigate to /etc/apache2/mods-enabled. Enter the following commands.
sudo ln -s /etc/apache2/mods-available/php7.4.load php7.4.load
sudo ln -s /etc/apache2/mods-available/php7.4.conf php7.4.conf

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.

Note

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.

You can do this through the memory_limit configuration directive by specifying a different memory limit.3 To make things easier, you can append a size modifier to the end of the number, using M for megabytes and G for gigabytes.
memory_limit = 512M
This sets the memory limit for each script execution to 512 MB. If you wanted to increase this to a full gigabyte of memory, you’d instead use the following.
memory_limit = 1G

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

Like the memory_limit directive, you can use a size modifier appended to the number, using M for megabytes and G for gigabytes. Most importantly, you don’t need a huge file size limit set. However, you may work with PDFs or other documents that take up space. I’d suggest setting this to 200 MB, using the following.
upload_max_filesize = 200M

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.

Let’s ensure that the directive is configured like the following.
display_errors = On

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.

On your development server, however, you want as much information as possible, since it may be useful for troubleshooting later. Search for the error_reporting directive (it should be near the display_errors directive) and modify it to match the following.
error_reporting = E_ALL

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.

Here’s an example that sets the timeout to 60 seconds.
max_execution_time = 60

Installing PHP Extensions

Note

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.

I’d recommend installing the following commonly used extensions.
  • 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.

Find the extension you wish to enable and remove the semi-colon. For the recommended modules, ensure the following is included in the “Dynamic Extensions” section.
extension=curl
extension=gd2
extension=mysqli
extension=pdo_mysql
Your projects might require additional extensions to be enabled, such as gettext or intl. For example, Craft CMS requires the following PHP extensions to be enabled to support its functions that are not enabled by default.
  • 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.

Note

Any time you make changes to your PHP configuration, you need to restart Apache.

; Turns on PHP's scripting engine
engine = On
; Enables or disables PHP short tags. These are not generally
; recommended, as they may create issues with other file formats,
; such as XML.
short_open_tag = Off
; Configures how much output data, in bytes, is buffered before being
; sent in response to to a browser's request. 4096 bytes is recommended
output_buffering = 4096
; Configures which PHP functions are disabled. This is useful for
; Apache-based installs, where you do not want to open access to
; powerful and potentially damaging functions.
disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
; Configures the amount of time, in seconds, PHP waits on a script
; before failing and reporting an error. Default is 30 seconds. For
; development environments, it may be useful to increase this to 60
; seconds.
max_execution_time = 60
; Configures the amount of memory available to a running PHP script.
; By default, this is 128 megabytes, but should be increase for data-
; heavy applications.
memory_limit = 128M
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Configures which errors PHP reports. Production usually ignores
; deprecation errors, compatibility notes, and notices. For a
; development environment, we want to report everything.
error_reporting = E_ALL
; Enables or disables errors being returned as part of its output. By
; default this is disabled, reporting errors only to the log files. For
; development environments, it is often useful to display these errors
; within the browser.
display_errors = On
; Enables or disables logging of errors to Apache.
log_errors = On
;;;;;;;;;;;;;;;;;
; Data Handling ;
;;;;;;;;;;;;;;;;;
; Determines which super global arrays are registered when PHP starts.
; The below registers $_GET, $_POST, $COOKIE, and $SERVER
variables_order = "GPCS"
; Determines the order data is registered into the $_REQUEST super
; variable. This places GET first, and PUT second
request_order = "GP"
; Enables or disables the $argc and $argv variables. These are mostly
; used when a PHP script is used from the command line. Since Apache
; doesn't work this way, I recommend disabling them to increase
; performance.
register_argc_argv = Off
; Enables or disables Just In Time processing for the $_REQUEST and
; $_SERVER variables. This means they aren't created until they're
; used in the script, increasing performance.
auto_globals_jit = On
; Configure the maximum size of POST data. The default is 8 megabytes,
; which is generally considered sufficient.
post_max_size = 8M
; Configures the default MIME type sent to the browser, which helps it
; to render the content. In general, we want to keep the default value.
default_mimetype = "text/html"
; Configures the character set sent to the browser, which helps it to
; render individual characters correctly. This is important when making
; use of non-alphanumeric extended characters.
default_charset = "UTF-8"
;;;;;;;;;;;;;;;;
; File Uploads ;
;;;;;;;;;;;;;;;;
; Enables or disables the ability to receive files uploaded via
; a user's browser.
file_uploads = On
; Configures the maximum allowable file size for uploads. We will
; configure this for 200 megabytes.
upload_max_filesize = 200M
; Configures how many files can be uploaded from a user's browser
; simultaneously.
max_file_uploads = 20
;;;;;;;;;;;;;;;;;;
; Fopen wrappers ;
;;;;;;;;;;;;;;;;;;
; Configures the ability to use URLs in PHP's fopen() function. This is
; useful for loading external data files like JSON or CSV.
allow_url_fopen = On
; Configures the ability to use external URLs in PHP's include()
; function. Since this function is most commonly used for including
; PHP functionality, it's not recommended to allow this.
allow_url_include = Off
; Configures the default timeout, in seconds, when connecting to an
; external URL. This could be increased to support connecting to slow
; APIs.
default_socket_timeout = 60
;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;
; Enables the cURL extension
extension=curl
; Enables MySQLi
extension=mysqli
; Enables the GD2 graphics library
extension=gd2
; Enables the PDO extension for MySQL, which provides additional
; functionality for secure data handling
extension=pdo_mysql
;;;;;;;;;;;;;;;;;;;;
; Configure MySQLi ;
;;;;;;;;;;;;;;;;;;;;
[MySQLi]
; Configure the number of persistent links. We'll set this to -1, which
; indicates no limit
mysqli.max_persistent = -1
; Enables or disables persistent connections to a MySQL server.
mysqli.allow_persistent = On
; Configures the number or links allowed to a MySQL server. We'll set
; this to -1, which indicates no limits
mysqli.max_links = -1
; Configures the default port for connecting to a MySQL server.
; Generally, this is port 3306
mysqli.default_port = 3306
; Enable or disable reconnecting to the MySQL Server. This is disabled
; by default, and I recommend leaving this setting.
mysqli.reconnect = Off
;;;;;;;;;;;;;;;;;;;;;;
; Configure Sessions ;
;;;;;;;;;;;;;;;;;;;;;;
[Session]
; Configures how PHP stores and retrieves session data. This saves the
; data securely as files, which helps manage memory usage.
session.save_handler = files
; Enables or disables strict session mode. This is a security option,
; disabled by default, which requires a session ID be created before
; working with session data.
session.use_strict_mode = 0
; Enables or disables the use of Cookies within PHP
session.use_cookies = 1
; Enables or disables the use of a cookie for storing and maintaining
; the session ID. This is highly recommended for security.
session.use_only_cookies = 1
; Configures the name of the session stored in the cookie. This is
; configured to use the contents of a PHP constant.
session.name = PHPSESSID
; Configures the serializer used by PHP for session data.
session.serialize_handler = php
; Configures the expiry of data for session data, in seconds, before it
; is automatically removed.
session.gc_maxlifetime = 1440

Testing It Out

After making changes to your php.ini to support your particular codebase, restart Apache and navigate to your DocumentRoot. Create a file named index.php and include the following PHP script.
<?php
phpinfo();
This simple script calls the phpinfo() function, which returns information about your PHP installation. Save the file, and open this URL in your browser: http://localhost/index.php. You see a screen similar to Figure 4-1.

A web page of P H P Version 8.1.3 contains the information for System, Build Date, Build System, Configure Command, Server A P I, Virtual Directory Support, Configuration File Path, Loaded Configuration File, and directory for additional files.

Figure 4-1

PHP configuration page

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.

The standard model for running Node.js applications on a development environment is to use Express and set up a transitory server through a command in your terminal, such as the following.
node app.js

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.

To install PM2, open your terminal and type the following.
npm install pm2@latest -g
Note

You may need to run this as sudo on Linux

This installs PM2 globally.

Configuring the Application

Let’s set up a basic Node.js Hello World application to show how things work. Create a new directory in your code directory, and create a new app.js file with the following contents.
const express = require('express')
const app = express()
app.get('/', function (req, res) {
  res.send('Hello World!')
})
app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})
Next, you need to create a package.json with the following.
{
  "name": "helloworld",
  "version": "0.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "You!",
  "license": "ISC",
  "dependencies": {
    "express": "^4.15.3"
  }
}

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

Once you’ve configured your application, you can use PM2 to add it as a service. Type the following into your terminal. After changing to the directory, your Node.js application is stored in (substituting app.js with your application’s main entry point).
pm2 start app.js
You see something similar to the following.
[PM2] Spawning PM2 daemon with pm2_home=/home/darren/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /var/www/sites/nodejs/helloworld/app.js in fork_mode (1 instance)
[PM2] Done.
┌───┬──────────────┬───────┬─────┬────────┬───────┬───────┐
│  id │ name               │ mode     │ ↺     │ status    │ cpu      │ memory   │
├───┼──────────────┼───────┼─────┼────────┼───────┼───────┤
│ 0  │ app                │ fork     │ 0      │ online    │ 0%       │ 29.3mb   │
└───┴──────────────┴───────┴─────┴────────┴───────┴───────┘

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

Open your httpd.conf, and look for the following line (the paths to mod_proxy.so and mod_proxy_http.so differ on macOS and Windows).
#LoadModule proxy_module lib/httpd/modules/mod_proxy.so
Uncomment this directive by removing the #, so that you have the following.
// On Mac OS:
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
// On Windows using XAMPP:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Test your configuration and restart Apache for the changes to take effect.

On Linux

Open a terminal and navigate to /etc/apache2/mods-enabled.

Type the following.
ln -s ../mods-available/proxy.load proxy.load
ln -s ../mods-available/proxy_http.load proxy_http.load

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

Despite running things through a proxy, you still need to configure Apache to provide a virtual host for the Node.js server. The following configuration creates a domain in Apache for http://nodeapp.local, and configures it to pass requests through a configured proxy to port 3000 (instead of port 80, the default port for most URLs).
<VirtualHost *:80>
    DocumentRoot "/var/www/sites/nodeapp"
    ServerName nodeapp.local
    # Set up Logging
    ErrorLog ${APACHE_LOG_DIR}/nodeapp-error.log
    CustomLog ${APACHE_LOG_DIR}/nodeapp-access.log combined
    <IfModule mod_proxy.c>
        ProxyPass / http://portly.local:3000
        ProxyPassReverse / http://portly.local:3000/
        <Proxy *>
           Order allow,deny
            Allow from all
        </Proxy>
    </IfModule>
</VirtualHost>

Testing It Out

Once you have the preceding configured, visit http://nodeapp.local in your browser, and you should see something similar to Figure 4-2.

A page of a web browser with address, node app dot local, and an open web page with text, Hello World.

Figure 4-2

Loading your local Node.js development environment

If your Node.js app is not running, you see something like Figure 4-3.

A page of a web browser with address, node app dot local contains an error message that the Service is unavailable and the server is temporarily unable to service the request due to maintenance or capacity problems and to try again later.

Figure 4-3

Apache’s error page when loading a non-running Node.js application

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset