Running an Apache web server under OS X El Capitan

Apple's OS X/macOS operating system (OS) comes with the Apache webserver software, which I decided to enable on my MacBook Pro laptop running OS X El Capitan, version 10.11.6 on the laptop.

The Apache web server software isn't running by default and you can no longer enable it through the Sharing option under System Preferences as in some earlier versions of OS X, but you can start it from a command line interface (CLI) by opening a Terminal window (Terminal is found in the Applications/Utilities folder), with the command sudo apachectl start. Once you start the software, you will see the system is listening on the well-known port for Hypertext Transfer Protocol (HTTP) connections, port 80, by using the netstat command.

$ sudo apachectl start
Password:
$ netstat -a | grep http | grep LISTEN
tcp46      0      0  *.http                 *.*                    LISTEN     
$

Note: if you run the apachectl command without the sudo command before it, you will see the error message below:

$ apachectl restart
This operation requires root.

If you then open a web browser and use http://127.0.0.1 as the Uniform Resource Locator (URL), you should see a page displayed with just "It works!" on the webpage. The 127.0.0.1 IP address is the localhost address for the system, i.e., it's just a standard address for the system you are using, i.e., the one you are running the browser on in this case.

You can stop the software with sudo apachectl stop or restart it, if it is already running, with sudo apachectl restart.

The configuration file for Apache is stored at /etc/apache2/httpd.conf (default httpd.conf file) on a Mac OS X system. You can edit it with a text editor.

By default, the Apache webserver under OS X serves documents from the directory /Library/WebServer/Documents. The location is controlled by the DocumentRoot setting in the httpd.conf file.

#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "/Library/WebServer/Documents"

You will see an index.html.en file in that directory that is displayed when you point your browser to http://127.0.0.1. You can't place files in that directory from a regular user account, but you can use the sudo command, which will allow you to run commands with root, i.e., administrator, privileges, and the vi editor to place a file in that directory. E.g., I could use the vi text editor to create a file in that directory named test.html with the following lines in the file using the command sudo vi /Library/WebServer/Documents/test.html:

Tutor for Mac OS X El Capitan
Tutor for Mac OS X El Capitan
1x1 px

<html>
<head>
<title>Testing</title>
</head>

<body>
This is a test page.
</body>

</html>

Note: if you aren't familiar with the vi editor, you will find the GNU nano editor easier to use. The vi editor has a lot of features for manipulating text, but becoming proficient in it requires learning its unique commands. To create the same file with the nano text editor, you could use the command sudo nano /Library/WebServer/Documents/test.html.

If I then pointed my browser to http://127.0.0.1/test.html, I would see a web page displayed with only "This is a test page." appearing on the page. But suppose you want to serve pages from a user directory, one way to do that is to create a "virtual host". Within the httpd.conf file, you will see the following lines:

# Virtual hosts
#Include /private/etc/apache2/extra/httpd-vhosts.conf

