xFelix
xFelix
Issue Synology Let's Encrypt Cert by acme.sh docker

I wrote a previous blog talking about how to issue and install letsencrypt ssl cert on Synology 3 years ago. I also participated in updating the early version of Synology NAS Guide wiki of acme.sh. At that time, acme.sh was installed on Synology DSM OS directly. It was running well and smoothly if you follow my blog instruction.

However, recently I notice acme.sh tries to move away from using root user or sudo to run the script. This leaves some concern if we still use the old way of managing Let’s Encrypt certificate on DSM is not that appropriate. Also considering the limitation I highlighted in both my blog and acme wiki, after each major DSM firmware upgrade, need manually fix the broken acme environment. And the last, lot of people like me want to keep the system clean, and are fan of Docker virtual instance. After 3 years, I believe most Synology users have upgraded their equipments already that support Docker. So this new guide is talking about how to use acme.sh docker to issue Let’s Encrypt certificate for Synology DSM.

Again, I use Cloudflare DNS as example.

After 3 years, Cloudflare also improved their API and permissions. Now you can generate individual API key for specific service instead of giving out global API key. You can also control the permission required for different service.

  • Go to your Cloudflare dashboard and get your API key.
  • The API key only requires Zone:Zone:Read, and Zone:Dns:Edit permission, Zone resources need to include all zones from your account.
  • Copy your generated new API key and Account ID with below format and save to /volume1/docker/acme/account.conf
export CF_Token="32jfjsah3wjhfalfxxxxxxx"
export CF_Account_ID="6axxxxxxxxxxxxxxxxxxxxx"
  • Log into Synology DSM and open Docker app
  • In the Registry, search and find neilpang/acme.sh. Download the latest image.
  • Launch the container with the downloaded neilpang/acme.sh image
  • Go to Advanced setting, map the volume folder dock/acme with /acme.sh and set the container network to use the same as host. Environment command ‘daemon’

  • Then start the container and with auto-restart
  • Go to container Terminal – Create – Launch with command

  • Enter a command: ‘sh’

  • In ‘sh’ terminal command, type in acme.sh cert issue command you need.
  • eg.
    acme.sh --issue --dns dns_cf -d a.example.com

  • After successfully issue the certificate, the cert files will be stored at /volume1/docker/acme/a.example.com/
  • You can now create a scheduled task (every month) in DSM to regularly copy cert files to DSM system directories. Please note: the command below is for reference only, you need to replace with the correct path of your system environment. Especially the ‘Random PATH’ is unique in your DSM.
docker exec neilpang-acme.sh1 acme.sh --issue --force --dns dns_cf -d a.example.com
sleep 2m
rsync -avh "/volume1/docker/acme/a.example.com/a.example.com.cer" "/usr/syno/etc/certificate/_archive/Random PATH/cert.pem"
rsync -avh "/volume1/docker/acme/a.example.com/a.example.com.key" "/usr/syno/etc/certificate/_archive/Random PATH/privkey.pem"
rsync -avh "/volume1/docker/acme/a.example.com/fullchain.cer" "/usr/syno/etc/certificate/_archive/Random PATH/fullchain.pem"
rsync -avh "/volume1/docker/acme/a.example.com/ca.cer" "/usr/syno/etc/certificate/_archive/Random PATH/chain.pem"
/usr/syno/etc/rc.sysv/nginx.sh reload
  • It’s all done. No need to modify DSM system configuration and repair broken acme.sh env anymore.
Written by Felix. Licensed under CC BY-NC-SA 3.0 Unported.

Leave a Reply

