xFelix
xFelix

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

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"
synosystemctl restart nginx
  • 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?

    4 years ago Reply
    • 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

      4 years ago Reply
    • 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.

      4 years ago Reply
      • 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?

        4 years ago Reply
        • 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.

          4 years ago Reply
          • 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.

            4 years ago
  • Kai

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

    4 years ago Reply
  • 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?

    4 years ago Reply
    • 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).

      4 years ago Reply
      • 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?

        4 years ago Reply
    • FelixOwner

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

      4 years ago Reply
  • 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 ;)

    4 years ago Reply
    • 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.

      4 years ago Reply
      • 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.

        4 years ago Reply
      • 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.

        4 years ago Reply
      • 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?

        4 years ago Reply
  • 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.

    3 years ago Reply
    • 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?

      3 years ago Reply
      • Max

        @Wim: I’ve got the same issue, the problem being that if I do an actual restart of nginx it kills a bunch of other things in the process, notably Docker and all running containers, as well as the Virtual Machine Manager and any VMs.

        I can’t understand why nginx would be so ingrained with unrelated services but there it is. What’s needed is a way to properly reload the service without restarting it…

        2 years ago Reply
        • Max

          @Max: Ah, I foung the answer on reddit:

          synow3tool –gen-all && systemctl reload nginx

          Hopefully this helps someone else years down the line!

          2 years ago Reply
          • @Max: Edit Script – need to force using external DNS like current acme.sh uses external DNS
            using internal is an issue – causes me to edit DNS away from internal then run script
            next – love the new restart – having to switch in security > certs is a PITA

            1 year ago
  • 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?

    3 years ago Reply
  • nsar

    thank you so much for this great post!

    maybe it’s a very noob question but is it possible to make it work Synology DNS server app ?

    3 years ago Reply
    • nsar

      @nsar: im not able to edit the post.

      one more question. is this including lets encrypt wildcads ?

      3 years ago Reply
      • FelixOwner

        @nsar: Hi Nsar, I haven’t used Synology DNS server. To issue a public trusted letsencrypt certificate using DNS mode, you have to publish the DNS server to Internet. Which is not that easy to maintain from security point of view. But technically it is possible. Need to see whether acme.sh DNS api supports Synology DNS server.
        For the wildcast, it is supported by acme.sh.

        3 years ago Reply
  • having a few issues – DNS – must use public DNS cannot use internal dns
    would like to have the script use a dedicated DNS for its purposes only…

    basically it doesn’t work when I use my internal DNS – I have to set DNS to public DNS then the script work fine…

    (network forces all dns to internal AD then only allows 53 UDP/TCP from authorized DNS outbound)
    have rule now allowed for syno to go outbound – however have to edit resolv conf every time.)
    using ldap logins from AD so need to maintain the DNS to keep ldap operational as well!

    3 years ago Reply
    • @viper-3: Maybe – DNS wise – Utilize DoH for dns-01 challenge?!?
      I’m not sure how that would work but the call would be a tls / ssl request to 1.1.1.1 for the specific script vs all normal traffic could still maintain normal path.

      — Issue #2
      Was previously using this guide
      https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide
      worked but had to manually set the export variables every time —
      Issue currently is while the system cert is showing correct and valid…
      Surveillance Station is still holding onto the expired cert… think its part of the old way / exports…

      Haven’t found it just yet… still digging…

      3 years ago Reply
      • FelixOwner

        @viper-3: Surveillance Station use the same certificate as DSM. So please check the system default one is getting renewed properly. And the web service is reloaded.

        Regarding the DNS issue you mentioned, I believe it is due to the fact of acme.sh using DoH to query the upstream DNS server for DNS01 method. This is part of letsencrypt (acme.sh) domain ownership verification method.

        If your network environment is blocking direct outbound DoH or DNS to Internet, it will fail. Just think if acme.sh only queries your local DNS (AD), you have all the ways to control your DNS server to spoof the certificates issue process.

        3 years ago Reply
        • Meeshaw

          @Felix: I see the new certificate in DSM but still have the old one in the Browser. Replaced the certificates under /usr/syno/etc/certificate/_archive/xyz/ and /usr/syno/etc/certificate/system/default/ as well. Restarting the Synology did not help so I’m assuming thats not the correct certificate location? Any help is much appreciate. Btw I only have one certificate.

          2 years ago Reply
          • FelixOwner

            @Meeshaw: @Meeshaw, you can try to login DSM to make sure which certificate the system is using. There’s setting in DSM – Security – Certificate to choose which certificate bind to which service. You can also try to add a new self-issued certificate in DSM so that you can compare the new created certificate path. Replace the acme.sh issued certificate in that location may be helpful in this case. Also restart the nginx web service.

            2 years ago
  • cgeo

    For some reason I cannot get my letsencrypt certificates from within the terminal. I always get the error “timeout during connect (likely firewall problem)”. When I ssh to synology and run the acme script it works without issues. The container has the same network as the host so I am not sure where the problem is since I am using the DSN method, no ports need to be opened. Any ideas ?

    2 years ago Reply
    • FelixOwner

      @cgeo: Is acme.sh container the only one running in docker? Probably worth check your docker network settings. Any other container has network issue?

      2 years ago Reply
  • Aizal

    Hi, if I need to cover for wildcard, do I need to change the “a.example.com” to “*.example.com”?

    2 years ago Reply
    • FelixOwner

      @Aizal: acme.sh –issue -d example.com -d ‘*.example.com’ –dns dns_cf

      You can also check acme.sh manual

      2 years ago Reply
  • Andreas

    Hi,
    thank you for the idea of using acme.sh via docker, I just recently configured it on the NAS itself with the drawback of fixing the environment on updates as you mentioned.
    I might clean it up and start over with the docker way.

    One improvement I could recommend is using the web deploy hook from acme.sh which is available for DSM.
    That way is more secure and less error prone to replace the certificate in use and will restart the necessary services automatically via API access.
    No need to schedule a task to copy the certificates at all, you do not need to rsync the certs and check the appropriate folders.

    You can check the wiki here:
    https://github.com/acmesh-official/acme.sh/wiki/deployhooks#20-deploy-the-cert-into-synology-dsm

    You basically just need an admin user for API access and then deploy the certificate one time to set up the environment:
    acme.sh –deploy -d example.com –deploy-hook synology_dsm

    It will even work with 2FA, you just need to set a few environment variables

    2 years ago Reply

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