In this guide, you'll learn how to use SSL to secure Apache, this way, you can ensure your websites are encrypted and available over HTTPS.
By default, Apache configuration listens for traffic on port 80 in Ubuntu, and not port 443 (HTTPS).
Confirm by running the following command:
sudo netstat -tulpn |grep apache
This would be the output if apache is only listening to port 80:
tcp6 0 0 :::80 :::* LISTEN 1163/apache2
If the server is listening on port 443, the below output should look similar:
tcp6 0 0 :::80 :::* LISTEN 3356/apache2
tcp6 0 0 :::443 :::* LISTEN 3356/apache2
To enable support for HTTPS traffic, you need to first enable the SSL module, and you then restart:
sudo a2enmod ssl
sudo systemctl restart apache2
Ubuntu default Apache includes a site configuration listening for a connection on port 443, and other config related to SSL.
Open it up to understand how it works:
sudo nano /etc/apache2/sites-available/default-ssl.conf
This is the output would the comment stripped out:
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
<FilesMatch ".(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
</IfModule>
- On the first line, you see IfModule mod_ssl.c, this is pretty explanatory, the <IfModule mod_>...</IfModule> section is used to mark directives that are conditional on the presence of a specific module. The directives within a <IfModule> section are only processed if the module is true. If the module is false, everything between the start and end markers is ignored.
- On the second line, the virtual host is listening on port 443, and the _default_ option applies to unspecified traffic, which means any traffic coming into port 443 that hasn't already been identified in any other virtual host.
- The ServerAdmin email specifies the email address that is displayed in any error messages shown in case there is a problem with the site.
- Documentroot is the location you are serving the website content from, in this case, I am serving the content from /var/www/html, this is totally customizable.
- The error log is stored at /var/log/error.log and contains information you can use whenever someone has trouble
- The access log contains information relating to HTTP requests that come in, and by default is stored in /var/log/access.log.
- SSLEngine on enables SSL traffic
- Right after that, you have options for your SSL certificate file, and key files, which we would get over in a moment.
- FileMatch is used to target multiple files, in this case, it is targeting those file HTML, PHP, etc. and adding an SSL encryption for the matched file.
- The <Directory> clause allows us to apply specific options to a
directory. In this case, the /usr/lib/cgi-bin directory is being applied to the SSLOptions +StdEnvVars setting, which enables default environment variables for use with SSL.
By default, the default-ssl.conf file is not enabled, In order to benefit from its configuration options, we'll need to enable it, which we can do with the a2ensite command as we would with any other virtual host:
sudo a2ensite default-ssl.conf
Our site isn't secured just yet, as we would need to install SSL certificated on our web server.
There are two ways you can do this, you can either go with a self-signed certificate which most browsers won't trust by default (it would return a not secure error, which you can bypass anyway) and the other way is to install certificates signed by a certificate authority, which is the recommended method.
We would be using a self-signed certificate as an illustration in this guide, they are not recommended for a production environment, so, if you are planning to secure Nginx on a production server, you can go with this article: Securing Apache Server Using (Let's Encrypt) [Ubuntu]
Installing a Self-Signed Certificate
Create a directory that houses our certificate. Create a certs directory under /etc/apache2/
Change your working directory into /etc/apache2/ and run the following command
sudo mkdir certs
To avoid an error when issuing a self-signed certificate in Ubuntu, you might need to create a .rnd in your user directory, make sure this is owned by the user of the home directory, it is used by OpenSSL to store some amount (256 bytes) of seed data.
Create the .rnd file:
touch ~/.rnd
Now, request for the certificate and key pair with the following command:
Note: You can also change the name of the key and cert file to match the name of your website.
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/certs/mywebsite.key -out /etc/apache2/certs/mywebsite.crt
You would be asked a series of questions, this is would be incorporated in your certificate request, here is the questions, and answer of mine:
Country Name (2 letter code) [AU]:NG
State or Province Name (full name) [Some-State]:Lagos
Locality Name (eg, city) []:Ikeja
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Devsrealm
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:blog.devsrealm.com
Email Address []:faruq@devsrealm.com
Now, if you go into the /etc/apache2/certs directory, you'll see two files created: mywebsite.crt and mywebsite.key, which represent the certificate and private key respectively.
Now that these files have been generated, the next thing for us to do is to configure Apache to use them.
Find the following line in the /etc/apache2/sites-available/default-ssl.conf file:
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
Comment out the lines by placing # symbol in front of both:
# SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
# SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
Add the generated certificate and key below the commented out line. e.g:
SSLCertificateFile /etc/apache2/certs/mywebsite.crt
SSLCertificateKeyFile /etc/apache2/certs/mywebsite.key
Reload Apache to add the new configuration:
sudo systemctl reload apache2
There is one more step to go, our certificate file is already installed, but we need to inform Apache of when to apply them.
Add Severname option to the above file to ensure the site supports SSL.
ServerName mywebsite.com:443
Now, when traffic comes in to your server on port 443 requesting a domain that matches the domain you typed for the ServerName option, it should result in a secure browsing
session for the client.
As this certificate isn't coming from a known certificate authority, you might see an error, which you can skip. This doesn't mean the encryption isn't working though, the browser is just skeptical of the certificate
If you want to host multiple websites over HTTPS, you might want to separate the virtual host file for each domain.
To do this:
- copy all the content in the /etc/apache2/sites-available/default-ssl.conf
- create a new file under sites-available, e.g website1.conf
- Change the virtual to listen for anything coming in on port 443 e,g <VirtualHost *:443>
- Make sure the servername is changed to the specific domain, and it's listening on port 443
- Change the documentroot to the folder the website file is located
- Lastly, customize the error and access log
- Here is an example:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName website1.com:443
ServerAdmin webmaster@localhost
DocumentRoot /var/www/website1
ErrorLog ${APACHE_LOG_DIR}/website1.com-error.log
CustomLog ${APACHE_LOG_DIR}/website1.com-access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/certs/website1/acme.crt
SSLCertificateKeyFile /etc/apache2/certs/website1/acme.key
<FilesMatch ".(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
</IfModule>