How to get free SSL certificate

TL;DR

  1. curl --silent https://raw.githubusercontent.com/srvrco/getssl/master/getssl > ~/getssl ; chmod 700 ~/getssl
  2. ~/getssl -c site.com
  3. openssl genrsa 4096 > ~/.getssl/account.key
  4. openssl dhparam -out ~/.getssl/dhparam.pem 4096
  5. echo "CA=\"https://acme-v02.api.letsencrypt.org/directory\"
    ACCOUNT_EMAIL=\"your@email.com\"
    ACCOUNT_KEY_LENGTH=4096
    ACCOUNT_KEY=\"/root/.getssl/account.key\"
    PRIVATE_KEY_ALG="rsa"
    ACL=('/var/www/site.com/.well-known/acme-challenge')
    RELOAD_CMD=\"service apache2 restart\"
    " > ~/.getssl/site.com/getssl.cfg
  6. Apache configuration:

    SSLEngine on

    SSLCertificateFile /root/.getssl/site.com/site.com.crt
    SSLCertificateKeyFile /root/.getssl/site.com/site.com.key
    SSLCertificateChainFile /root/.getssl/site.com/chain.crt

    SSLOpenSSLConfCmd DHParameters “/root/.getssl/dhparam.pem”

    header set Strict-Transport-Security “max-age=31536000;”
    header set Content-Security-Policy-Report-Only “default-src https:; script-src https: ‘unsafe-eval’ ‘unsafe-inline’; style-src https: ‘unsafe-inline’; img-src https: data:; font-src https: data:; report-uri /csp-report”

  7. -OR- NGINX configuration:

    ssl on;

    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_session_cache shared:SSL:50m;
    ssl_prefer_server_ciphers on;

    ssl_dhparam /root/.getssl/dhparam.pem;

    ssl_certificate /root/.getssl/site.com/chain.crt;
    ssl_certificate_key /root/.getssl/site.com/site.com.key;

    add_header Strict-Transport-Security “max-age=31536000;”;
    add_header Content-Security-Policy-Report-Only “default-src https:; script-src https: ‘unsafe-eval’ ‘unsafe-inline’; style-src https: ‘unsafe-inline’; img-src https: data:; font-src https: data:; report-uri /csp-report”;

  8. ~/getssl site.com

In cron (crontab -e) (Why?):
23 5 * * * /root/getssl -u -a -q

Ok, what’s going on? (Or something went wrong)

Theory

We are using https://letsencrypt.org/ CA (Certificate Authority) to obtain certificate.

It is designed to be used as a fully automated service, using scripts for creating new certificates, renewing them, verifying domains ownership etc.

Automated Certificate Management Environment (ACME) is used for communication between letsencrypt.org and your environment. We are using GetSSL client for this purpose.

It is assumed n all the examples that we are working from root user, our E-mail is your@email.com and domain site.com. Change any of these to fit your needs.

Configuration

At first we need to install GetSSL client (We will install it to our home directory):
curl --silent https://raw.githubusercontent.com/srvrco/getssl/master/getssl > ~/getssl ; chmod 700 ~/getssl
After that we have getssl executable. Create needed folders for your domain:
~/getssl -c site.com
Once you’ve done it, new folder ~/.getssl/site.com will be created.

Open ~/.getssl/site.com/getssl.cfg and modify it and set values to be specific to you.

Minimal configuration that worked for me:

CA=”https://acme-v02.api.letsencrypt.org/directory”

ACCOUNT_EMAIL=”your@email.com
ACCOUNT_KEY_LENGTH=4096
ACCOUNT_KEY=”/root/.getssl/account.key
PRIVATE_KEY_ALG=”rsa”

ACL=(‘/var/www/site.com/.well-known/acme-challenge‘)

RELOAD_CMD=”service apache2 restart

