ObjectiveThe 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
RequirementsPrivileged access to the webserver.
- # - requires given linux commands to be executed with root privileges either directly as a root user or by use of
- $ - given linux commands to be executed as a regular non-privileged user
IntroductionInstalling 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 supportTo install the packages required, simply run as root:
# yum install httpd mod_ssl -yIf 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 serverUsing systemd you can enable and start the webserver with the below command:
# systemctl enable httpd && systemctl start httpdThis way the httpd service will be automatically started by systemd on every boot.
Verify installation and statusYou 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: Starting The Apache HTTP Server... Jul 07 21:35:33 web.foobar.com systemd: Started The Apache HTTP Server.
To Check that mod_ssl is properly installed:
And is loaded as a module into httpd server:
# rpm -q mod_ssl mod_ssl-2.4.6-80.el7.x86_64
# apachectl -M | grep ssl ssl_module (shared)
Certificate usageWhen 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:
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:
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:
And then use openssl to get the expiration date:
# grep SSLCertificateFile /etc/httpd/conf.d/ssl.conf | grep -v "#" SSLCertificateFile /etc/pki/tls/certs/localhost.crt
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.
# openssl x509 -enddate -noout -in /etc/pki/tls/certs/localhost.crt notAfter=Jul 10 07:06:17 2019 GMT
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
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 httpsNow 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.dwith a descriptive name, say,
redirect_http.confwith the following content (where web.foobar.com is the DNS name of the site):
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):
<VirtualHost _default_:80> Servername web.foobar.com Redirect permanent / https://web.foobar.com/ </VirtualHost>
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
$ 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]
10.9.8.8 - - [19/Jul/2018:16:13:01 +0200] "GET / HTTP/1.1" 200 240