
Let’s Encrypt is a new certificate authority backed
by Mozilla, Akamai, EFF, Facebook and others, which provides free, automated
SSL/TLS certificates. The public beta started on December 3, 2015 and a whole lot of certificates have been issued already:

Several clients to automate issuing, renewing and revoking certificates have been released both by the community and the Let’s Encrypt team. This post is an overview and comparison of 10 popular Let’s Encrypt clients:
- letsencrypt-auto, the official Let’s Encrypt client
- acme-tiny, a tiny semi-automatic Python implementation
- gethttpsforfree.com, a static website to assist the manual process
- simp_le, another Python implementation
- letsencrypt-nosudo, the predecessor of acme-tiny and gethttpsforfree
- acmetool, an ACME client in Go
- lego, an ACME client and library written in Go
- letsencrypt.sh, a Bash ACME client implemenation
- acme, ACME implementation in PHP
- lescript, a PHP library
Background
ACME
The Automated Certificate Management Environment (ACME)
protocol defines a way of automatically obtaining trusted certificates
without human intervention. First, the control of a domain has to be proven,
then the agent can request, renew and revoke certificates:

Certificates issued by Let’s Encrypt are valid for 90 days, and are expected to be renewed automatically. More background information can be found on the Let’s Encrypt - How It Works page.
At the time of writing, these rate limits has been in place:
- 10 Registrations per IP per 3 hours
- 5 Certificates per Domain per 7 days (incl. subdomains)
SSL Certificates & Signing
Obtaining a valid SSL certificate generally includes the following steps:
- You create a private and public key pair on the server.
- You create a Certificate Signing Request (CSR) which includes the domain name, organization name, the public key, and other information. The CSR is signed with your private key.
- You send the CSR to the certificate authority (in this case Let’s Encrypt).
- The certificate authority signs the request, thus producing a public certificate.
- You use the public certificate in your webserver.
For more information on configuring a webserver with certificates, check out these links:
Client Analysis
These tests are going to obtain a certificate for a domain such as www.example.com
and setting up automatic certificate renewal.
Domain ownership verification requires the ACME server being able to access a specific file
on the domain. To accomplish this, we assume a webserver is running and serves
files from /var/www/htdocs/ (the webroot) and it’s subdirectories. For instance, a file at /var/www/htdocs/.well-known/acme-challenge/8303 should be accessible via www.example.com/.well-known/acme-challenge/8303.
Official Let’s Encrypt Client
The official Let’s Encrypt client, letsencrypt-auto, is
a heavyweight, fully automated Python program with various modes of operation and installers (for instance to automagically update Apache and nginx configurations).
The standard client automatically installs various system dependencies via the standard package manager (see the source code and /bootstrap/), and sets up a virtualenv with
a number of Python dependencies. The client is also available as a Docker image,
which avoids the necessity to install packages system-wide.
In case of an error (eg. the ACME server is not reachable), the official client gracefully terminates with an info message.
The official Let’s Encrypt client also supports config files, which may be
easier to automate with a cronjob (see this post
for more infos).
- Official client, active community
- Well documented, and well tested
- Can do a lot of things, including server configs (experimental!)
- Accessible for non-technical users
- Complex program, many moving parts, hard to review
- Runs as root and installs dependencies without asking
Standard Installation
$ git clone https://github.com/letsencrypt/letsencrypt
$ cd letsencrypt
$ ./letsencrypt-auto --help
⇾ show output
$ ./letsencrypt-auto --help
Updating letsencrypt and virtual environment dependencies.......
Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt --help
letsencrypt [SUBCOMMAND] [options] [-d domain] [-d domain] ...
The Let's Encrypt agent can obtain and install HTTPS/TLS/SSL certificates. By
default, it will attempt to use a webserver both for obtaining and installing
the cert. Major SUBCOMMANDS are:
(default) run Obtain & install a cert in your current webserver
certonly Obtain cert, but do not install it (aka "auth")
install Install a previously obtained cert in a server
revoke Revoke a previously obtained certificate
rollback Rollback server configuration changes made during install
config_changes Show changes made to server config during installation
plugins Display information about installed plugins
Choice of server plugins for obtaining and installing cert:
--apache Use the Apache plugin for authentication & installation
--standalone Run a standalone webserver for authentication
(nginx support is experimental, buggy, and not installed by default)
--webroot Place files in a server's webroot folder for authentication
OR use different plugins to obtain (authenticate) the cert and then install it:
--authenticator standalone --installer apache
More detailed help:
-h, --help [topic] print this message, or detailed help on a topic;
the available topics are:
all, automation, paths, security, testing, or any of the subcommands or
plugins (certonly, install, nginx, apache, standalone, webroot, etc)
Obtaining a certificate
To obtain a certificate without stopping a running webserver, we are going to use the webroot method, which
only requires write access for the webroot to save the authentication file.
$ sudo ./letsencrypt-auto certonly \
--webroot --webroot-path /var/www/htdocs/ \
--email admin@example.com \
-d www.example.com
This command creates the private and public keys, generate a certificate signing request, get the challenge from the ACME server, saves it to the webroot, and downloads the signed certificate in /etc/letsencrypt/live/example.com/. The process
is fully automated and results in the certificate and private key, ready to be used by your webserver.
⇾ show list of generated files
$ tree /etc/letsencrypt/
.
├── accounts
│ └── acme-v01.api.letsencrypt.org
│ └── directory
│ └── 69e7ae92b1a61252a6989403c95a10c8
│ ├── meta.json
│ ├── private_key.json
│ └── regr.json
├── archive
│ └── www.example.com
│ ├── cert1.pem
│ ├── cert2.pem
│ ├── cert3.pem
│ ├── chain1.pem
│ ├── chain2.pem
│ ├── chain3.pem
│ ├── fullchain1.pem
│ ├── fullchain2.pem
│ ├── fullchain3.pem
│ ├── privkey1.pem
│ ├── privkey2.pem
│ └── privkey3.pem
├── csr
│ ├── 0000_csr-letsencrypt.pem
│ ├── 0001_csr-letsencrypt.pem
│ ├── 0002_csr-letsencrypt.pem
│ └── 0003_csr-letsencrypt.pem
├── keys
│ ├── 0000_key-letsencrypt.pem
│ ├── 0001_key-letsencrypt.pem
│ ├── 0002_key-letsencrypt.pem
│ └── 0003_key-letsencrypt.pem
├── live
│ └── www.example.com
│ ├── cert.pem -> ../../archive/www.example.com/cert3.pem
│ ├── chain.pem -> ../../archive/www.example.com/chain3.pem
│ ├── fullchain.pem -> ../../archive/www.example.com/fullchain3.pem
│ └── privkey.pem -> ../../archive/www.example.com/privkey3.pem
└── renewal
└── www.example.com.conf
Alternatively the offial Let’s Encrypt client includes a manual plugin, which
can generate a certificate from another computer than the webserver
(akin to gethttpsforfree.com or letsencrypt-nosudo).
You can run this plugin with the command ./letsencrypt-auto certonly --manual.
Renewal
To renew certificates automatically, simply add the --renew parameter to the above command:
$ sudo ./letsencrypt-auto certonly \
--renew \
--webroot --webroot-path /var/www/htdocs/ \
--email admin@example.com \
-d www.example.com
acme-tiny
Acme-tiny is a tiny Python script which assists with issuing and renewing certificates. You generate
the private key and create a certificate signing request (CSR) manually, and acme-tiny handles the rest (submitting the CSR
to the ACME server, receiving the authentication files, putting it in the acme-challenge folder and receiving the final certificate). The output of this script is the signed certificate.
- Documentation (in the README)
- Super simple, no dependencies
- Easy to embed in custom Python application
Installation
# Get a copy of acme-tiny
$ cd /opt
$ git clone https://github.com/diafygi/acme-tiny.git
$ cd acme-tiny
$ python acme_tiny.py --help
⇾ show output
$ python acme_tiny.py --help
usage: acme_tiny.py [-h] --account-key ACCOUNT_KEY --csr CSR --acme-dir
ACME_DIR [--quiet] [--ca CA]
This script automates the process of getting a signed TLS certificate from
Let's Encrypt using the ACME protocol. It will need to be run on your server
and have access to your private account key, so PLEASE READ THROUGH IT! It's
only ~200 lines, so it won't take long.
===Example Usage===
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /usr/share/nginx/html/.well-known/acme-challenge/ > signed.crt
===================
===Example Crontab Renewal (once per month)===
0 0 1 * * python /path/to/acme_tiny.py --account-key /path/to/account.key --csr /path/to/domain.csr --acme-dir /usr/share/nginx/html/.well-known/acme-challenge/ > /path/to/signed.crt 2>> /var/log/acme_tiny.log
==============================================
optional arguments:
-h, --help show this help message and exit
--account-key ACCOUNT_KEY
path to your Let's Encrypt account private key
--csr CSR path to your certificate signing request
--acme-dir ACME_DIR path to the .well-known/acme-challenge/ directory
--quiet suppress output except for errors
--ca CA certificate authority, default is Let's Encrypt
Obtaining a certificate
# Create a directory for the keys and cert
mkdir -p /etc/letsencrypt/www.example.com
cd /etc/letsencrypt/www.example.com
# Generate a private key
openssl genrsa 4096 > account.key
# Generate a domain private key (if you haven't already)
openssl genrsa 4096 > domain.key
# Create a CSR for www.example.com
openssl req -new -sha256 -key domain.key -subj "/CN=www.example.com" > domain.csr
# Create the challenge folder in the webroot
mkdir -p /var/www/htdocs/.well-known/acme-challenge/
# Get a signed certificate with acme-tiny
python /opt/acme-tiny/acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/htdocs/.well-known/acme-challenge/ > ./signed.crt
# Append the Let's Encrypt intermediate cert to your cert
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
⇾ show output
# openssl genrsa 4096 > account.key
Generating RSA private key, 4096 bit long modulus
...................................................................................................................++
.........................................................................................................++
e is 65537 (0x10001)
# openssl genrsa 4096 > domain.key
Generating RSA private key, 4096 bit long modulus
........................................++
.........................................................................................................................................................................................................................................................................................................................................................................................++
e is 65537 (0x10001)
# openssl req -new -sha256 -key domain.key -subj "/CN=www.example.com" > domain.csr
# mkdir -p /var/www/htdocs/.well-known/acme-challenge/
# python /opt/acme-tiny/acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/htdocs/.well-known/acme-challenge/ > ./signed.crt
Parsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying www.example.com...
www.example.com verified!
Signing certificate...
Certificate signed!
At this point chained.pem contains the signed certificate chain and, along with domain.key, can be used to run a http server
(more infos).
Renewal simply requires running this script again with the same parameters.
gethttpsforfree.com
gethttpsforfree.com is a website which helps users to manually generate all the necessary information to create a certificate signing request (CSR), guiding a user through the whole ACME process:
- Manually create a public and private key.
- Manually create a certificate signing request (CSR).
- Manually sign a number of requests with the private key.
- Manually verify ownership by serving the signed requests (either through an existing webserver or a simple Python webserver).
- The website tells the ACME server to check for the verifications, and in case of success provides you with the signed certificate.
The website provides OpenSSL commands at each step, and waits for the output of the commands to be pasted back into the website to verify the success. The website never asks for any kind of private key. It can be saved and used locally without any server side logic.
- Works as advertised
- Static site allows to save and use later
simp_le
- github.com/kuba/simp_le

