Let's encrypt - how to

See rather community documentation where I moved this procedure including changes needed for Turris 3.9+
Turris Documentation

Hi everyone.

For some time I was looking for some reliable way how to setup HTTPS certificate for Let’s Encrypt. Here is already available one thread for this but it is not perfect and not suitable for my needs. So I prepared myself set of scripts to cover the problematic. If you are intersted see below.

The condition I needed to cover:

  • full automation
  • currently nothing is listening on HTTPS port (I have different port for Foris / Luci)

If your setup is different you need to modify my solution accordingly.

I decided to use the acme.sh script which is quite simple and have no prerequisites.
https://github.com/Neilpang/acme.sh


Installation:
Very simple if you don’t want any customization and everything can remain under /root

wget -O - https://get.acme.sh | sh

Or check more options: https://github.com/Neilpang/acme.sh/wiki/How-to-install


New certificate:
Few notes

  • I do not have anythign listening and allowed on HTTPS port 443
  • acme.sh has its own “server” for port 443 during domain verification
    → firewall must be updated to pass packets to port 443 temporarily
    → lighttps must be restarted for new certificates (and to not block acme.sh if you are using default HTTPS)

All things are going to happen in /root/.acme.sh (default setup)

Create file add443.gw

 config redirect
         option target 'DNAT'
         option src 'wan'
         option dest 'lan'
         option proto 'tcp'
         option src_dport '443'
         option dest_ip '<TURRIS_IP>'  
         option dest_port '443'
         option name 'Turris  Lets encrypt'

Create file get_acme.sh

 #!/bin/bash
 VER=1.0.0

 # Backup firewall config
 # Update firewall rules to allow access via port 443 from internet
 cp /etc/config/firewall  /etc/config/firewall~
 cat add443.gw >> /etc/config/firewall
 /etc/init.d/firewall reload

> # Stop lighttpd as acme.sh is starting its own daemon
> /etc/init.d/lighttpd stop

> # Trigger request to Let's Encrypt (and ensure to have the directory)
> mkdir -p /etc/lighttpd/certs
> ./acme.sh --issue --tls -d <DOMAIN> --certhome /etc/lighttpd/certs --ca-path /etc/ssl/certs

> # Prepare the certificates for lighttpd
> ./acme.sh --install-cert -d <DOMAIN> --certhome /etc/lighttpd/certs  --cert-file /etc/lighttpd/host.crt --key-file /etc/lighttpd/host.key --fullchain-file /etc/lighttpd/fullchain.crt --reloadcmd  "cat /etc/lighttpd/host.crt /etc/lighttpd/host.key > /etc/lighttpd/hostkey.pem"

> # Start lighttpd again
> /etc/init.d/lighttpd start

> # Restore firewall to original state
> mv /etc/config/firewall~ /etc/config/firewall
> /etc/init.d/firewall reload

We are ready to trigger the certificate request:

chmod o+x get_acme.sh /root/.acme.sh/get_acme.sh

Now the certificates are acquired and prepared for lighttpd. Update the configuration file as follows:
/etc/lighttpd/conf.d/ssl-enable.conf

# This settings enables https with Let's Ecnrypt certificate

$SERVER["socket"] == ":443" {
        ssl.engine = "enable"
        ssl.pemfile = "/etc/lighttpd/hostkey.pem"
        ssl.ca-file = "/etc/lighttpd/fullchain.crt"
}

$SERVER["socket"] == "[::]:443" {
        ssl.engine  = "enable"
        ssl.pemfile = "/etc/lighttpd/hostkey.pem"
        ssl.ca-file = "/etc/lighttpd/fullchain.crt"
}

Then restart the lighttpd once more. This is not automated by purpose.


Certificate renewal:

Situation is very similar to new certificate. So the add443.gw will be reused.

Create file renew_acme.sh

#!/bin/bash
VER=1.0.0

# Backup firewall config
# Update firewall rules to allow access via port 443 from internet
cp /etc/config/firewall  /etc/config/firewall~
cat add443.gw >> /etc/config/firewall
/etc/init.d/firewall reload

# Stop lighttpd as acme.sh is starting its own daemon
/etc/init.d/lighttpd stop

# Trigger renewal request to Let's Encrypt
./acme.sh --cron --certhome /etc/lighttpd/certs --ca-path /etc/ssl/certs

# Prepare the certificates for lighttpd
./acme.sh --install-cert -d <DOMAIN> --certhome /etc/lighttpd/certs  --cert-file /etc/lighttpd/host.crt --key-file /etc/lighttpd/host.key --        fullchain-file /etc/lighttpd/fullchain.crt --reloadcmd  "cat /etc/lighttpd/host.crt /etc/lighttpd/host.key > /etc/lighttpd/hostkey.pem"

