How to setup SSL/TLS with Apache httpd on Red Hat

Objective

The objective is to set up Apache webserver with SSL/TLS support on Red Hat Linux, using the packages shipped with the distribution.

Operating System and Software Versions

  • Operating system: Red Hat Enterprise Linux 7.5
  • Software: Apache httpd, mod_ssl

Requirements

Privileged access to the webserver.

Difficulty

EASY

Conventions

  • # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
  • $ – given linux commands to be executed as a regular non-privileged user

Introduction

Installing a webserver is pretty easy on modern distributions, as use cases of a webserver are so common that most if not all distributions provide packages in their repositories. Apache httpd is a reliable webserver used by a large portion of the Internet, and many modules are available to extend it’s functionality.

The tech news these days are filled with security breaches, data theft/leakage, and a growing urge to use encryption
where it is possible. While using HTTPS has a certain computing overhead on both server and client side, not using it means all data sent in both directions is clear text, readable by anyone who is able to read the traffic while it passes trough the network.

Suppose you have a web service where clients can log in using their username and password – a common authentication method – to reach their own data, including the admins of the site. If you provide this service over http, all this information can be recorded, so someone could get all the login credentials, log in as the admin of the site, and lock out the real admins or publish content harmful to visitors.

The ability to use encryption while browsing is built in to all major modern browsers for a long time, and the same way encryption is available to webservers for many years now.



Install Apache webserver with SSL/TLS support

To install the packages required, simply run as root:

# yum install httpd mod_ssl -y

If the server already have httpd installed, you only need to install mod_ssl, all the required configuration is done
by the installer. Note however that in this case you need to restart httpd, so it can load the ssl module. By using
the packages shipped with the distribution, we can make our life much easier, as Red Hat will provide properly tested updates for both the operating system and the webserver, of course, you need a subscription to receieve the updates – but updates are needed for the operating system anyway to stay up to date.

Enable and start httpd server

Using systemd you can enable and start the webserver with the below command:

# systemctl enable httpd && systemctl start httpd

This way the httpd service will be automatically started by systemd on every boot.

Verify installation and status

You can check status of the webserver using systemd:

# systemctl status httpd -l
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2018-07-07 21:35:33 CEST; 1 weeks 4 days ago
     Docs: man:httpd(8)
           man:apachectl(8)
 Main PID: 1292 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
    Tasks: 9
   CGroup: /system.slice/httpd.service
           ├─ 1292 /usr/sbin/httpd -DFOREGROUND
           ├─13271 /usr/sbin/httpd -DFOREGROUND
           ├─13272 /usr/sbin/httpd -DFOREGROUND
           ├─13273 /usr/sbin/httpd -DFOREGROUND
           ├─27508 /usr/sbin/httpd -DFOREGROUND
           ├─27509 /usr/sbin/httpd -DFOREGROUND
           ├─27510 /usr/sbin/httpd -DFOREGROUND
           ├─27511 /usr/sbin/httpd -DFOREGROUND
           └─27512 /usr/sbin/httpd -DFOREGROUND

Jul 07 21:35:32 web.foobar.com systemd[1]: Starting The Apache HTTP Server...
Jul 07 21:35:33 web.foobar.com systemd[1]: Started The Apache HTTP Server.


To Check that mod_ssl is properly installed:

# rpm -q mod_ssl
mod_ssl-2.4.6-80.el7.x86_64

And is loaded as a module into httpd server:

# apachectl -M | grep ssl
 ssl_module (shared)

Certificate usage

When we install the mod_ssl package, the module adds itself to the httpd server, so it will load it on next startup.
A self-signed certificate is generated by default, which is used to establish encrypted connection with the browser.
Open a browser, and point it to the server over https:

SSL error message in Firefox browser

SSL error message in Firefox browser

Let’s ignore this for now, add the security exception (don’t set “permanently store this exception”), and continue. The default page appears. In case of Red Hat, this looks like as follows:

Default home page of a httpd webserver install on Red Hat Linux

Default home page of a httpd webserver install on Red Hat Linux


Note the exclamation point next to the URL (other browsers may show different warning).

Our webserver is now up and running over https with a self-signed certificate, and ready to serve content published
under /var/www/html, the default content root of the webserver on Red Hat.

