Getting started with Let's Encrypt SSL Certificates on Ubuntu
This tutorial will guide you through your very first configuration of an SSL website with Let's Encrypt certification. Let's Encrypt is a new SSL authority that provides free SSL certificates. We are going to use two existing tutorials (“How to setup an intermediate compatible SSL website with Let's Encrypt certificate” and “The Perfect Server - Ubuntu 15.10 (Wily Werewolf) with Apache, PHP, MySQL, PureFTPD, BIND, Postfix, Dovecot and ISPConfig 3”).
The setup described here is compatible with any Ubuntu LAMP server, so you can use this one as the basis setup too.
This tutorial will show you how to setup Let's Encrypt on Servers without ISPConfig 3 as there will be a direct implementation of the Let's Encrypt service in the next ISPConfig 3 release (version 3.1) soon. So if you plan to use ISPConfig, wait for the 3.1 release and also a new tutorial.
Creating the website
The 1st step is to create the website configuration and directory and enable SSL (Apache mod_ssl) for it. It’s up to you if you use the default configuration for one website on a server or you plan to use multiple vhosts to host more than one domain. For more reliable and scalable usage, I’ll create a vhost configuration for my “lab” domain isp1.cloudapp.net from Azure.
All vhosts are stored in the /etc/apache2/sites-available directory by default on Ubuntu and Debian. Run the following command to retrieve a list of existing vhost configuration files.
ls -l /etc/apache2/sites-available/
My output looks like this:
root@isp1:/home/falco# ls -l /etc/apache2/sites-available/
-rw-r--r-- 1 root root 1332 May 20 2015 000-default.conf
-rw-r--r-- 1 root root 6437 May 20 2015 default-ssl.conf
We can now use the "default" configuration file for cloning and edit it or we can use our own configuration. I prefer using my own configuration as I do that for many years, so let’s create a new vhost by creating the file:
vi /etc/apache2/sites-available/isp1.cloudapp.net.conf
In this file paste, the following content:
<VirtualHost *:80>
ServerName isp1.cloudapp.net
ServerAlias www.isp1.cloudapp.net
DocumentRoot /home/web/isp1.cloudapp.net/public_html
ErrorLog /home/web/isp1.cloudapp.net/log/habdak.eu_error_log
CustomLog /home/web/isp1.cloudapp.net/log/habdak.eu_access_log combinedScriptAlias /cgi-bin/ /home/web/isp1.cloudapp.net/cgi-bin/
DirectoryIndex index.html index.htm index.php index.php4 index.php5
<Directory /home/web/isp1.cloudapp.net/public_html>
Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
allow from all
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
Require all granted
AddType application/x-httpd-php .php
AddType application/json .json
</Directory>
<Directory /home/web/isp1.cloudapp.net/cgi-bin>
allow from all
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
Require all granted
</Directory>
RemoveHandler .php
RemoveHandler .php5
php_admin_value engine Off
IPCCommTimeout 301
FcgidMaxRequestLen 1073741824
php_value memory_limit 128M
php_value suhosin.session.encrypt Off
</VirtualHost>
<VirtualHost *:443>
ServerName isp1.cloudapp.net
ServerAlias www.isp1.cloudapp.net
DocumentRoot /home/web/isp1.cloudapp.net/public_html
ErrorLog /home/web/isp1.cloudapp.net/log/habdak.eu_error_log
CustomLog /home/web/isp1.cloudapp.net/log/habdak.eu_access_log combined
ScriptAlias /cgi-bin/ /home/web/isp1.cloudapp.net/cgi-bin/
DirectoryIndex index.html index.htm index.php index.php4 index.php5
<Directory /home/web/isp1.cloudapp.net/public_html >
Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
allow from all
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
Require all granted
AddType application/x-httpd-php .php
AddType application/json .json
</Directory>
<Directory /home/web/isp1.cloudapp.net/cgi-bin >
allow from all
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
Require all granted
</Directory>
RemoveHandler .php
RemoveHandler .php5
php_admin_value engine Off
IPCCommTimeout 301
FcgidMaxRequestLen 1073741824
php_value memory_limit 128M
php_value suhosin.session.encrypt Off
SSLEngine on
SSLCertificateFile /home/web/isp1.cloudapp.net /ssl.cert
SSLCertificateKeyFile /home/web/isp1.cloudapp.net /ssl.key
SSLCACertificateFile /home/web/isp1.cloudapp.net /ssl.ca
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLProtocol All -SSLv2 -SSLv3
SSLCompression off
SSLHonorCipherOrder On
</VirtualHost>
Replace the domain name with your domain wherever it occurs and save the file. To activate the configuration, run:
a2ensite isp1.cloudapp.net.conf
Now reate the folders for the website:
mkdir /home/web
mkdir /home/web/isp1.cloudapp.net
mkdir /home/web/isp1.cloudapp.net/public_html
mkdir /home/web/isp1.cloudapp.net/cgi-bin
mkdir /home/web/isp1.cloudapp.net/logs
Restart apache to apply the new configuration:
sudo service apache2 restart
Now we have to generate the certificate files.
Install Let's Encrypt and generate your first SSL Certificate
I prefer to use the root login for administration instead of running sudo before each command, so let’s su to root user:
sudo su
Navigate to your roots home directory:
cd ~root
Install git for fetching the Let's Encrypt git repository files:
apt-get install git
Now clone the Let's Encrypt git repository:
git clone https://github.com/letsencrypt/letsencrypt.git letsencrypt
Navigate to your new letsencrypt folder:
cd letsencrypt
And request your SSL certificate:
./letsencrypt-auto certonly --webroot -w /home/web/isp1.cloudapp.net/public_html -d isp1.cloudapp.net
If you request a certificate for the master domain (1st level domain aka cloudapp.net) use -d parameter twice. With and without www prefix like this:
./letsencrypt-auto certonly --webroot -w /home/web/cloudapp.net/public_html -d cloudapp.net -d www.cloudapp.net
If you won’t do this, the certificate won’t be valid for visitors opening your site with www prefix.
You can also add other subdomains to one certificate. For example, if your subdomain admin.cloudapp.net matches the same site (the same folder on the server), you should add it to this certificate as well. Unfortunately, you can’t use a wildcard like (*.cloudapp.net) with let's encrypt.
Let's Encrypt will automatically update all dependencies and guide you through its setup. All you need to do is wait for the prompt window asking you for your e-mail address. This address is used for recovering lost data only.
Your new keys are now stored in /etc/letsencrypt/ by default. We are going to link them to our website directory so we can manage the keys later.
ln -s /etc/letsencrypt/archive/isp1.cloudapp.net/cert1.pem /home/web/isp1.cloudapp.net/ssl.cert
ln -s /etc/letsencrypt/archive/isp1.cloudapp.net/chain1.pem /home/web/isp1.cloudapp.net/ssl.ca
ln -s /etc/letsencrypt/archive/isp1.cloudapp.net/privkey1.pem /home/web/isp1.cloudapp.net/ssl.key
Now you should be able to access your website with SSL. Let's Encrypt will automatically inform you about expiring certificates in time by sending you an e-mail to the address you have provided within the installation of Let's Encrypt.