Note (2026): This post is kept as a December 2015 snapshot. The
letsencryptutility became Certbot, and itsletsencrypt-auto/certbot-autowrapper is no longer supported. The TLS-SNI-01 challenge used below was permanently disabled on March 13, 2019 because it was not secure enough; use HTTP-01 or DNS-01 instead. Renewal is now handled bycertbot renewon a cron job or systemd timer (the snap package ships one preconfigured), or by an ACME-aware reverse proxy such as Caddy or Traefik. Default lifetimes are shrinking too: 64 days from February 10, 2027 and 45 days from February 16, 2028, so anything hard-coded around 90 days needs revisiting.
Why?
A secure connection has many advantages over good old HTTP: protection against traffic interception, protection against content substitution, better search ranking, and so on. I, for one, like the green icon in the address bar. In the past you had to pay for all that pleasure, so certificates were mostly seen only on large projects or payment systems, where the risk of data compromise is high and without a certificate people simply would not understand you. The letsencrypt.org project is meant to change this state of affairs once and for all.
Getting a free but fully functional certificate is now available to everyone. The project provides a command-line utility that can generate a key and a certificate and, in typical cases, even install that certificate into your web server configuration. The only serious difference from the usual paid certificates was, at the time of writing, a three-month lifetime (the default is dropping to 64 days in 2027 and 45 days in 2028, see the note above). But this is not a minus; it is an intentional approach. The idea is that the server will be configured to automatically obtain a new certificate in place of the previous one, which should help fight key compromise.
Setup
The supplied command-line utility is said to be able to analyze and update Apache and nginx configs on its own, generating a new certificate and adding all the necessary settings for it. Obviously, this makes it possible to update typical configs with little blood spilled, but I think this approach is far from always justified. First, your config may be much more complex than a typical one, and there is no guarantee that automatic mode will cope with it. Second, it is good to have a full understanding of what is happening on your server and why, so that you can fix shortcomings or repeat the steps to get the result. Third, in my case nginx was wrapped inside a Docker container, and the utility definitely was not prepared for that. So we will act the old-fashioned way.
First, download the utility (the repository has since moved to certbot/certbot; the old URL redirects there):
cd /opt
mkdir letsencrypt && cd letsencrypt
git clone https://github.com/letsencrypt/letsencrypt .Now write a script that generates the certificate. Here /var/www/astgo is the directory with the application sources. Important: before creating the certificate, you need to free the ports, if they are occupied, so the utility can use them to confirm that you own the specified domain. In the example below, Docker containers are stopped for this, and after the certificate is renewed they need to be brought back up.
# /opt/update-cert.sh
(cd /var/www/astgo && docker-compose stop && docker-compose rm --force) &&
(cd /opt/ && ./letsencrypt/letsencrypt-auto certonly -d ast.rocks --email astartsky@gmail.com --standalone --renew-by-default --agree-tos --standalone-supported-challenges tls-sni-01) &&
cp /etc/letsencrypt/live/ast.rocks/cert.pem /var/www/astgo/build/nginx &&
cp /etc/letsencrypt/live/ast.rocks/chain.pem /var/www/astgo/build/nginx &&
cp /etc/letsencrypt/live/ast.rocks/fullchain.pem /var/www/astgo/build/nginx &&
cp /etc/letsencrypt/live/ast.rocks/privkey.pem /var/www/astgo/build/nginx &&
(cd /var/www/astgo/ && docker-compose build --no-cache && docker-compose up -d)Let us look at the utility call in more detail:
- certonly – only generate the certificate; no automatic installation actions are required;
- -d – the domain for which the certificate will be generated;
- –email – the email address where Let’s Encrypt can contact you;
- –standalone – a separate web server will be started to confirm domain ownership;
- –renew-by-default – an alias of
--force-renewal: if a certificate for these domains already exists, renew it right away regardless of expiry, so the script can be re-run on a schedule; - –agree-tos – of course, on the first run you need to agree to the terms of service;
- –standalone-supported-challenges tls-sni-01 – allow port 443 to be used for domain validation (this challenge no longer exists, see the note above);
After running the script, the coveted certificates will appear in the folders listed above. The only thing left is to point nginx configs at them. For example, like this:
ssl_stapling_verify on;
ssl_stapling on;
ssl_trusted_certificate /opt/chain.pem;
ssl_certificate_key /opt/privkey.pem;
ssl_certificate /opt/fullchain.pem;
listen 443 ssl;Back then it also made sense to put a call to this script into cron every two months, so certificate renewal was fully automatic. With today’s shorter lifetimes, let certbot renew decide when a certificate is due instead of hard-coding an interval.






