This chapter demonstrates setting up the Apache web server, including enabling HTTPS with a digital certificate. While system administrators must be able to setup web servers, it is also a valuable skill for software developers and network engineers, as they can be very useful for development and testing. The steps for enabling security features, in particular HTTPS, are quite involved, but serve as an excellent demonstration of security concepts such as public key cryptography, digital signatures and certificates.
This chapter assumes you have knowledge of:
Basic operating system concepts, including users, passwords and file systems
Basic Linux command line skills, as covered in Chapter 4, are assumed. You will need to be able to:
While a web server is setup on a single computer, to test it is beneficial if you have at least one other computer for a client (the client and server can be on the same computer, but then it is harder to observe communications between the two).
The recommended virtnet (Chapter 3) topology is:
The instructions in this chapter refer to topology 5, where node1 is the client (web browser), node2 is the router and node3 is the server (running Apache web server). The example domains are those pre-configured in virtnet (but can be easily changed by editing the /etc/hosts file—see Section 9.11.2).
You may first need to install Apache web serve (it may already be installed, e.g. on virtnet nodes; trying to install it again won’t hurt):
network@node3:~$ sudo apt install apache2
We can use systemctl (described further in Section 12.2.5) to check if it is running. It should be displayed as “active (running)” when performing:
network@node3:~$ sudo systemctl status apache2
Video: Apache Web Server and HTTPS on Linux (47 min)
There are various files and directories that you may need to access when managing the web server. Those you will initially most likely access are:
The main configuration directory for Apache is:
/etc/apache2/
The main configuration file for Apache is:
/etc/apache2/apache2.conf
You can edit these file if you use sudo and your favourite text editor.
Other important configuration files are in the directories:
/etc/apache2/conf.d/
/etc/apache2/sites-available/
In this section we do not try to explain all the details of the apache2.conf file. The default settings are suitable for a basic web server.
An important file specific to the web site is:
/etc/apache2/sites-available/default
This file contains configuration options specific to a site. (You can potentially host multiple sites on the one Apache server).
The web server documents (e.g. the HTML pages that are available via the server) are stored in a base directory:
/var/www/html/
By default there is a file called index.html. You can browse the server by entering the URL http://127.0.0.1/ or http://localhost/ to view the web page and test that your server is working.
You can create any files/directories in the base directory which will then be accessible by the web server.
Finally, log files are stored in /var/log/apache2/. Section 12.2.6 gives a brief explanation of the Apache web server log.
Use a web browser, e.g. lynx, wget, to access the web server by IP address. For example, if the web server has IP address 192.168.2.22 and you are on node1 in virtnet:
network@node1:~$ lynx http://192.168.2.22/
As we do not have a real DNS server, we are limited to using just IP addresses to other computers. However you may manually setup fake domain names by editing the /etc/hosts file on all computers. For example, if the web server has IP address 192.168.2.22, on the client we can add the following line to /etc/hosts (Section 9.11.2):
192.168.2.22 www.example.com
You may add multiple IP/domain values, e.g. if you have multiple servers on different IPs. Note that these fake domain names can only be used on computers that have /etc/hosts setup. Section 9.11.2 explains the format of /etc/hosts.
When you install Apache, the web server automatically starts. You may stop, start or restart Apache using the command systemctl
network@node3:~$ sudo systemctl stop apache2
network@node3:~$ sudo systemctl start apache2
network@node3:~$ sudo systemctl restart apache2
You can also see the current status, e.g. if it is running:
network@node3:~$ sudo systemctl status apache2
When you make changes to the web server configuration files, those changes do not take effect until you reload the configuration (or restart the server):
network@node3:~$ sudo systemctl reload apache2
Finally, Apache is automatically started when your computer boots. You may disable automatic startup (and similarly, you may enable it):
network@node3:~$ sudo systemctl disable apache2
Video: Managing Apache Web Server with systemctl (5 min; Apr 2018)
Another important file is the log produced by Apache. Apache logs (records) all requests for content on this server. The log is a text file:
/var/log/apache2/access.log
The format of this log file is a space separated file with each line showing details of a single request for a web page on the server. Each line has the following fields:
You should not edit the access.log file. Instead use less or tail to display its contents. less will display the file, page by page:
network@node3:~$ less access.log
The command tail will display the last 10 lines of the file:
network@node3:~$ tail access.log
Video: Apache Web Server Access Log (10 min; Apr 2018)
The remaining steps are enabling HTTPS and creating a certificate for the web server. In the following instructions we assume the IP of the server is 192.168.2.22 and of the client is 192.168.1.11. The domain of the server is www.example.com. The steps are:
Finally we can test HTTPS using a web browser.
Video: Apache Web Server and HTTPS on Linux (47 min)
In practice, a CA would be an external node. However for this simple demo we will use server as both the CA and the actual web server. So now lets setup the CA on the server.
First our root CA needs its own, self-signed certificate. Generate a RSA public/private key pair. Here we generate a 20148-bit RSA private key using a public exponent (e) of 65537. The key is NOT encrypted with DES (or other ciphers).
network@node3:~$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out cakey.pem
Next create a self-signed certificate. Enter the details for your CA.
network@node3:~$ openssl req -new -x509 -key cakey.pem -out cacert.pem -days 1095
You will be prompted for information and should set appropriate values, such as:
Now we setup the CA to handle certificate signing requests from other entities (i.e. our web server). OpenSSL uses some default files and directories, which are specified in /usr/lib/ssl/openssl.cnf. Lets create them with the following commands:
network@node3:~$ cd
network@node3:~$ mkdir demoCA
network@node3:~$ mkdir demoCA/certs
network@node3:~$ mkdir demoCA/crl
network@node3:~$ mkdir demoCA/newcerts
network@node3:~$ mkdir demoCA/private
network@node3:~$ touch demoCA/index.txt
network@node3:~$ echo 02 > demoCA/serial
network@node3:~$ mv cacert.pem demoCA/
network@node3:~$ mv cakey.pem demoCA/private
The above commands create the necessary directory structure to run a CA. If you make a mistake, then the CA will not be able to correctly issue certificates. In that case, the best approach is to delete the entire demoCA directory (rm -fR ~/demoCA/) and repeat the above commands.
Lastly for the CA setup, OpenSSL has strict policies on the details of the CA matching that of the requesting server. For example, it requires the state of the CA and server to be identical. We can change the policy by editing /usr/lib/ssl/openssl.cnf, in particular the “For the CA policy” section. Edit the configuration file:
network@node3:~$ sudo nano /usr/lib/ssl/openssl.cnf
Find the section “For the CA policy”. Change the values to look like this:
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Now the CA is setup and ready to process certificate signing requests.
To create a certificate for the www.example.com website, first generate a RSA public/private key pair. Here we generate a 2048-bit RSA private key using a public exponent (e) of 65537. The key is NOT encrypted with DES (or other ciphers).
network@node3:~$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out privkey-www.example.com.pem
The output file (privkey-www.example.com.pem) is plaintext. It contains the private key, encoded as Base64, in between two lines indicating the begin and end of the key.
Next create a certificate request that will be sent to the Certificate Authority. This takes a private key as input (i.e. the file generated above) and produces a .csr certificate request file as output. This is a new certificate request.
network@node3:~$ openssl req -new -key privkey-www.example.com.pem -out certreq-www.example.com.csr
You will be prompted to enter your certificate information:
You will also be prompted for a challenge password. You do NOT want a password - just press ENTER to continue. The value of Common Name MUST be the domain of the website, e.g. www.example.edu. The other values may be different, depending on the policy of the OpenSSL CA.
Send your certificate request file to the CA. Since in this demo both the server and CA are on the same Linux VM, there is no actual sending (the file already is available to the CA).
Now the CA processes the certificate signing request using the following command. Make sure all the file names are correct and the certificate is successfully committed to the database of the CA.
network@node3:~$ openssl ca -in certreq-www.example.com.csr -out cert-www.example.com.pem
The CA will be prompted to sign the certificate (choose y for yes) and commit to the database (choose y for yes).
Finally lets copy the CAs certificate from the demoCA directory, renaming the extension to .crt (which is expected by Apache).
network@node3:~$ cp demoCA/cacert.pem cert-ourca.crt
To check all the steps were successful, verify the server certificate:
network@node3:~$ openssl verify -CAfile cert-ourca.crt cert-www.example.com.pem
The output should show OK, e.g.:
cert-www.example.com.pem: OK
Now you need to enable HTTPS in Apache, including making both certificates available. First lets copy the files into appropriate directories for Apache to read:
network@node3:~$ sudo cp cert-www.example.com.pem /etc/ssl/certs/
network@node3:~$ sudo cp cert-ourca.crt /etc/ssl/certs/
network@node3:~$ sudo cp privkey-www.example.com.pem /etc/ssl/private/
You should set the permissions on the private key so that no-one else can access it (i.e. only root can).
Now edit the configuration file for the Secure Sockets Layer (SSL) enable website:
network@node3:~$ sudo nano /etc/apache2/sites-available/default-ssl.conf
You need to add in the following line (after the ServerAdmin line):
ServerName www.example.com:443
And you need to comment out the snakeoil certificates and add in three lines:
# SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
# SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
SSLCertificateFile /etc/ssl/certs/cert-www.example.com.pem
SSLCertificateKeyFile /etc/ssl/private/privkey-www.example.com.pem
SSLCACertificateFile /etc/ssl/certs/cert-ourca.crt
Finally, enable the SSL module, the SSL-based website and restart the server:
network@node3:~$ sudo a2enmod ssl
network@node3:~$ sudo a2ensite default-ssl
network@node3:~$ sudo systemctl reload apache2
You can now try testing access to the website with lynx on the client.
Although the web server has its own certificate, signed by a CA, we still get a warning message when accessing the web site from the client. This is because the client (192.168.1.11 in our example) does not trust the CA that signed the servers certificate. We will now add the CA’s certificate to the list of CA certificates trusted by the client.
Perform the following on the client.
Copy the CAs certificate from the server to the client (change the IP address and directory as necessary):
network@node1:~$ scp 192.168.2.22:/home/steven/cert-ourca.crt .
Ubuntu keeps are store of trusted CAs certificates, which is used by lynx when it accesses websites. We need to create a directory for extra CA’s, add our CAs certificate to it, and then re-configure the store to include the new certificate:
network@node1:~$ sudo mkdir /usr/share/ca-certificates/extra
network@node1:~$ sudo cp cert-ourca.crt /usr/share/ca-certificates/extra/
network@node1:~$ sudo dpkg-reconfigure ca-certificates
After running the dpkg-reconfigure command you will be given several options about trust—choose the default—and then presented with a list of CA’s. Scroll down to the bottom until you find cert-ourca.crt and then mark it by pressing space. Then ok.
That’s it. Now test again with lynx and you should find no errors/warnings when connecting to the secure web server.
Of course you can use your web browser on node1 (e.g. lynx) to access the website. You can also test using openssl directly on the client:
network@node1:~$ openssl s_client -connect www.example.com:443
Press Ctrl-C to exit. This command should show details of the certificate and SSL communications.