Jump to content

Welcome to 247fixes PC Help Forum

Welcome to 247fixes PC Help Forum! Like most online communities you must first register to view or post in our community, but don't worry this is a simple free process that requires minimal information. Take advantage of it immediately, Register Now or Sign In.

Please read over Welcome To 247Fixes to learn more about our site.

  • Start new topics and reply to others
  • Subscribe to topics and forums to get automatic updates
  • Add events to our community calendar
  • Get your own profile and make new friends
  • Customize your experience here
Guest Message by DevFuse

Tutorial info Visit support topic

  • Added on: Mar 25 2016 07:48 AM
  • Views: 459

* * * * *
0 Ratings

Generating SSL Certificates using LetsEncrypt Certification Authority

LetsEncrypt is free certification authority provided by the ISRG (Internet Security Research Group) who's goal is to help bring encryption to the Internet without all the big fees of a traditional certification authority.

Posted by Dominick M. on Mar 25 2016 07:48 AM

LetsEncrypt is an Automated Certificate Management Environment (ACME)[1] based certification authority in which utilizes the Linux command line to generate SSL certificates. These SSL Certificates rely on ACME .well-known challenges for verification, which ties into DNS, we'll get into that in a bit.
System Requirements
The Let's Encrypt Client presently only runs on Unix-ish OSes that include Python 2.6 or 2.7; Python 3.x support will be added after the Public Beta launch. The client requires root access in order to write to /etc/letsencrypt,/var/log/letsencrypt, /var/lib/letsencrypt; to bind to ports 80 and 443 (if you use the standalone plugin) and to read and modify webserver configurations (if you use the apache or nginx plugins). If none of these apply to you, it is theoretically possible to run without root privileges, but for most users who want to avoid running an ACME client as root, either letsencrypt-nosudo or simp_le are more appropriate choices.
The Apache plugin currently requires a Debian-based OS with augeas version 1.0; this includes Ubuntu 12.04+ and Debian 7+.
Installing LetsEncrypt
You need root or sudo privileges on your server to install using these methods. If you cannot obtain said access (for example, you are using a public shell service), see the information for letsencrypt-nosudo below
Installation from Distribution Package
At the time of this tutorial, the following distributions have functional LetsEncrypt packages within package repos. See Installing From Source below if your distro is not within this list

  • FreeBSD
  • OpenBSD
  • Arch Linux
  • Debian (Stretch, Sid, Wheezy)
  • Fedora
  • Gentoo


  • Port: cd /usr/ports/security/py-letsencrypt && make install clean
  • Package: pkg install py27-letsencrypt



  • Port: cd /usr/ports/security/letsencrypt/client && make install clean
  • Package: pkg_add letsencrypt

Arch Linux
sudo pacman -S letsencrypt letsencrypt-apache
If you run Debian Stretch, Sid, or Wheezy, you can install letsencrypt packages.

sudo apt-get update
sudo apt-get build-dep letsencrypt
sudo apt-get install letsencrypt python-letsencrypt-apache
If you don’t want to use the Apache plugin, you can omit the python-letsencrypt-apache package.
Packages for Debian Jessie are not yet available, and must be compiled from source.