# Start lighttpd again
/etc/init.d/lighttpd start

# Restore firewall to original state
mv /etc/config/firewall~ /etc/config/firewall
/etc/init.d/firewall reload

Now just make it executable:

chmod o+x renew_acme.sh

As last step add this into cron with your own frequency. Let’s Ecnrypt suggests daily but once a week should be enough.

/root/.acme.sh/renew_acme.sh

8 Likes

First let me thank you for your work - ill try it tomorrow I think.

Some questions:

  • this kind of setup (acme-script) can only utilise port 80 or 443, right?
  • as I am using port 443 for other servers I would need to automate lighttpd-conf, too. You wrote you refrain to do this on purpose - why?

Hi,
please can you integrate it into our community documentation?:slight_smile:

2 Likes

Hi,

Let’s Encrypt in general does not support non-standard ports. From definition. So you must be able to reach port 443 at the domain name which is in certificate’s common name.

So the acme script contains its own daemon listening at port 443. That’s one of the reasons for stopping lighttpd to have the port 443 available (not in my setup but in general).

On purpose - I meant to not modify the lighttpd config by script but manually. As it is one time only task I prefer to have full control over it. Renewal of the certificates is automatic every two months, don’t worry.

If you have additonal devices on port 443 behind your Turris then you need to make a bit different steps. I will provide a guide later cause I have this done also. I am letting my Synology NAS connected behind the Turris to acquire Let’s Encrypt certificate.
If you mean that another service running directly on Turris is using port 443 you will have to modify the scripts to stop / start such service before and after the certificates operation.

2 Likes

Ok, so I don’t need that lighttpd-actions for my setup, thanks for clarifying.
The steps taken for a Synology Diskstation would be really nice to know because I also run one (DS213+) behind an openwrt-router (WRT1900AC) with Synology webservices available on port 443. Having to have port 80 open all the time is not really nice in my eyes :unamused: And this way I cannot use it for other actions…

Another question: what do you think would be more work to implement for the following scenario:
I own a wildcard-domain with lets say defined router.mydomain.tl, wiki.mydomain.dl and mydomain.tl. Behind the Turris NAT I will run a dedicated server with several virtual servers accessible by wiki.mydomain.dl and mydomain.tl and both shall be accessible on port 443 (and some other ports). Turris shall be accessible by router.mydomain.tl on port 80 (for OpenVPN).
Would it be better to run the certificate-requests/renewals all on the Turris and having a (maybe a bit complex) copying routine or to open the necessary ports when needed (chronological harmonised cron-actions

  • on dedicated server running another acme
  • and cron on Turris opening/closing ports for it)?

And as an additional question for the case it would be better to run all certificate-requests/renewals on the Turris:
If I now choose to only run the acme-request for the router.mydomain.tl on the Turris, will I be later on able to change it towards requesting the certificates for wiki.mydomain.tl and mydomain.tl together with router.mydomain.tl?

Finally I tested it. Due to my different needs (see above) I adjusted the */get_acme.sh, but syntax stayed the same.
firewall request-version contains the port-rule you wrote in your start-post (instead of the the port forward to my dedicated server contained by firewall normal-version)

#!/bin/bash
 VER=1.0.0

 # Activate firewall request-version config
 cp '/etc/config/firewall[certificate.operations]'  /etc/config/firewall
 /etc/init.d/firewall reload

> # Stop lighttpd as acme.sh is starting its own daemon
> /etc/init.d/lighttpd stop

> # Trigger request to Let's Encrypt (and ensure to have the directory)
> ./acme.sh --issue --tls -d <DOMAIN> --certhome /etc/ssl/private --ca-path /etc/ssl/certs

> # Prepare the certificates for lighttpd
> ./acme.sh --install-cert -d <DOMAIN> --certhome /etc/ssl/private  --cert-file /etc/ssl/private/<DOMAIN>.crt --key-file /etc/ssl/private/<DOMAIN>.key --fullchain-file /etc/ssl/private/fullchain.crt --reloadcmd  "cat /etc/ssl/private/<DOMAIN>.crt /etc/ssl/private/<DOMAIN>.key > /etc/ssl/private/<DOMAIN>.pem"

> # Start lighttpd again
> /etc/init.d/lighttpd start

> # restore firewall normal-version config
> cp '/etc/config/firewall[normal.operations]'  /etc/config/firewall
> /etc/init.d/firewall reload

Unfortunatelly it does not work, I get the following error:

/root/.acme.sh/get_acme.sh: line 8: syntax error near unexpected token `newline’

/root/.acme.sh/get_acme.sh: line 8: `> # Stop lighttpd as acme.sh is starting its own daemon’

Do you know what went wrong? Unfortunatelly I’m bloody beginner when it comes to bash…

(As I didn’t want to wait - executing the commands directly in terminal works flawlessly! Thanks for the detailled explanation :grin:)

1 Like

Yes please add this to community documentation, I was not aware of this possibility and will going to use with Turris and Synology nas as well. Thank you !

Hi,

Do you really have the “>” character at the beginning of the lines? If so it is the problem.

Btw, having the file “/etc/config/firewall[normal.operations” preconfigured is quite dangerous. Any changes done via web GUI will be discarded by your script cause you will copy the old configuration. That’s why my original version of the script is making dynamic modification.

Stupid me - you are right concerning the “>”. Unfortunately they are inside your first script above, too.
Concerning the firewall-files: yes, I’ve been thinking about that. I will experiment with that this evening.

Can you answer (one or more) other of my question(s) above?

I see, sorry for those > . The original post can no longer be modified :unamused:

I updated the community documentation - https://www.turris.cz/doc/en/public/letencrypt_turris_lighttpd

NAS setup will come soon, I hope.

To the questions of ssdnvv:
Port 443 - Let’s necrypt does not allow for domain verification non-standard ports. So the acme.sh daemon must be reachable on 443. If some other services are runnig (like VPN) you must add to script command to stop it before and start after the certificate operations.

More certificates - I would prefer to run each device its own request. How to open ports will be in the Synology NAS guide.

Mixing certiifcates - Let’s Encrypt does not much care that you change the certificates. You you can can generate some now and later on to change it and use different content of certificate. Only thing I did never tested is to generate two different certificates (on different machines) but with the same hostname. This may cause some troubles in future.

4 Likes

Guide for devices behind Turris, eg. Synology NAS was added to community documentation.
https://www.turris.cz/doc/en/public/letencrypt_nas_behind_turris

3 Likes

I found the following cron for my diskstation:
"Minute":[11],"day":[-1],"hour":[22],"month":[-1],"week":[6]
The “-1” symbolizes a “*”, right?
So my crontab should look like this giving the routine 5 minutes before and 5 minutes after the Synology’s Let’s Encrypt-renewal-time?

6 22 * * 6 "/root/.acme.sh"/open_acme_NAS.sh > /dev/null
16 22 * * 6 "/root/.acme.sh"/close_acme_NAS.sh > /dev/null

Thank you tristone that you considered also Synology NAS as I want to install on Synology as well.

@tristone could you help me with post#13?

You mean the cron job timing?

Your example looks fine. But I am not perfectly sure how the day of the week (“week” parameter) is handled by SYnlogogy synocron. So if 6 means Saturday or Sunday.
For common Linux system in crontab the 6 means Saturday.

You may try to put 5 in your Turris crontab. Or just * to have the port open everyday.

Sorry but I did not found reliable documentation for synocrond.

Are you facing some exact issues?

Thanks for checking.

No, up til now I didn’t had access to my DS213+ due to work and now vacation.
But I gave your post some thoughts and one can easily check whether 6 is for Saturday or Sunday: one just needs to start a new cron-task via Synology web-interface.
I will try that and post the results (when I’m back from vacation) - I think that should be entered into documentation.

Hello @tristone,
thanks for sharing your know-how, I really like the idea.
It might be even more interesting to combine it with Apache HTTP server as ACME is being built in as module mod_md. :slight_smile:

Which way would you choose in order to use Apache - replace lighttpd (in order to use it as rrplacemeny for Luci/foris webif) or install Apache in LXC (for use with encapsulated webservices)?

Hi @Koleon

Question is what you mean by combining with Apache. If you want Apache httpd as secondary webserver on Turris the situation will we very similar to the lighttpd one, you need to adapt.
And if you mean Apache somewhere behing Turris then again you have to adapt the Synology guide accordingly.
I cannot provide guide for all possible combinations :slight_smile: and that’s why I covered the default usecase (lighttpd) and one typical for additional device.

If you want some hints how to setup Let’s Encrypt for Apache HTTPD I can provide. I have it done for Apache on both main platforms - Linux and Windows.

In general I do prefer to use external utility instead of Apache module. First thing is that it is external module (even if founded by Mozilla) and as such it may not be forever maintained in sync with the rest of httpd. And second it will be used once in 2-3 months and the rest of the time it will just be loaded and consume resources.
The external maintenance is not a problem even for live traffic cause Apache has gracefull restart feature so no connections are closed in case of restart needed for certificates renewal.

1 Like