You can set Apache to read that file for virtual host information by removing the hash sign (#), which turns the line into a comment rather than a configuration directive, from the beginning of the "Include" line. If you are using the GNU nano editor, you can search for the line by hitting the control-w (control and "w") keys and then typing httpd-vhosts.conf in the search field. When you've removed the hash sign at the beginning of the line, you can save the file with control-x.

You then need to edit the httpd-vhosts.conf file. As with the httpd.conf file, you will have to use sudo to save any changes you make to the file. E.g., I could add the following lines to the end of that file after deleting the existing VirtualHost sections or commenting them out by placing a hash sign (#) at the beginning of all the lines for the existing dummy virtual hosts, i.e., all the sections that begin with <VirtualHost *:80> and end with </VirtualHost>:

Advanced Mac OS X - Technical and Security Skills
Advanced Mac OS X
Technical and Security Skills
1x1 px

<VirtualHost *:80>
    ServerAdmin john.smith.1@example.com
    DocumentRoot "/Users/jasmith1/Documents/www"
    ServerName myserver.example.com
    ErrorLog "/Users/jasmith1/Documents/www/log/myserver-error_log"
    CustomLog "/Users/jasmith1/Documents/www/log/myserver-access_log" common
    <Directory "/Users/jasmith1/Documents/www">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

For the example above, you would substitute a valid email address you use for the ServerAdmin email address and a valid directory path on the system in place of /Users/jasmith1/Documents/. You would also need to create the www and /www/log directories beneath it. E.g., if I was logged into the jasmith1 account for the example, I could use the commands below:

$ mkdir ~/Documents/www
$ mkdir ~/Documents/www/logs
$

In the example above I used myserver.example.com as a fully qualified domain name (FQDN). The domain example.com like example.net, example.edu, and example.org, is a second-level domain name that is used for documentation purposes and examples of the use of domain names. So you could create some name of your own and, such as myserver and tack example.com, examaple.org, example.net, or example.edu on to it or you could create a fictitious domain name, i.e., anything you've made up, e.g., you could put .loc or .lan at the end of the FQDN rather than .com to indicate "local" or "local area network". Or you could register a domain name with a domain name registrar, if you needed people on other systems to be able to access the web server running on your system. Or, if you have a registered domain name and a website on some other system, such as a server from a hosting provider, but want to use your Apple Mac system as a place to test pages before deploying them to the actual production server, you can edit the hosts file on the Mac, so browsers on it will bring up the pages you want to test on the Mac.

Supposing, that I've decided I will use myserver.example.com; even my system won't be able to look up an IP address corresponding to the FQDN by querying a Domain Name System (DNS) server. But, if I'm not registering a domain with a domain name registrar, I can get around that problem by simply adding an entry to my system's hosts file found at /etc/hosts (default hosts file). I can simply modify the IPv4 localhost line in that file so that it reads as follows (of course substituting the name you picked to use for the server):

127.0.0.1       localhost, myserver.example.com

I.e., you can just append a comma, a space and the name you picked after localhost on the line beginning with 127.0.0.1. Alternatively, you could add another 127.0.0.1 line to the end of the file and put the name you selected after the address. E.g.:

127.0.0.1       myserver.example.com

You should then be able to successfully ping either localhost or the name you picked for the system, e.g., myserver.example.com.

$ ping -c 1 myserver.example.com
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.050 ms

--- localhost ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.050/0.050/0.050/0.000 ms
$ ping -c 1 localhost
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.046 ms

--- localhost ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.046/0.046/0.046/0.000 ms
$

Then you can need to place an index.html file in the /Documents/jasmith1/www directory or whatever directory you picked for the document root directory for the virtual host myserver.example.com. E.g., I could place a file named index.html with the following lines at that location:

Learning Apache Web Server Administration
Learning Apache Web Server Administration
1x1 px

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Page on My Server</title>
</head>

<body>
This is a test page on My Server.
</body>

</html>

You don't have to name the file index.html, but if you don't specify a file name Apache will display an index.html file if one is present in the specified directory or the document root directory if you just use http://myserver.example.com. If you named a file test.html and placed it in the document root directory, to display it you would need to use http://myserver.example.com/test.html.

To have the virtual host settings take effect, you will need to restart Apache with sudo apachectl restart. Otherwise, if you used http://myserver.example.com in your browser, it will load the same "It works!" page as before, because myserver.example.com has the IP address of 127.0.0.1 and the default document will be served for the localhost address. If it doesn't work, you can check the Apache configuration settings using apachectl -S. E.g., in the output below, I see that Apache can't find the directory in which to place its log files.

$ apachectl -S
AH00557: httpd: apr_sockaddr_info_get() failed for GSSLA15122293
AH00558: httpd: Could not reliably determine the server's fully qualified domain nam
e, using 127.0.0.1. Set the 'ServerName' directive globally to suppress this message
VirtualHost configuration:
*:80                   myserver.example.com (/private/etc/apache2/extra/httpd-vhosts
.conf:24)
(2)No such file or directory: AH02291: Cannot access directory '/Users/jasmith1/Docu
ments/www/log/' for error log of vhost defined at /private/etc/apache2/extra/httpd-v
hosts.conf:24
AH00014: Configuration check failed
$ ls ~/Documents/www/
daily_reports	index.html	logs
$

The Cannot access directory '/Users/jasmith1/Documents/www/log/' for error log of vhost defined at /private/etc/apache2/extra/httpd-vhosts.conf:24 message references a "log" directory, but I named the directory logs, so I need to either rename the directory or change the two log file references in the modified httpd-vhosts.conf file I created to reference the directory that actually exists. I can then run the sudo apachectl restart command again.

Note, if you try accessing the web page in the document root directory with http://myserver.example.com/ and see a "403 Forbidden page" error with the text below displayed, instead of the contents of the HTML file you created, then you may have made a mistake in the httpd-vhosts.conf file.

Forbidden

You don't have permission to access / on this server.

Make sure you added a "Directory" section to the httpd-vhosts.conf file with lines like the following ones, since, by default, Apache won't be allowed to access files under users' directories:

    <Directory "/Users/jasmith1/Documents/www">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

For the 2.2 version of Apache you could use the two lines below to control access to the specified directory, in this example /Users/jasmith1/Documents/www:

Order allow,deny
Allow from all

But for the current 2.4 version, you need to use Require all granted as noted in Upgrading to 2.4 from 2.2. Otherwise, you will see the "Forbidden" page and lines similar to the following one in the access log:

Udemy Generic Category (English)120x600
::1 - - [03/Feb/2017:17:39:00 -0500] "GET / HTTP/1.1" 403 209

And lines similar to the one below in the error log file.

Fri Feb 03 20:15:04.349161 2017] [authz_core:error] [pid 18680] [client 127.0.0.1:55
095] AH01630: client denied by server configuration: /Users/jasmith1/Documents/www/

You can see the version of Apache that is installed with the apachectl -v command.

$ apachectl -v
Server version: Apache/2.4.18 (Unix)
Server built:   Feb 20 2016 20:03:19
$

You can see other options for the apachectl command by issuing the command apachectl -h.

$ apachectl -h
Usage: /usr/sbin/httpd [-D name] [-d directory] [-f file]
                       [-C "directive"] [-c "directive"]
                       [-k start|restart|graceful|graceful-stop|stop]
                       [-v] [-V] [-h] [-l] [-L] [-t] [-T] [-S] [-X]
Options:
  -D name            : define a name for use in <IfDefine name> directives
  -d directory       : specify an alternate initial ServerRoot
  -f file            : specify an alternate ServerConfigFile
  -C "directive"     : process directive before reading config files
  -c "directive"     : process directive after reading config files
  -e level           : show startup errors of level (see LogLevel)
  -E file            : log startup errors to file
  -v                 : show version number
  -V                 : show compile settings
  -h                 : list available command line options (this page)
  -l                 : list compiled in modules
  -L                 : list available configuration directives
  -t -D DUMP_VHOSTS  : show parsed vhost settings
  -t -D DUMP_RUN_CFG : show parsed run settings
  -S                 : a synonym for -t -D DUMP_VHOSTS -D DUMP_RUN_CFG
  -t -D DUMP_MODULES : show all loaded modules 
  -M                 : a synonym for -t -D DUMP_MODULES
  -t                 : run syntax check for config files
  -T                 : start without DocumentRoot(s) check
  -X                 : debug mode (only one worker, do not detach)
$

Once you have Apache working on the system, if you wish to use PHP with Apache, see PHP for Apache on OS X El Capitan. If you configure Apache to use PHP, you can see that Apache runs from the _www account, if you create a PHP page with the PHP code system("id -a"); on it, e.g., whoami.php, which would produce the output shown below:

uid=70(_www) gid=70(_www) groups=70(_www),12(everyone),61(localaccounts),701(com.apple.sharepoint.group.1),100(_lpoperator)

You can see information on that accont for Apache in /etc/passwd .

$ grep _www /etc/passwd
_www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
_wwwproxy:*:252:252:WWW Proxy:/var/empty:/usr/bin/false
$

Related articles:

  1. PHP for Apache on OS X El Capitan
  2. Using Perl with Apache under OS X El Capitan
  3. Using Python scripts with Apache on OS X El Capitan