The connection between the webserver and the browser is now encrypted, so it is harder to spoof the traffic (which
can be used, for example steal login credentials). Are we done? In a way, we completed our goal.

The fact that our browser can’t identify the server certificate as valid does not prevent it to use encrypted communication with the server, if we explicitly decide that we trust this certificate. This may be suitable for a small (home) system, where you have only a few users, as well as only a few webservers – you have to accept the self-signed certificate in browsers that should be clients of the webservers, and any other browser in the world should not ever see the content provided by these servers.

Note however, that this self-signed certificate will expire in time (as any other certificate should), and you will have
to renew it in order to use it. Expired certificates are considered invalid by the browsers, the same way as certificates that can’t be proven to be valid by a valid certificate chain above them.

To find out when the self-signed (or any other) certificate will expire, we have to find it on the filesystem by consulting the ssl module’s configuration file:

# grep SSLCertificateFile /etc/httpd/conf.d/ssl.conf | grep -v "#"
SSLCertificateFile /etc/pki/tls/certs/localhost.crt

And then use openssl to get the expiration date:

# openssl x509 -enddate -noout -in  /etc/pki/tls/certs/localhost.crt
notAfter=Jul 10 07:06:17 2019 GMT

After (or rather, before) the certificate expires, you have to renew or replace it with a certificate the clients trust. A
more elegant approach in contrast to self-signed certificates is requesting and using a certificate from a CA
(Certificate Authority) your clients already trust, either from your internal CA (which in turn can have a globally
trusted root CA above it), or directly from a globally-trusted CA.

To use the obtained certificate instead of the default, the below parameters must point to the certificate file, the
certificate key, and the certificate of the CA that signed the SSL certificate, respectively. The files must be copied on
the webserver, and must be readable by the operating system user running the webserver – in case of a Red Hat default install, the apache user. These parameters can be found in the above mentioned ssl.conf.

SSLCertificateFile	/etc/httpd/custom-cert/server-ssl.crt
SSLCertificateKeyFile	/etc/httpd/custom-cert/server-ssl.key
SSLCACertificateFile	/etc/httpd/custom-cert/ca.crt


Redirecting http traffic to https

Now that we serve over https, we can enforce the usage of https while serving all or part of our content. In our
example, we are very secure, and use http only to redirect incoming clients to https.

A question may arise, if we want to speak https only, why do we listen to http at all? Suppose an end user, who just heard of our site, and got an URL from a friend not containing the protocol. To this day, most browsers default to http protocol, if one is not specified explicitly. If we stop serving over http, the user typing the URL without https will receive an error message if his/her browser tries to reach our server over http.

To redirect all incoming http requests to https, we create a file under /etc/httpd/conf.d with a descriptive name, say, redirect_http.conf with the following content (where web.foobar.com is the DNS name of the site):

<VirtualHost _default_:80>
        Servername web.foobar.com
        Redirect permanent / https://web.foobar.com/
</VirtualHost>

And restart the webserver. We can test if the redirection works correctly from the command line with wget (from a host that trusts the SSL certificate of the webserver):

$ wget http://web.foobar.com/
--2018-07-19 16:13:01--  http://web.foobar.com/
Resolving web.foobar.com (web.foobar.com)... 10.9.8.7
Connecting to web.foobar.com (web.foobar.com)|10.9.8.7|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://web.foobar.com/ [following]
--2018-07-19 16:13:01--  https://web.foobar.com/
Connecting to web.foobar.com (web.foobar.com)|10.9.8.7|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 240 [text/html]
Saving to: ‘index.html’

100%[====================================================================================>] 240         --.-K/s   in 0s      

2018-07-19 16:13:01 (7.04 MB/s) - ‘index.html’ saved [240/240]

The output shows the http 301 response, and we can see how our wget client follows the redirect to connect using https protocol. By default the ssl traffic is logged in different logfiles then the http traffic. We can find the above
request logged in /var/log/httpd/ssl_access_log:

10.9.8.8 - - [19/Jul/2018:16:13:01 +0200] "GET / HTTP/1.1" 200 240

Conclusion

With this we have completed our objective, we set up a webserver that uses https to speak with clients, and redirects incoming http requests to https as well.