sudo dnf install letsencrypt
The official Let’s Encrypt client is available in Gentoo Portage. If you want to use the Apache plugin, it has to be installed separately:
emerge -av app-crypt/letsencrypt
emerge -av app-crypt/letsencrypt-apache
Currently, only the Apache plugin is included in Portage. However, if you want the nginx plugin, you can use Layman to add the mrueg overlay which does include the nginx plugin package:
emerge -av app-portage/layman
layman -S
layman -a mrueg
emerge -av app-crypt/letsencrypt-nginx
When using the Apache plugin, you will run into a “cannot find a cert or key directive” error if you’re sporting the default Gentoo httpd.conf. You can fix this by commenting out two lines in/etc/apache2/httpd.conf as follows:
<IfDefine SSL>
LoadModule ssl_module modules/mod_ssl.so
to this
#<IfDefine SSL>
LoadModule ssl_module modules/mod_ssl.so
For the time being, this is the only way for the Apache plugin to recognize the appropriate directives when installing the certificate. Note: this change is not required for the other plugins.
Installing From Source
We need to make sure git and it's development libraries are installed. This is easily done by installing the following
apt-get install build-essential pkg-config git
yum groupinstall "Development Tools"; yum install pkgconfig git
Other distributions: Use your respective package manager, and install development tools (equivalent to Yum's groupinstall "Development Tools" or Apt's apt-get install build-essential)
[email protected]:~$ git clone https://github.com/letsencrypt/letsencrypt
[email protected]:~$ cd letsencrypt
[email protected]:~/letsencrypt$ ./letsencrypt-auto --help
Now that you've got LetsEncrypt installed, let's go over how it works. If you've installed it from source, you will need to use the lets-encrypt-auto wrapper to generate your SSL certificates. Note this should be ran as root, because when we generate SSL all our important files (the certificate itself, CA Certificate, and Private key) will be stored in /etc/letsencrypt/live/domain.tld/
Upon first run, LetsEncrypt will create the Python virtual environment that is required to generate SSL certificates. This takes a little bit of time depending on your CPU. After it sets up the virtual environment, we will be able to generate SSL certificates.
LetsEncrypt has four different methods of ACME Verification, as listed below
  • Apache/2.x
    • This has been confirmed as working on Debian Jessie and Ubuntu 12.04+
    • This is the most common used plugin as apache is a widely used HTTP Daemon (httpd)
  • Standalone
    • For more advanced users, this allows for manual intervention from the system administrator for verification
      • You CANNOT have any service bound to port 80 or 443 or this will fail. If you choose to use standalone on a server that has an httpd, stop the httpd before continuing. After issuing the standalone trigger in the letsencrypt command, it will paste an output of commands you should run as a superuser to establish a basic HTTP server based off the Python virtual environment that will supply LetsEncrypt with the challenge-response for the ACME .well-known query
  • Webroot
    • This is the best module to use if you are already running a httpd server that can be considered mission-critical and cannot be shutdown. This module will add a /.well-known sub-directory to the domains you are requesting certificates for so LetsEncrypt can verify without you needing to explain why your web server went down :P
  • Nginx
    • This module is highly experimental and for the most part is not packaged with LetsEncrypt. LE Developers recommend you use the webroot module, or even the standalone module, before trying to use the nginx module.
Here's an example that I've actually used for therock247uk to secure one of his cPanel VPS servers. This is a CentOS 6 server running cPanel/WHM
Note: Before you even consider generating the SSL certificate, the domains you want certificates for need to resolve to your server. This is how ACME works.

# Check DNS records

host 247fixes.co.uk
host server1.247fixes.co.uk

# Safe to assume that DNS works. Continue on

# Stop the HTTPD. cPanel does not play nicely with webroot, so we are going to request a certificate using the "certonly" switch

service httpd stop

# Generate the request to LetsEncrypt

cd ~/letsencrypt
./letsencrypt-auto --debug certonly --text --agree-tos --email [email protected] --renew-by-default --standalone -d 247fixes.co.uk -d server1.247fixes.co.uk

# We can restart the web server now that the certificate is generated

service httpd start

# As certificates are generated, their respective RSA keys are generated, example, the current cert key is
# Lets be lazy and make cat paste the output to the shell, allowing us to simply copy and paste the values into WHM
# We are going to pull the fullchain.pem rather than the chain.pem, we will explain why later

cat /etc/letsencrypt/live/247fixes.co.uk/fullchain.pem

# When you generate the certificates, the first BEGIN to END CERTIFICATE in fullchain.pem is your CERTIFICATE then CA BUNDLE. You MUST fill these both out on cPanel under Home -> Service Configuration -> Manage Service SSL Certificates
# Grab the RSA Key, fill it out in WHM as well

cat /etc/letsencrypt/live/247fixes.co.uk/privkey.pem
Let's explain the files generated by LetsEncrypt, and why we favor fullchain.pem over chain.pem or cert.pem
Upon successful generation, you will have "chain.pem", "fullchain.pem", "privkey.pem" and "cert.pem"
  • cert.pem
    • This is the actual certificate, by itself, generated for your server.
  • chain.pem
    • This is the Certification Authority's certification that must be presented to connecting clients to verify the authenticity of your server's certificate
  • fullchain.epm
    • Yeah, I think you got it by now, this is the chain.pem and the cert.pem put together in one.
  • privkey.pem
    • Do I need to explain this? This is the corresponding RSA Private Key that goes hand in hand with your certificate