Marked parts are that you have to modify. Some additional info:
ACCOUNT_KEY option points to your account private key (Will be explained below).
ACL option says how domain ownership verification will be performed. Generally, it works as follows: letsencrypt service sends you some string that you have to put in a file it also sends you (All this done in automated way) and tries to access it. Given example says script to use direct file editing (It also can be done via SSH, FTP, SFTP etc., see GetSSL documentation for explanations). Path must point to directory on your site so script could modify file inside of it. Example above points to https://site.com/.well-known/acme-challenge (.well-known/acme-challenge part must not be modified).
RELOAD_CMD option says how your web server can be restarted. Depending on your OS and environment this can be service nginx restart, systemctl restart nginx.service or any else. Also keep in mind that you probably need to prepend sudo to this command in case your script is executed not from admin user.

Keep in mind that provided in configuration CA is “production” one and has some rate limits (E.g. not more than 5 cetificates for one domain per week). If you need some testing, you can use CA=”https://acme-staging-v02.api.letsencrypt.org/directory”, which has no limits but doesn’t issue full certificates (You’ll see security warning when accessing domain using its certificate). After you finish all testings, you can switch to working CA.

DH Parameters

We need to setup Diffie-Hellman parameters for SSL key-exchange mechanism to work securely.

First, generate configuration file (This can take a particular time, around 5 minutes):
openssl dhparam -out ~/.getssl/dhparam.pem 4096

In next step we will use this file for web server configuration.

Web server setup

You must setup your web server (Apache, nginx etc.) in order your site to work via https. In general you have to point to your certificate files. Configuration may look like this (For Apache server):

<VirtualHost 192.168.0.1:443>
DocumentRoot /var/www/site.com
ServerName site.com

SSLEngine on

SSLCertificateFile /root/.getssl/site.com/site.com.crt
SSLCertificateKeyFile /root/.getssl/site.com/site.com.key
SSLCertificateChainFile /root/.getssl/site.com/chain.crt

SSLOpenSSLConfCmd DHParameters “/root/.getssl/dhparam.pem

header set Strict-Transport-Security “max-age=31536000;”
header set Content-Security-Policy-Report-Only “default-src https:; script-src https: ‘unsafe-eval’ ‘unsafe-inline’; style-src https: ‘unsafe-inline’; img-src https: data:; font-src https: data:; report-uri /csp-report”
</VirtualHost>

NGINX server:

ssl on;

ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_session_cache shared:SSL:50m;
ssl_prefer_server_ciphers on;

ssl_dhparam /root/.getssl/dhparam.pem;

ssl_certificate /root/.getssl/site.com/site.com.crt;
ssl_certificate_key /root/.getssl/site.com/site.com.key;

add_header Strict-Transport-Security “max-age=31536000;”;
add_header Content-Security-Policy-Report-Only “default-src https:; script-src https: ‘unsafe-eval’ ‘unsafe-inline’; style-src https: ‘unsafe-inline’; img-src https: data:; font-src https: data:; report-uri /csp-report”;


Take a note of Strict-Transport-Security and Content-Security-Policy-Report-Only headers configuration. These are strongly recommended because while they don’t need any additional resources, they allow you to obtain an A+ security rating (You can check your site’s rating at SSL Labs site) which is really cool to have :)

Thanks @DimaSmirnov for this information.

Account key

You can have multiple accounts on letsencrypt, each identified by email & key pair (Account option starts with ACCOUNT_ in GetSSL configuration file).
E-mail can be any you have. Under every account you can have multiple domains with unique certificate for every one of them. But account key is single. If you don’t have any key pair for your account, you can generate one with the command (And place it to .getssl folder in your home directory):
openssl genrsa 4096 > ~/.getssl/account.key

Getting the certificate

After you configured web server and GetSSL client, you are ready to go. Request a certificate for your domain by simply
~/getssl site.com

This will send new certificate request, verify domain ownership, create new certificate and restart web server.

Cron task

Letsencrypt offers certificates only for 90 days. It is a good idea to put renewing in automated way in order to not to forget to renew your certificate and not to do it manually. We’ll create new daily cron task which will renew any certificate which is about to end.
Open crontab: crontab -e
And add new task:

23 5 * * * /root/getssl -u -a -q

-u says to check for new version of GetSSL client on startup
-a says to check all certificates (All domains you configured)
-q is a quiet mode

That’s it, now you have your fully trusted SSL certificate with automated renewal mechanism.

Please fill free to ask for some help in comments or report for any broken links.

Share Button

1 comment

Leave a Reply

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