- 112 commits, 9 contributors
- Mode: Fully or Semi-Automatic
- License: GPLv3
- Language: Python
- Lines of code: 775 Python, 126 Shell Script, 41 YAML
- Dependencies: Some
simp_le is an ACME client written in Python. It works similar to acme-tiny, but can
also generate the private key and CSR automatically. Requires a small number of dependencies to be installed.
Installation
$ cd /opt
$ git clone https://github.com/kuba/simp_le
$ cd simp_le
# Setup dependencies and run
$ ./bootstrap.sh
$ ./venv.sh
$ ./venv/bin/simp_le --help
⇾ show output
$ ./venv/bin/simp_le --help
Simple Let's Encrypt client.
-v, --verbose Increase verbosity of the logging. (default: False)
-h, --help Show this help message and exit.
--version Display version and exit.
--revoke Revoke existing certificate (default: False)
--test Run tests and exit. (default: False)
Webroot manager:
This client is just a sophisticated manager for $webroot/.well-known/acme-
challenge. You can (optionally) specify `--default_root`, and override
per-vhost with `-d example.com:/var/www/other_html` syntax.
-d DOMAIN:PATH, --vhost DOMAIN:PATH
Domain name that will be included in the certificate.
Must be specified at least once. (default: None)
--default_root PATH Default webroot path. (default: None)
Certificate data files:
-f PLUGIN Input/output plugin of choice, can be specified
multiple times and, in fact, it should be specified as
many times as it is necessary to cover all components:
key, certificate, chain. Allowed values:
account_key.json, cert.der, cert.pem, chain.der,
chain.pem, external_pem.sh, fullchain.der,
fullchain.pem, key.der, key.pem. (default: [])
--cert_key_size BITS Certificate key size. Fresh key is created for each
renewal. (default: 4096)
--valid_min SECONDS Minimum validity of the resulting certificate.
(default: 2592000)
--reuse_key Reuse private key if it was previously persisted.
(default: False)
Registration:
This client will automatically register an account with the ACME CA
specified by `--server`.
--account_key_public_exponent BITS
Account key public exponent value. (default: 65537)
--account_key_size BITS
Account key size in bits. (default: 4096)
--tos_sha256 HASH SHA-256 hash of the contents of Terms Of Service URI
contents. (default: 33d233c8ab558ba6c8ebc370a509acdded
8b80e5d587aa5d192193f35226540f)
--email EMAIL Email address. CA is likely to use it to remind about
expiring certificates, as well as for account
recovery. Therefore, it's highly recommended to set
this value. (default: None)
HTTP:
Configure properties of HTTP requests and responses.
--user_agent NAME User-Agent sent in all HTTP requests. Override with
--user_agent "" if you want to protect your privacy.
(default: simp_le/0)
--server URI Directory URI for the CA ACME API endpoint. (default:
https://acme-v01.api.letsencrypt.org/directory)
See https://github.com/kuba/simp_le for more info.
Obtaining a certificate
$ ./venv/bin/simp_le \
-f account_key.json -f key.pem -f cert.pem -f fullchain.pem \
--email admin@example.com \
-d www.example.com:/var/www/htdocs/
On success, this command produces 4 files: account_key.json, cert.pem, fullchain.pem and key.pem,
which can be used from your webserver’s SSL configuration (see here for an example integration in Apache).
Renewal works by using the same command.
Exit codes:
- 0 if certificate data was created or updated;
- 1 if renewal not necessary;
- 2 in case of errors.
letsencrypt-nosudo
This program is a predecessor of acme-tiny and functionally equivalent to gethttpsforfree.com (made by the same author). The script guides you through the whole process and ask you do run all the necessary commands in the terminal.
You generate a private key and certificate signing request (CSR), then run sign_csr.py to get the signed certificate. The script goes through the ACME protocol with the Let’s Encrypt certificate authority and outputs the signed certificate to stdout.
Installation
$ cd /opt
$ git clone https://github.com/diafygi/letsencrypt-nosudo
$ cd letsencrypt-nosudo
$ python sign_csr.py -h
⇾ show output
$ python sign_csr.py -h
usage: sign_csr.py [-h] -p PUBLIC_KEY [-e EMAIL] [-f] 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.
NOTE: YOUR ACCOUNT KEY NEEDS TO BE DIFFERENT FROM YOUR DOMAIN KEY.
Prerequisites:
* 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
Obtaining a certificate
$ 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
⇾ show output
user@hostname:~$ openssl genrsa 4096 > user.key
Generating RSA private key, 4096 bit long modulus
.............................................................................................................................................................................++
....................................................++
e is 65537 (0x10001)
user@hostname:~$ openssl rsa -in user.key -pubout > user.pub
writing RSA key
user@hostname:~$ openssl genrsa 4096 > domain.key
Generating RSA private key, 4096 bit long modulus
.................................................................................................................................................................................++
...........................................++
e is 65537 (0x10001)
user@hostname:~$ openssl req -new -sha256 -key domain.key -subj "/CN=www.example.com" > domain.csr
user@hostname:~$ python sign_csr.py --public-key user.pub domain.csr > signed.crt
Reading pubkey file...
Found public key!
Reading csr file...
Found domains www.example.com
STEP 1: What is your contact email? (webmaster@www.example.com)
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 daniel@roesler.cc...
Already registered. Skipping...
Requesting challenges for www.example.com...
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 www.example.com (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('dKsTWOsqGuOIBep_DYGpXOFqc_aLMu8HiXKMZ8xvsww.1Gt_C6ImtCNs62Zb5YArtvUOnWTp6MkprcNt88ZgUp8'); \
s = BaseHTTPServer.HTTPServer(('0.0.0.0', 80), h); \
s.serve_forever()"
Press Enter when you've got the python command running on your server...
Requesting verification for www.example.com...
Waiting for www.example.com challenge to pass...
Passed www.example.com challenge!
Requesting signature...
Certificate signed!
You can stop running the python command on your server (Ctrl+C works).
user@hostname:~$ cat signed.crt
-----BEGIN CERTIFICATE-----
MIIGJTCCBQ2gAwIBAgISATBRUGjFwTtjF4adpF7zd/5qMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTAeFw0xNTEwMjQwOTU4MDBaFw0x
NjAxMjIwOTU4MDBaMCoxKDAmBgNVBAMTH2xldHNlbmNyeXB0LmRheWxpZ2h0cGly
YXRlcy5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2Ac7twhMz
AxreQxmlY0gBq20zrriMOCLTwwdJ3sfv9bNxo+iG7eidu9imLI0FNjZkxtpyJeG/
+4OnvTgChHiTEKtD0Q3SoeSOu3Bl73d4bVBfTsvj0yEoMrF4Y89VvqbH7HP+2evv
Uraj2Qv0EUor3KAsOJW4hiSQedmz69+3IVZHWdpyYTtC1HjO9C5DqPgD7hlrtRrP
k0SL4j048NIiDvMm36pzn/UM+HxuavVxIyQ7BigDk7Hev6jXH2BqQk0ADtR0CycI
nJeS5gk+i6ImDeOsrhPrXvub02aRbol/paoSknskAOJKe4628dd873QfMXnQz1JT
aggaFQA1S8M2DY9l574/gOH39BudXdvOGzln7MeDJoi7Tybih2FJJbj8tQPV2zwh
ArbKLHPJibM1HP8jc7QQcrWnNf3H2N5FhP8uvEVchdYk3zV2tJPqlQnsHctOjNrV
18WRsl+JpUNLclRWQ3JLYZL+waIaJvsAsjp58J3XK1PI1s7QPuJpI3u7hlu4zz2e
TMF8OqAEy+rkHML5j+ncB+ctxhgNgirwpCUQ3NL9rslte0OmO+kzjrVfJ7o5D6zt
Hn5xg2WTgNoCdXbIruEzC43SqkPIH8VeFkzjPCqGajQsXXmdbDyoNkJ+SK0Fz0hI
3alW4kaOSe0aeto22sKtOjsIy7GF6qDw4QIDAQABo4ICIzCCAh8wDgYDVR0PAQH/
BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8E
AjAAMB0GA1UdDgQWBBSpGhk6yOALnLPWzrncMA/wnd6nNzAfBgNVHSMEGDAWgBSo
SmpjBH3duubRObemRWXv86jsoTBwBggrBgEFBQcBAQRkMGIwLwYIKwYBBQUHMAGG
I2h0dHA6Ly9vY3NwLmludC14MS5sZXRzZW5jcnlwdC5vcmcvMC8GCCsGAQUFBzAC
hiNodHRwOi8vY2VydC5pbnQteDEubGV0c2VuY3J5cHQub3JnLzAqBgNVHREEIzAh
gh9sZXRzZW5jcnlwdC5kYXlsaWdodHBpcmF0ZXMub3JnMIIBAAYDVR0gBIH4MIH1
MAoGBmeBDAECATAAMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0
cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBD
ZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBh
cnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0
ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3Np
dG9yeS8wDQYJKoZIhvcNAQELBQADggEBADQ2nWJa0jSOgStC7luKLmNOiNZTbiYP
ITFetj6WpRIsAHwz3vTwDIWFtczrhksWRTU9mCIwaxtqflZrirc3mE6jKugeSUHr
1yqTXZ097rDNAnMvUtvoET/UBkAU+gUDn8zRFtKOePuWX7P8qHq8QqjNqMC0vb5s
ncyFqSSZl1j9e5l+Kpj/GeTCwkwck5U75Ry44kPbnu5JLd70P724gBnyEi6IxXHB
txXZEUmI0R1Ee3Kw/5N6JfeWNE1KEmM47VVFomRitruxBj9nlXtIILvkPCTWkDua
pr1OmFi/rUcaHw+Txbs8aBmZEBkxy9HPSfgqqlYqEd0ipGqFtqaFJEI=
-----END CERTIFICATE-----
user@hostname:~$
- github.com/hlandau/acme

- 103 commits, 1 contributors
- Mode: Automatic / Interactive
- License: MIT
- Language: Go
- Lines of code: ~6,000
- Dependencies: None (Binary Release)
acmetool is an ACME client written in Go, supporting automatic domain verification with webroot and standalone methods as well as an interactive wizard. acmetool stores credentials and certificates at /var/lib/acme/live/HOSTNAME/{cert,chain,fullchain,privkey} by default and includes support to import certificates from the official client.
acmetool furthermore provides a reconcile option which makes sure all desired hostnames
have valid certificates which don’t expire soon.
Installation
You can either get a binary release, or build from source as described in the Readme:
$ wget https://github.com/hlandau/acme/releases/download/v0.0.22/acmetool-v0.0.22-linux_amd64.tar.gz
$ tar -xvf acmetool-v0.0.22-linux_amd64.tar.gz
$ cd acmetool-v0.0.22-linux_amd64
$ bin/acmetool --help
⇾ show output
Obtaining a certificate
You need to set the webroot to /var/run/acme/acme-challenge as described
in the docs, or use the proxy method. The command acmetool want tries all available methods.
$ sudo acmetool want www.example.com
lego
- github.com/xenolf/lego

- 162 commits, 4 contributors
- Mode: Automatic
- License: MIT
- Language: Go
- Lines of code: ~2,000
- Dependencies: None (Binary Release)
- Show HN
Lego is an ACME library and standalone application written in Go. It can be downloaded as
a binary release or build by yourself.
Running the standalone version requires the permission to bind to port 80 and 443,
which conflicts with a webserver which is already running.
Installation
$ wget https://github.com/xenolf/lego/releases/download/v0.1.0/lego_linux_amd64.tar.gz
$ tar -xvf lego_linux_amd64.tar.gz
lego
LICENSES.txt
README.txt
$ ./lego help
⇾ show output
# ./lego help
NAME:
lego - Let's encrypt client to go!
USAGE:
./lego [global options] command [command options] [arguments...]
VERSION:
0.1.0
COMMANDS:
run Register an account, then create and install a certificate
revoke Revoke a certificate
renew Renew a certificate
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--domains, -d [--domains option --domains option] Add domains to the process
--server, -s "https://acme-v01.api.letsencrypt.org/directory" CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client.
--email, -m Email used for registration and recovery contact.
--rsa-key-size, -B "2048" Size of the RSA key.
--path "/opt/le5-lego/dl/.lego" Directory to use for storing the data
--port Challenges will use this port to listen on. Please make sure to forward port 443 to this port on your machine. Otherwise use setcap on the binary
--help, -h show help
--version, -v print the version
Obtaining a certificate
$ sudo ./lego --email="admin@example.com" --domains="www.example.com" run
⇾ show output
$ sudo ./lego --email="admin@example.com" --domains="www.example.com" run
2015/12/13 17:32:25 No key found for account admin@example.com. Generating a 2048 bit key.
2015/12/13 17:32:26 Saved key to /opt/le5-lego/dl/.lego/accounts/acme-v01.api.letsencrypt.org/admin@example.com/keys/admin@example.com.key
2015/12/13 17:32:26 [INFO] acme: Registering account for admin@example.com
2015/12/13 17:32:27 !!!! HEADS UP !!!!
2015/12/13 17:32:27
Your account credentials have been saved in your Let's Encrypt
configuration directory at "/opt/le5-lego/dl/.lego/accounts/acme-v01.api.letsencrypt.org/admin@example.com".
You should make a secure backup of this folder now. This
configuration directory will also contain certificates and
private keys obtained from Let's Encrypt so making regular
backups of this folder is ideal.
2015/12/13 17:32:27 Please review the TOS at https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf
2015/12/13 17:32:27 Do you accept the TOS? Y/n
Y
2015/12/13 17:32:30 [INFO] acme: Obtaining bundled SAN certificate for www.example.com
2015/12/13 17:33:02 [INFO] acme: Trying to solve TLS-SNI-01
2015/12/13 17:33:04 The server validated our request
2015/12/13 17:33:04 [INFO] acme: Validations succeeded; requesting certificates
2015/12/13 17:33:05 [INFO] acme: Requesting issuer cert from https://acme-v01.api.letsencrypt.org/acme/issuer-cert
2015/12/13 17:33:05 [www.example.com] Server responded with a certificate.
letsencrypt.sh
Installation
$ git clone https://github.com/lukas2511/letsencrypt.sh
$ ./letsencrypt.sh --help
⇾ show output
$ ./letsencrypt.sh --help
Usage: ./letsencrypt.sh [-h] [command [argument]] [parameter [argument]] [parameter [argument]] ...
Default command: cron
Commands:
--cron (-c) Sign/renew non-existant/changed(TODO)/expiring certificates.
--sign (-s) domain.tld Force-sign specific certificate from domains.txt, even if not yet expiring or changed.
--revoke (-r) path/to/cert.pem Revoke specified certificate
--help (-h) Show help text
Parameters:
--config (-f) path/to/config.sh Use specified config file
--privkey (-p) path/to/key.pem Use specified private key instead of account key (useful for revocation)
Obtaining a certificate
Create a file called domains.txt which contains the domains and subdomains you want to
generate certificates for:
example.com www.example.com
example.net www.example.net wiki.example.net
This requests two certificates, for example.com and example.net. The other domains in the corresponding line are their alternative names.
letsencrypt.sh writes the challenge files by default into the directory "${SCRIPTDIR}/.acme-challenges". To adjust this to your webroot, you need to create a config file (config.sh) with another $WELLKNOWN path (see config.sh.example):
WELLKNOWN="${SCRIPTDIR}/.well-known/acme-challenge"
Then simply run letsencrypt.sh (⇾ show output).
$ ./letsencrypt.sh
Using config file /opt//letsencrypt.sh/config.sh
Processing www.example.com
+ Signing domains...
+ Generating private key...
+ Generating signing request...
+ Requesting challenge for www.example.com...
+ Responding to challenge for www.example.com...
+ Challenge is valid!
+ Requesting certificate...
+ Checking certificate...
+ Creating fullchain.pem...
+ Done!
$ ./letsencrypt.sh
Using config file /opt//letsencrypt.sh/config.sh
+ Found existing cert...
+ Valid till Mar 12 22:42:00 2016 GMT (Longer than 14 days). Skipping!
acme-client
acme-client is an ACME client written in PHP, built on top of the acme PHP library by the same author.
It requires PHP 7 and composer to install it’s dependencies.
Installation
$ git clone https://github.com/kelunik/acme-client
$ cd acme-client
$ composer install
Obtaining a certificate
# Register the Let's Encrypt account
$ sudo bin/acme register \
--server acme-v01.api.letsencrypt.org/directory \
--email me@example.com
# Issue the certificate
$ sudo bin/acme issue \
--server acme-v01.api.letsencrypt.org/directory \
--domains example.com,www.example.com \
--path /var/www/example.com/htdocs
lescript
- github.com/analogic/lescript

- 3 commits, 1 contributors
- Mode: Automatic
- License: BSD
- Language: PHP
- Lines of code: ~450
- Dependencies: PHP 5.4.8+ with OpenSSL and curl extension
- Show HN
lescript is a very simplistic PHP ACME client library, with an example CLI wrapper.
Installation
$ git clone https://github.com/analogic/lescript.git
$ cd lescript
Obtaining a certificate
Use the library as shown in _example.php.
Summary
| Client |
User Mode |
Deps. |
Language |
LOC |
License |
Capabilities |
Domain Authentication |
| Official Let's Encrypt Client (Docs) |
Automatic / Interactive / Manual |
Many |
Python |
~8.600 |
Apache 2.0 |
Issue, Renew, Revoke, Server Config |
Webroot, Standalone, Manual |
| acme-tiny |
Automatic / Semi-Automatic |
None |
Python |
~200 |
MIT |
Issue, Renew |
Webroot |
gethttpsforfree .com (Source) |
Semi-Manual |
None |
HTML/JS |
~1200 |
MIT |
Issue, Renew |
Webroot |
| simp_le |
Automatic / Semi-Automatic |
Some |
Python |
~800 |
GPLv3 |
Issue, Renew, Revoke |
Webroot |
| letsencrypt-nosudo |
Manual (assisted) |
None |
Python |
~400 |
AGPL |
Issue, Renew, Revoke |
Standalone |
| acmetool |
Automatic / Interactive |
None |
Go |
~6,000 |
MIT |
Issue, Renew |
Webroot, Standalone |
| lego |
Automatic |
None |
Go |
~2,000 |
MIT |
Issue, Renew, Revoke |
Standalone |
| letsencrypt.sh |
Automatic |
None |
Bash |
~600 |
? |
Issue, Renew, Revoke |
Webroot |
| acme-client |
Semi-Automatic |
Some (incl. PHP 7) |
PHP |
~400 |
MIT |
Issue, Renew, Revoke |
Webroot |
| lescript |
Semi-Automatic |
None |
PHP |
~450 |
BSD |
Issue, Renew |
Webroot |
If you have suggestions or feedback, please let me know via @metachris.