How To Create A Self-Signed SSL Certificate For Apache In Ubuntu 16.04

A self-signed certificate will encrypt communication between your server and any clients. However, because it is not signed by any of the trusted certificate authorities included with web browsers, users cannot use the certificate to validate the identity of your server automatically.

A self-signed certificate may be appropriate if you do not have a domain name associated with your server and for instances where the encrypted web interface is not user-facing. If you do have a domain name, in many cases it is better to use a CA-signed certificate.

1: Create the SSL Certificate

$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt

The questions are listed below. The important question is ‘Common Name' where you want to enter your ip address. Enter your local ip (for example:

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:Los Angeles
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.
Organizational Unit Name (eg, section) []:Web Applications
Common Name (e.g. server FQDN or YOUR name) []:server_IP_address
Email Address []

2. Create a strong Diffie-Hellman group:

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

3. Configure Apache to Use SSL

Create a new snippet in the /etc/apache2/conf-available directory named ‘ssl-params.conf' :

$ sudo nano /etc/apache2/conf-available/ssl-params.conf

copy/paste this to the file:

# from
# and

SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
# Requires Apache >= 2.4
SSLCompression off 
SSLSessionTickets Off
SSLUseStapling on 
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"

Ctrl-X, then ‘Y' to save and exit.


If using this with NextCloud/OwnCloud then edit these 2 lines:

Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff


Header set X-Frame-Options DENY
Header set X-Content-Type-Options nosniff

we just eliminated ‘always' on both lines because they was causing security warnings with NextCloud. They also would not allow the opening of files on a mounted drive. The above code edits solved both issues.

4. Modify the Default Apache SSL Virtual Host File

First, back up the original SSL Virtual Host file:

$ sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/default-ssl.conf.bak

Next, open the SSL Virtual Host file to make adjustments:

$ sudo nano /etc/apache2/sites-available/default-ssl.conf

We adjust the SSL directives to point to our certificate and key files, and uncomment one section that provides compatibility for older browsers. After making these changes, your server block should look similar to this (with the comments removed):

<IfModule mod_ssl.c>
        <VirtualHost _default_:443>
                ServerAdmin [email protected]
                ServerName server_domain_or_IP

                DocumentRoot /var/www/html

                ErrorLog ${APACHE_LOG_DIR}/error.log
                CustomLog ${APACHE_LOG_DIR}/access.log combined

                SSLEngine on

                SSLCertificateFile      /etc/ssl/certs/apache-selfsigned.crt
                SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key

                <FilesMatch "\.(cgi|shtml|phtml|php)$">
                                SSLOptions +StdEnvVars
                <Directory /usr/lib/cgi-bin>
                                SSLOptions +StdEnvVars

                BrowserMatch "MSIE [2-6]" \
                               nokeepalive ssl-unclean-shutdown \
                               downgrade-1.0 force-response-1.0


We updated the

  1. ServerAdmin email address
  2. added a line for the ServerName and included our ip address (e.g.,
  3. changed the line ‘SSLCertificateFile /etc/ssl/certs/' to ‘SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt'
  4. changed the line ‘SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key' to ‘SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key'
  5. added extra lines of code rght underneath the </Directory> tag

Ctrl-X then ‘Y' to save and exit.

5. Modify the unencrypted virtual host file to redirect to HTTPS

As it stands now, the server will provide both unencrypted HTTP and encrypted HTTPS traffic. For better security, it is recommended in most cases to redirect HTTP to HTTPS automatically. If you do not want or need this functionality, you can safely skip this section.

Open and edit the file below:

$ sudo nano /etc/apache2/sites-available/000-default.conf

Inside the ‘VirtualHost' configuration blocks, add a Redirect directive after the ‘DocumentRoot' line, pointing all traffic to the SSL version of the site (using the same ip address that you used above):


ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Redirect "/" ""

Ctrl-X then ‘Y' to save and exit.

6. Adjust the firewall

If you have the ufw firewall enabled, you might need to adjust the settings to allow for SSL traffic. To see the available profiles:

$ sudo ufw app list

To see the current setting:

$ sudo ufw status

To let in HTTPS traffic, we can allow the “Apache Full” profile and then delete the redundant “Apache” profile allowance:

$ sudo ufw allow 'Apache Full'
$ sudo ufw delete allow 'Apache'

An example of your status:

$ sudo ufw status


Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Apache Full                ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Apache Full (v6)           ALLOW       Anywhere (v6)

If you do not have ufw enabled, you will see:

Status: inactive

To enable ufw:

$ sudo ufw allow ssh
$ sudo ufw enable

You will receive a warning that says the command may disrupt existing SSH connections. We already set up a firewall rule that allows SSH connections, so it should be fine to continue. Respond to the prompt with ‘y'.

check status:

$ sudo ufw status verbose

then, for all necessary connections:

$ sudo ufw allow http
$ sudo ufw allow https
$ sudo ufw allow ftp

and you can allow any other connections that may be necessary, check the link above for more options.

Then follow follow the steps above to allow HTTPS traffic.

7. Enable the changes in Apache

$ sudo a2enmod ssl
$ sudo a2enmod headers
$ sudo a2ensite default-ssl
$ sudo a2enconf ssl-params

To check for syntax errors:

sudo apache2ctl configtest

If everything is successful, you will get a result that looks like this:

AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
Syntax OK

Restart Apache:

sudo systemctl restart apache2

8. Test Encryption

Open your web browser and type https:// followed by your server's domain name or IP into the address bar:


Because the certificate we created isn't signed by one of your browser's trusted certificate authorities, you will likely see a warning saying that your connection in not secure … This is expected and normal. We are only interested in the encryption aspect of our certificate, not the third party validation of our host's authenticity. Click “ADVANCED” and then the link provided to proceed to your host anyways (Add Exception -> Confirm Security Exception)

You should be taken to your site. If you look in the browser address bar, you will see a lock with an yellow “!” over it (or something similar). In this case, this just means that the certificate cannot be validated. It is still encrypting your connection.

To check if Apache is redirecting HTTP to HTTPS, just type in http in the beginning of the url:


You should be redirected to the https url.

9. Change to a permanent Redirect

If your redirect worked correctly and you are sure you want to allow only encrypted traffic, you should modify the unencrypted Apache Virtual Host again to make the redirect permanent.

Open your server block configuration file again:

$ sudo nano /etc/apache2/sites-available/000-default.conf

Find the Redirect line we added earlier. Add ‘permanent' to that line, which changes the redirect from a 302 temporary redirect to a 301 permanent redirect:

<VirtualHost *:80>
        . . .

        Redirect permanent "/" "https://your_domain_or_IP/"

        . . .

Ctrl-X then ‘Y' to save and exit.

Check your configuration for syntax errors:

$ sudo apache2ctl configtest

When you're ready, restart Apache to make the redirect permanent:

$ sudo systemctl restart apache2

Adding a crontab

As the certificate currently expires after 90 days by default, to automatically renew the certificate let’s create a cronjob:

sudo crontab -e

This will open the crontab file for the root user. Add the following line to the crontab file (substitute ‘username' with your username:

0 0 * * 0 /home/username/certbot-auto renew

Ctrl+X, then ‘Y' to save and exit.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.