In most cases, you will be able to specify one single certificate file (in our case, fullchain.pem) to verify your certificate, and since the CA's certificate is included, we don't need to waste time or resources specifying another file to verify the cert, meaning all you really need is the fullchain.pem and privkey.pem
Specifying multiple domains for a SAN (Subject Alternative Name)
This is as easy as adding additional -d domain.tld to the inital LetsEncrypt command, as depicted above for therock247uk's cPanel server.
Certificate Expiry Time
Each SSL certificate generated by LetsEncrypt expires after 90 days of initial generation. If you automatically renew the certificates using the LetsEncrypt Client, the expiry time will be 30 to 60 days. Renewal of certificates can easily be automated by using cron, which is outside the scope of this tutorial.
Hopefully this is enough information for the majority of people to understand how LetsEncrypt works, and how to secure your website(s) for free. If you have questions, please see the support topic and I'll be more than happy to help you. :)
Appendix 1: LetsEncrypt without root or sudo
  • openssl
  • python
How to use the signing script
First, you need to generate an user account key for Let's Encrypt. This is the key that you use to register with Let's Encrypt. If you already have user account key with Let's Encrypt, you can skip this step.
openssl genrsa 4096 > user.key
openssl rsa -in user.key -pubout > user.pub
Second, you need to generate the domain key and a certificate request. This is the key that you will get signed for free for your domain (replace "example.com" with the domain you own). If you already have a domain key and CSR for your domain, you can skip this step.
#Create a CSR for example.com
openssl genrsa 4096 > domain.key
openssl req -new -sha256 -key domain.key -subj "/CN=example.com" > domain.csr

