3

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?

Notes

  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.

Noam M
  • 441
  • 1
  • 7
  • 17
  • Have you seen posts like https://community.letsencrypt.org/t/how-to-completely-automating-certificate-renewals-on-debian/5615 and http://www.linuxjournal.com/content/lets-automate-lets-encrypt ? – muru Aug 07 '17 at 02: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... –  Aug 07 '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... –  Aug 07 '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. –  Aug 07 '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 08 '17 at 00:03
  • Thanks! Please elaborate what is CA (to short for wiki article I guess). Even if I self sign, I assume this would be part of the automation. –  Aug 08 '17 at 00:06
  • This might be a solution for me. Please don't hesitate to publish an answer with this solution. –  Aug 08 '17 at 00:14
  • CA = Certificate Authority (Thawte, VeriSign, Comodo, LetsEncrypt, CACert, etc.). To use HTTPS for encryption between the client and web server, companies will use certificates signed by one of the well known trusted CAs. The public root or intermediate certificates of various trusted signers are bundled with most operating systems and popular browsers. Without describing PKI in more detail, you really don't need this unless you are dealing with the public (or perhaps internal security requirements). – Deathgrip Aug 08 '17 at 02:22
  • I'm not sure I understand "dealing with the public"? My websites are public, anyone can visit them. You meant something else? –  Aug 08 '17 at 02:37
  • Your words, "I just want to use HTTP2 on my **private**, minimal, Nginx environment". – Deathgrip Aug 08 '17 at 02:49
  • I meant to say it's private in the sense I manage it (I store at DigitalOcean). I'll clarify. –  Aug 08 '17 at 03:19
  • To all commenters, please see this question: https://unix.stackexchange.com/questions/395382/combining-certbot-with-an-nginx-server-block-maker –  Oct 05 '17 at 16:23

4 Answers4

3

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                                          
WELLKNOWN="/st/hosting/hamilton/htdocs/.well-known/acme-challenge"
CONTACT_EMAIL=<you@email>

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:

#!/bin/sh

CERTS_DIR=/usr/local/etc/dehydrated/certs
NGINX_SSL=/usr/local/etc/nginx/ssl
DOMAINS=$(awk '{ print $1 }' /usr/local/etc/dehydrated/domains.txt)

for d in $DOMAINS; do
  short_d=${d%%.rinet.ru}
  short_d=${short_d%%.ru}
  # 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
done

# 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
Fedor Dikarev
  • 1,761
  • 8
  • 13
  • 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. –  Aug 09 '17 at 03: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 09 '17 at 05:52
  • But what do you mean adding it to each site? Where? In the site-block? –  Aug 09 '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 09 '17 at 13:32
  • Besides basic Bash scripting (and `awk`), what do you think someone dealing with this for the first time should learn?... What practices should I take? Please elaborate on this, which I find extremely important. Please feel free to edit the answer with this information. –  Aug 09 '17 at 13:46
  • 1
    Based on my experience with Lets Encrypt and Dehydrated you only need a 30-60 minutes of spare time and read carefully article https://www.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 09 '17 at 19:12
  • @Benia so have you tried creating and updating certificates with `dehydrated`? Does it work for you? – Fedor Dikarev Aug 14 '17 at 04:01
  • No I haven't tried. I am new to Linux and yet to have acquired enough knowledge in `awk` or `regex` and just learning SSL. I would desire for a Bash-only solution anyway. I already have a Bash-only solution which works for self-signed certificates but a similar solution for LE seems as something I should have some intros for. –  Aug 14 '17 at 04:11
  • You don't need any of `regex` knowledges to use it. Simply get this script using `sudo wget -O /usr/bin/dehydrated https://raw.githubusercontent.com/lukas2511/dehydrated/master/dehydrated && chmod a+x /usr/bin/dehydrated`, create folder for it: `sudo mkdir /etc/dehydrated`, put your e-mail and folder to store certs in `/etc/dehydrated/config` file, list your domains in `/etc/dehydrated/domains.txt`, add `.well-known` location to nginx configuration and run `dehydrated`. Thats all. In my example I use `awk` just to get first domain in row, I guess you don't need it in your case. – Fedor Dikarev Aug 14 '17 at 04:52
  • Or you could use `Certbot` if you have mostly by-default settings for nginx. Good tutorials for `certbot` are: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04 and https://certbot.eff.org/#ubuntuxenial-nginx – Fedor Dikarev Aug 14 '17 at 04:55
  • Given I want a Bash only solution I think your script is good for me even for the start and I want to understand it and not just run it. –  Aug 14 '17 at 05:12
  • Good idea: not just run but understand :-) Don't forget to add `ssl_certificate` and `ssl_certificate_key` on your nginx configuration so Nginx will load certificates after you create them. And mark my solution as "accepted" (Click the checkmark under this post, on the left, it's right below the arrows) if my submission help you with certificates creation and bash learning. – Fedor Dikarev Aug 14 '17 at 05:45
  • For my self-signed certs I've added these two rows to each site-conf. These are added each time the script crerates a new site conf, with the cert. Can this be done in this script? –  Aug 14 '17 at 06:14
  • You should have an option for your script that creates new site conf: at first you should create http-only site as you don't have cert for it yet. After that you should add this domain to `domains.txt` file and run `dehydrated` to create cert and use my script to copy cert to nginx folder. And after that you should create conf for your site with ssl. (And don't forget `.well-known` location as it's also used for updating certificates). And latter you could combine all that steps in one single script. – Fedor Dikarev Aug 14 '17 at 06:42
  • Hello, Fedor, please take a look here: https://unix.stackexchange.com/questions/395382/combining-certbot-with-an-nginx-server-block-maker –  Oct 05 '17 at 16:23
2

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.

Deathgrip
  • 2,496
  • 1
  • 9
  • 16
  • `NNNNN` is a serial number. It *should* be different for each certificate. But for what you're doing, not critical. – Deathgrip Aug 08 '17 at 03: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 08 '17 at 04:00
  • I suggest editing and removing the serial altogether (I humbly think it's problematic for one with say 20 sites). –  Aug 13 '17 at 20:20
1

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.

quadruplebucky
  • 466
  • 3
  • 5
0

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.

MarkoShiva
  • 192
  • 9
  • 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. –  Aug 14 '17 at 08:39
  • @Benia - [Nginx on Ubuntu 16.04](https://certbot.eff.org/#ubuntuxenial-nginx) is a good starting point. As well as going through the [Certbot Documentation](https://certbot.eff.org/docs/). – 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. –  Aug 14 '17 at 17:59