textsms
account_circle
email

  • jason8612

    I’m a bit confused. acme.sh –issue –dns dns_cf -d a.example.com part does issue me a cert for my domain and the scheduled task does replace the old cert in synology, but to update the cert, it seems that I need to manually go to the container, terminal, sh and enter acme.sh –issue –dns dns_cf -d a.example.com then run the scheduled task.
    Is there a wat to automate this in the scheduled task?
    for instance the task would run the docker with acme.sh –issue –dns dns_cf -d a.example.com then copy the files and restart nginx?

    7 monthsago replied
    • jason8612

      @jason8612: docker exe CONTAINERNAME acme.sh –issue –force –dns dns_cf -d a.example.com
      sleep 2m
      rsync -avh “/volume1/docker/acme/a.example.com/a.example.com.cer” “/usr/syno/etc/certificate/_archive/Random PATH/cert.pem”
      rsync -avh “/volume1/docker/acme/a.example.com/a.example.com.key” “/usr/syno/etc/certificate/_archive/Random PATH/privkey.pem”
      rsync -avh “/volume1/docker/acme/a.example.com/fullchain.cer” “/usr/syno/etc/certificate/_archive/Random PATH/fullchain.pem”
      rsync -avh “/volume1/docker/acme/a.example.com/ca.cer” “/usr/syno/etc/certificate/_archive/Random PATH/chain.pem”
      /usr/syno/etc/rc.sysv/nginx.sh reload

      7 monthsago replied
    • FelixOwner

      @jason8612: Let the docket container run in Daemon mode which acme.sh will check whether issued cert is due to renew. No need to force renew by yourself.
      What you need to run a schedule task to copy the certificates issued from container to DSM default cert path.

      7 monthsago replied
      • Blaze

        @Felix: So that means, either we keep the docker container running in Daemon mode, and we can remove the “docker exec” and “sleep” in the scheduled tasks, or stopping the daemon process and “docker exec” and “sleep” on a monthly basis?

        3 monthsago replied
        • Blaze

          @Blaze: After some investigations, I figured it out.
          We need to keep the container running, so the scheduled task to make acme.ch to force issue certificates with your demo code. Suppose we can have a “docker start” command at the beginning, sleep for a bit, and follow by the “docker exec” command in your example.

          Hopefully this would help avoid any memory / socket issues. (I do find my container acting a little strange after a while in daemon mode, not able to see and create any terminals)

          I also tweaked the scheduled task a little for myself, to only “–renew”, rather than “–force –issue”, and rsync all files except the key file.

          As a security measure, I also remove the key file from the docker shared folder as well as chmod 400 to the “/usr/syno/etc/certificate/_archive/Random PATH/*” directory, tailing the end of the user defined script in scheduled tasks.

          Again thank you Felix for your great article, it does help me understand how certificate issue and renewal can be done using DNS-01.

          3 monthsago replied
          • FelixOwner

            @Blaze: Thanks again for you detailed comment.
            The reason I use -force is because the logic of acme.sh calculating whether certs need to renew is based on days, while DSM schedule task is only allowed to set frequency on certain date of each month. You know some month has 30 days, some has 31 days. If you leave acme.sh to decide when to renew, sometimes it will cause the certs expired due to 1 or 2 days gap.

            3 monthsago
  • Kai

    The “daemon” command make my day. Thank you.

    5 monthsago replied
  • Blaze

    Thank you Felix! This is wonderful!

    Can I check, after all the setup, I can stop the docker container right?

    Also, if I want to obtain another certificate under the same zone for the same NAS, do I:
    1) Run the same acme.sh command with different -d parameter in the “sh” terminal? and
    2) Duplicate the “docker” and “rsync” commands in the scheduled task script, with the right domains, paths, RANDOM_PATH?

    3 monthsago replied
    • FelixOwner

      @Blaze: I don’t think ‘docker exec’ can run on a stopped container.
      To answer your second question. Use this container you can issue any certificate as your wish. The issued certificates will be stored under /volume1/docker/acme/x.example.com/ . What you need to do is copy the relevant certificates out to the destination system (this NAS or any other devices).

      3 monthsago replied
      • Blaze

        @Felix: Thanks again.

        Referring to the documentation. https://github.com/acmesh-official/acme.sh/blob/master/README.md when running acme.sh as daemon, I presume acme.sh would automatically renew the Let’s Encrypt certificate, am I correct?

        If so, why need the docker exec commend in the scheduled task?
        Would you know if the auto renewal behaviour would persist after NAS/Docker container restart?

        3 monthsago replied
    • FelixOwner

      @Blaze: The acme.sh container will only consume around 10MB RAM and almost none cpu. No need to stop it.

      3 monthsago replied
  • vincentbls

    This method does not work completely.
    While the certificate appeared to be renewed, the “.pem” files of the new certificate are not copied wherever they should have been, so web browsers were still using the old files.
    Check your browser ;)

    3 monthsago replied
    • FelixOwner

      @vincentbls: Thanks for your comment. Please make sure you create monthly schedule task to force renew the certificate and rsync copy the certificate files to the right DSM cert directory. You can take a look at my previous post of how to find the DSM certificate directory.

      3 monthsago replied
      • vincentbls

        @Felix: That’s not the problem, it works fine. But the new certificate is not recognized by the browser.
        You just have to empty the cache, reconnect and consult the certificate used : it’s the old one.

        2 monthsago replied
      • vincentbls

        @Felix: The new certificate appears in the DSM control panel, but you have to re-import it manually so that it can be used instead of the old one.

        2 monthsago replied
      • vincentbls

        @Felix: Sorry I can’t edit my answers… I think we also need to update the *.pem files in the corresponding /usr/local/etc/certificate/WebStation/vhost_xxxxx directory. These are still the old files. Possible by modifying the script?

        2 monthsago replied
  • Wim

    Hi Felix. Thanks for the write up. It’s working like a charm. I’m running into 1 issue. So, certificates get renewed perfectly. In my case a wildcard certificate. It get’s copied tot the correct folder by rsync.

    The certificate is set as the default certificate for all my services. All of my services are running through the application portal/reverse proxy.

    Problem is, the updated certified does not get sent to browsers. It keeps showing the old, expired certificates. I’ve tested this via ssllabs.com.

    Rebooting the services or the entire synology does not help.

    The only thing which helps is adding a new, random certificate through the synology interface. Changing a service to use the new certificate. Then revert that back to using the default certificate. Now the updated certificate for this single service is showing to browsers. So I need to do these steps for all the services.

    This is quite weird and I can’t seem to find out why this happens.

    2 monthsago replied
    • Wim

      @Wim: Hey @felix, I might have figured it out.
      I’ve just tried
      /usr/syno/sbin/synoservicectl –restart nginx
      This seems to have fixed this for all my services at once.

      Do you think you should replace
      /usr/syno/etc/rc.sysv/nginx.sh reload
      with that?

      2 monthsago replied
  • Wim

    Hey Felix, I might have figured it out.
    I’ve just tried
    /usr/syno/sbin/synoservicectl –restart nginx
    This seems to have fixed this for all my services at once.

    Do you think you should replace
    /usr/syno/etc/rc.sysv/nginx.sh reload
    with that?

    2 monthsago replied

xFelix

Issue Synology Let's Encrypt Cert by acme.sh docker
I wrote a previous blog talking about how to issue and install letsencrypt ssl cert on Synology 3 years ago. I also participated in updating the early version of Synology NAS…
Scan QR code to continue reading
2020-04-17