#Alternatively, if you want both example.com and www.example.com
openssl genrsa 4096 > domain.key
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) > domain.csr
Third, you run the script using python and passing in the path to your user account public key and the domain CSR. The paths can be relative or absolute. By default the script will ask you to start a webserver on port 80. If you already have one, use the --file-based option instead.
python sign_csr.py --public-key user.pub domain.csr > signed.crt
When you run the script, it will ask you do do some manual commands. It has to ask you to do these because it doesn't know your private key or have access to your server. You can edit the manual commands to fit your situation (e.g. if your sudo user is different or private key is in a different location).
NOTE: When the script asks you to run these manual commands, you need to run them in a separate terminal window. You need to keep the script open while you run them. They sign temporary test files that the script created, so if you exit or continue the script before you run the commands, those test files will be destroyed before they can be used correctly (and you'll have to run the script again).
The *.json and *.sig files are temporary files automatically generated by the script and will be destroyed when the script stops. They only contain the protocol requests and signatures. They do NOT contain your private keys because this script does not have access to your private keys. Help text
[email protected]:~$ python sign_csr.py --help
usage: sign_csr.py [-h] -p PUBLIC_KEY [-e EMAIL] csr_path

Get a SSL certificate signed by a Let's Encrypt (ACME) certificate authority and
output that signed certificate. You do NOT need to run this script on your
server and this script does not ask for your private keys. It will print out
commands that you need to run with your private key or on your server as root,
which gives you a chance to review the commands instead of trusting this script.


* openssl
* python

Example: Generate an account keypair, a domain key and csr, and have the domain csr signed.
$ openssl genrsa 4096 > user.key
$ openssl rsa -in user.key -pubout > user.pub
$ openssl genrsa 4096 > domain.key
$ openssl req -new -sha256 -key domain.key -subj "/CN=example.com" > domain.csr
$ python sign_csr.py --public-key user.pub domain.csr > signed.crt

positional arguments:
csr_path path to your certificate signing request

optional arguments:
-h, --help show this help message and exit
-p PUBLIC_KEY, --public-key PUBLIC_KEY
path to your account public key
-e EMAIL, --email EMAIL
contact email, default is webmaster@<shortest_domain>
-f, --file-based if set, a file-based response is used
[email protected]:~$
Example use of the signing script Commands (what you do in your main terminal window)
[email protected]:~$ openssl genrsa 4096 > user.key
Generating RSA private key, 4096 bit long modulus
e is 65537 (0x10001)
[email protected]:~$ openssl rsa -in user.key -pubout > user.pub
writing RSA key
[email protected]:~$ openssl genrsa 4096 > domain.key
Generating RSA private key, 4096 bit long modulus
e is 65537 (0x10001)
[email protected]:~$ openssl req -new -sha256 -key domain.key -subj "/CN=letsencrypt.daylightpirates.org" > domain.csr
[email protected]:~$ python sign_csr.py --public-key user.pub domain.csr > signed.crt
Reading pubkey file...
Found public key!
Reading csr file...
Found domains letsencrypt.daylightpirates.org
STEP 1: What is your contact email? ([email protected]) [email protected]
Building request payloads...
STEP 2: You need to sign some files (replace 'user.key' with your user private key).

openssl dgst -sha256 -sign user.key -out register_KN2ihH.sig register_ABUO4T.json
openssl dgst -sha256 -sign user.key -out domain_BbpWG4.sig domain_rSKa5G.json
openssl dgst -sha256 -sign user.key -out challenge_fo6_ib.sig challenge_e3gHzd.json
openssl dgst -sha256 -sign user.key -out cert_36OUdW.sig cert_3IZULZ.json

Press Enter when you've run the above commands in a new terminal window...
Registering [email protected]..
Already registered. Skipping...
Requesting challenges for letsencrypt.daylightpirates.org...
STEP 3: You need to sign some more files (replace 'user.key' with your user private key).

openssl dgst -sha256 -sign user.key -out response_ATE3Yu.sig response_P87LMt.json

Press Enter when you've run the above commands in a new terminal window...
STEP 4: You need to run this command on letsencrypt.daylightpirates.org (don't stop the python command until the next step).

sudo python -c "import BaseHTTPServer; \
h = BaseHTTPServer.BaseHTTPRequestHandler; \
h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"eyJhbGciOiAiUlMyNTYifQ\", \"payload\": \"ewogICAgInRscyI6IGZhbHNlLCAKICAgICJ0b2tlbiI6ICJkbzVaWkMwMHVwZmNFN0tjeEhzOGNyS2FNaE02UFdBdTMtMnVwZ00zRG00IiwgCiAgICAidHlwZSI6ICJzaW1wbGVIdHRwIgp9\", \"signature\": \"Gp5V68da_XdC96piXs1YOhrv4USOQBNnhIL-CMmxvKSigmxAJ8z00xsgWS6nsYD8LPpMVa3GkXhb10qfbymPiWhtMpMYZ31kMLFwgpHrY9xkiNP-WK9Zljz6L-WAzxCOmF1Ov71z_75iEJij86E2f9EmTjDlmDmGAjP9lziII42uyyjjIZg9claU1GtFZUrfXd-uNHHEGHFUpoyLHQcyWCP1T04Xx4q4dY51VeOJNOmIv9csIjkbOma7EqFMAHwYAplAUE45FQ5N9lJvpymD49BoEgQj_kjH-UPnxO3q0QB0i-MJJCiwQYAhMKV618jV9rNE181zJ1FRkX48knMzqoE4oG3yEFUg2D_vAdFG3VCuotnuxrZ7BEzDPWyEm0z8XakxWQW-xHSADtKWRr1qsQCy7qVsoAKnVFQ_1b4rAzET1YfrmhSH4MVhMB5n9tOnjtPQ0OsJVbf0oVLh5AC1rbXe68weOQExDVJgsk56x3FvvwrmdaLe2TnbPJmzpkYUf1OK88e8KmhVYb34veuY1luDOBJQyQ9fOAGZC0F-g7SpWg1lp3hQzf5enkycHMK-fNAfFH7t1m1Ej_CvUuxfBVhI0W8ANpFWL4r8PxTZaZzE6NO38MYgB9nrICiKJuuTQQbsXdjOm22QuxrG1XpWA-vQCtbk-L891Ko6MdAUMzQ\"}'); \
s = BaseHTTPServer.HTTPServer(('', 80), h); \

Press Enter when you've got the python command running on your server...
Requesting verification for letsencrypt.daylightpirates.org...
Waiting for letsencrypt.daylightpirates.org challenge to pass...
Passed letsencrypt.daylightpirates.org challenge!
Requesting signature...
Certificate signed!
You can stop running the python command on your server (Ctrl+C works).
[email protected]:~$ cat signed.crt
[email protected]:~$
Manual Commands (the stuff the script asked you to do in a 2nd terminal)

#first set of signed files
[email protected]:~$ openssl dgst -sha256 -sign user.key -out register_KN2ihH.sig register_ABUO4T.json
[email protected]:~$ openssl dgst -sha256 -sign user.key -out domain_BbpWG4.sig domain_rSKa5G.json
[email protected]:~$ openssl dgst -sha256 -sign user.key -out challenge_fo6_ib.sig challenge_e3gHzd.json
[email protected]:~$ openssl dgst -sha256 -sign user.key -out cert_36OUdW.sig cert_3IZULZ.json
[email protected]:~$

#second set of signed files
[email protected]:~$ openssl dgst -sha256 -sign user.key -out response_ATE3Yu.sig response_P87LMt.json
[email protected]:~$
Server Commands (the stuff the script asked you to do on your server)

[email protected]:~$ sudo python -c "import BaseHTTPServer; \
> h = BaseHTTPServer.BaseHTTPRequestHandler; \
> h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"eyJhbGciOiAiUlMyNTYifQ\", \"payload\": \"ewogICAgInRscyI6IGZhbHNlLCAKICAgICJ0b2tlbiI6ICJkbzVaWkMwMHVwZmNFN0tjeEhzOGNyS2FNaE02UFdBdTMtMnVwZ00zRG00IiwgCiAgICAidHlwZSI6ICJzaW1wbGVIdHRwIgp9\", \"signature\": \"Gp5V68da_XdC96piXs1YOhrv4USOQBNnhIL-CMmxvKSigmxAJ8z00xsgWS6nsYD8LPpMVa3GkXhb10qfbymPiWhtMpMYZ31kMLFwgpHrY9xkiNP-WK9Zljz6L-WAzxCOmF1Ov71z_75iEJij86E2f9EmTjDlmDmGAjP9lziII42uyyjjIZg9claU1GtFZUrfXd-uNHHEGHFUpoyLHQcyWCP1T04Xx4q4dY51VeOJNOmIv9csIjkbOma7EqFMAHwYAplAUE45FQ5N9lJvpymD49BoEgQj_kjH-UPnxO3q0QB0i-MJJCiwQYAhMKV618jV9rNE181zJ1FRkX48knMzqoE4oG3yEFUg2D_vAdFG3VCuotnuxrZ7BEzDPWyEm0z8XakxWQW-xHSADtKWRr1qsQCy7qVsoAKnVFQ_1b4rAzET1YfrmhSH4MVhMB5n9tOnjtPQ0OsJVbf0oVLh5AC1rbXe68weOQExDVJgsk56x3FvvwrmdaLe2TnbPJmzpkYUf1OK88e8KmhVYb34veuY1luDOBJQyQ9fOAGZC0F-g7SpWg1lp3hQzf5enkycHMK-fNAfFH7t1m1Ej_CvUuxfBVhI0W8ANpFWL4r8PxTZaZzE6NO38MYgB9nrICiKJuuTQQbsXdjOm22QuxrG1XpWA-vQCtbk-L891Ko6MdAUMzQ\"}'); \
> s = BaseHTTPServer.HTTPServer(('', 80), h); \
> s.serve_forever()" - - [24/Oct/2015 06:58:10] "GET /.well-known/acme-challenge/do5ZZC00upfcE7KcxHs8crKaMhM6PWAu3-2upgM3Dm4 HTTP/1.1" 200 -
^CTraceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python2.7/SocketServer.py", line 236, in serve_forever
File "/usr/lib/python2.7/SocketServer.py", line 155, in _eintr_retry
return func(*args)
[email protected]:~$

Powered by Tutorials 1.4.3 © 2017, by Michael McCune