I have an Ubuntu-server 16.04 VPS and Nginx. Now I'm implementing HTTP1 (without TLS, utilizing port 80) but I desire to go "one step forward" and work with HTTP2 (with TLS, utilizing port 443), for all my (Wordpress) websites.

Assuming I adjusted my environment, this way:

1. Firewall

ufw app list # Choose Nginx HTTPS

2. Server blocks

Default server block

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name server_domain_or_IP;
    return 302 https://$server_name$request_uri;

server {

    # SSL configuration

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

Each site server block

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    root /var/www/html/example.com;
    index index.php index.html index.htm index.nginx-debian.html;
    example.com www.example.com;

    location / {
        try_files $uri $uri/ =404;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;

    location ~ /\.ht {
        deny all;

Now I need to create OpenSSL certificates, sign them with Let'sEncrypt, and associate them with each site dir, respectively.

My question:

How can the creation of OSSL certs, LE signage, and SDIR associating, be done as much automatic as possible from inside the terminal? Of course there is some part in which I need to verify a domain from my email, but beyond that, AFAIU, everything is done from the terminal, thus can be fully automated.

Can you share a Bash script code example (or a utilization of a particular utility, maybe GNU make), that helps achieving that?


  1. I would humbly prefer a dockerless solution (I read here and bedsides the fact it has to do with renewling, it also seems to implement docker which I have no intention to do for a small private server of less than 10 small sites, by means of minimalism).

  2. I understand that creating, signing, and site dir associating, requires a different algorithm than renewaling. I am asking only on creating, signing and associating.

Why I even ask this question:

Well, I just want to use HTTP2 on my self-managed, minimal VPS (no kernel/shell customization, no compilations, almost no contrib utilities), and it seems insane to me to manually implement this algorithm for many sites, or each time a new site is added.

  • Have you seen posts like community.letsencrypt.org/t/… and linuxjournal.com/content/lets-automate-lets-encrypt ? – muru Aug 7 '17 at 2:17
  • No, in a former quick google search I didn't find these. Until about yesterday, I didn't even know the concept of renewing exists... – JohnDoea Aug 7 '17 at 12:58
  • Anyway, @muru If these deal with renewing, I need something even more basic, something to create the certificates as much as I could from terminal... – JohnDoea Aug 7 '17 at 13:05
  • I read their preview and that's what I've understood, they deal with renewal, not with first-time creation of the certs. I don't understand their code enough though from what I do understand they seem to help with creation also. – JohnDoea Aug 7 '17 at 13:20
  • If it's your own private server, why not just use self-signed certificates created with OpenSSL? No need to have them signed by a CA unless they will be accessed from outside your environment. – Deathgrip Aug 8 '17 at 0:03

It's easy to create and update Let's Encrypt cerificates with dehydrated (https://github.com/lukas2511/dehydrated).

You have to add /.well-known/acme-challenge/ location for each site as Let's Encrypt service will look on challenge responses under this location to verify that you are the owner of sites you have requested certificates for:

location /.well-known/acme-challenge/ { allow all; root /st/hosting/hamilton/htdocs; } 

And use same path in dehydrated config:

egrep -v "^#|^[[:space:]]*$" config                                          

After that put all your domains in domain.txt file: on each line first domain will be CommonName and other names will be AlternativeNames, for example:

head -n1 domains.txt
hamilton.rinet.ru jenkins.hamilton.rinet.ru munin.hamilton.rinet.ru

After that you should put dehydrated -c in cron and use script like this one to install new generated certificates:


DOMAINS=$(awk '{ print $1 }' /usr/local/etc/dehydrated/domains.txt)

for d in $DOMAINS; do
  # short_d=${short_d##www.}
  cp -v ${CERTS_DIR}/$d/fullchain.pem ${NGINX_SSL}/${short_d}.crt
  cp -v ${CERTS_DIR}/$d/privkey.pem ${NGINX_SSL}/${short_d}.key

# Also update certs for Dovecot
cp -v ${CERTS_DIR}/hamilton.rinet.ru/fullchain.pem /usr/local/etc/dovecot/certs/certs/server.crt
cp -v ${CERTS_DIR}/hamilton.rinet.ru/privkey.pem /usr/local/etc/dovecot/certs/private/server.key
  • Thanks. Can you please edit and explain what is /.well-known/acme-challenge/ and why you use that? This is in the very start and needs most elaboration for smooth read of the answer. – JohnDoea Aug 9 '17 at 3:41
  • You have to add /.well-known/acme-challenge/ location for each site as Let's Encrypt service will look on challenge responses under this location to verify that you are the owner of sites you have requested certificates for. – Fedor Dikarev Aug 9 '17 at 5:52
  • But what do you mean adding it to each site? Where? In the site-block? – JohnDoea Aug 9 '17 at 13:01
  • You should have plain-http (no ssl, listen Port 80) in every site-block with this location. So Let's Encrypt ask you to prove that you are the owner of server and one option is to put file with given "random" name under this well-known location. And LE robot try to access it, you could see such requests in NGINX log. Another option is to use dns-challenges but I suppose http-challenge is easier to configure. – Fedor Dikarev Aug 9 '17 at 13:32
  • 1
    Based on my experience with Lets Encrypt and Dehydrated you only need a 30-60 minutes of spare time and read carefully article aaflalo.me/2016/09/dehydrated-bash-client-lets-encrypt and repeat it exaclty as described step by step. As there is no any fees for certificates you are free to make severall attempts and read log and script output to find out the reason of problems if any. And good knowledge of openssl program and especially openssl x509 section will help you to verify that you got result you expected. – Fedor Dikarev Aug 9 '17 at 19:12

First off, I would check out some of the LetsEncrypt clients. Particularly, the ones listed for Nginx. I'd start there before reinventing the wheel since you originally wanted to use LE signed certificates.

If instead, you want to use OpenSSL to create self-signed certificates, you can loop through your list of domain names and execute openssl for each domain with a command similar to:

openssl req -x509 -newkey rsa:2048 -keyout examplekey.pem -out examplecert.pem -nodes -days 365 -set_serial NNNNN -subj "/C=US/L=Any City/OU=FooBar Inc/CN=*.example.com"

Of course for each domain you want to change examplekey.pem, examplecert.pem, and *.example.com. Replace NNNNN with a serial number, increment for each iteration of the loop.

You should be able to easily write a script that loops through the desired domain names and updates the various Nginx configuration files.

  • NNNNN is a serial number. It should be different for each certificate. But for what you're doing, not critical. – Deathgrip Aug 8 '17 at 3:37
  • I'd have the same script do everything, create the cert and key, move them into the proper directories, modify the server block in nginx.conf. – Deathgrip Aug 8 '17 at 4:00
  • I suggest editing and removing the serial altogether (I humbly think it's problematic for one with say 20 sites). – JohnDoea Aug 13 '17 at 20:20

I'll add acmetool to the ring of let's encrypt clients here, it's dead simple once you get feed it the paths. acmetool want www.site1.org acmetool want www.site2.net etc. You do have to point the acme request to the right place with a location {} block in nginx... it handles the updates via cron if you like.


Use certbot --nginx -d your.domain.name should do the trick and certbot should automatically update your nginx config

Ok so after you have your Virtualhosts setup you can run for every of the domains where you will use ssl command certbot --nginx -d your.domain.name which will ask you few questions and generate the proper config file. Or you could just run certbot --nginx if you already have hostnames on nginx. It will include automatically configuration files for nginx the old will be saved as .old.

You can check this tutorial too: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04 Dont forget to add crontab with certbot --renew.

  • I suggest improving the answer by giving explanation on how to actually do it with certbot (the main stages of the process) and what to change in the Nginx conf. I think it could server more users and give more thumbs up. – JohnDoea Aug 14 '17 at 8:39
  • @Benia - Nginx on Ubuntu 16.04 is a good starting point. As well as going through the Certbot Documentation. – Deathgrip Aug 14 '17 at 17:39
  • This is true as is, but as this is a QA session, the answer should be given to the body of the question - how is it done with a personal explanation of the answerer - in its own words. – JohnDoea Aug 14 '17 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.