
Synology’s DSM comes with a default Synology self-signed certificate. When accessed via the web, the browser will prompt that the site is untrusted. As someone with obsessive-compulsive disorder, this is unbearable! So, I spent some time researching how to apply for a Let’s Encrypt certificate through DDNS.
The plan has a few principles:
- Try to use virtualization solutions as much as possible for easy migration in the future (although the likelihood of changing the NAS in the future is slim).
- The intrusion into the entire system should be as low as possible, and configuration work should be minimized.
Fortunately, DSM now supports Docker virtualization, which can basically meet the above two requirements. Now that the requirements and goals are clear, let’s get started!
Applying for a certificate with acme.sh
First, let me introduce some basic information about my environment: I use duckdns dynamic domain name to map DSM to the public network for easy access, so I prefer to apply for a Let’s Encrypt certificate for the duckdns domain name. At the same time, I like to use acme.sh, and this program has built-in support for duckdns.
The problem is, although there is a public IP, because domestic operators have blocked ports 80 and 443, it is not possible to apply for a ddns domain name certificate using http. After research, I found that duckdns can set txt records, so I decided to apply for a certificate using the dns txt record method.
Log in to DSM and use the following command to create an acme.sh image:
- docker run -itd -v <absolute path to save the certificate>:/acme.sh --env DuckDNS_Token="xxxxxxxx-oooo-xxxx-zzzz-aaaaaaaaaaa" --net=host --name=acme.sh neilpang/acme.sh daemon
neilpang/acme.sh is an image made by others on the internet, and after research, it fully meets the requirements of this time. Note that you should replace the part of the above command <absolute path to save the certificate> with the path where you store your certificate. Also, if you are using duckdns, you need to set an environment variable DuckDNS_Token. For acme.sh’s support for other ddns, please refer to reference 1 at the end of the text.
If the above container is successfully created, you can see the image just created on the web page:

Then execute the following command to formally start applying for the certificate, where xxxx.duckdns.org is the author’s ddns domain name:
- docker exec acme.sh --set-default-ca --server letsencrypt
- docker exec acme.sh --issue --dns dns_duckdns -d <your domain name> --insecure --debug
If there are no network problems, the certificate will be stored in the <absolute path to save the certificate> location, with <your domain name> as the folder name:

Updating the acme.sh certificate
Since the certificate applied for by Let’s Encrypt is valid for 3 months, it is necessary to consider the issue of regular certificate updates.
The good news is that the neilpang/acme.sh container has already considered this issue for us. As long as you start this container in daemon mode as described above, the container will automatically create a crontab task to check whether the certificate needs to be updated every day:

So we just need to ensure that the acme.sh container is always running, and the certificate we applied for can be automatically updated.
Let DSM help us initialize the certificate
OK, now that we have the certificate, we need to configure DSM to use the applied certificate. Here the author takes a shortcut and lets DSM help us initialize it once. Log in to DSM and select “Control Panel”, “Security”, “Certificate” in turn, select “Add New Certificate” and click “Next”:

The second step is to choose to import the certificate, the name can be arbitrary, it is recommended to use your domain name, this step must be checked “Set as default certificate”, because our update script in the later text depends on this default certificate feature:

The third step is to choose the certificate applied for by acme.sh above:

After clicking OK, you can see the certificate just applied for in DSM’s certificate management:

At this time, select the certificate just imported, click the settings button above, and set all system certificates to the certificate just imported:

After clicking OK, you will be prompted to restart the Web service. After the restart is complete, exit to the login page and find that accessing DSM with the ddns domain name will be marked as a secure link:

Configure certificate auto-update
Through research, it is found that DSM stores all certificate information in the /usr/syno/etc/certificate/_archive directory, and the /usr/syno/etc/certificate/_archive/DEFAULT file records the current default certificate (this is related to the check default certificate action mentioned above).
Therefore, the idea is to first read the folder name of the current certificate from the DEFAULT file, then replace the default certificate with the certificate file under the system service, and finally restart the system service. The formed update script is as follows (assuming you save the following content as the update-certificate.sh file), the usage method is:
./update-certificate.sh “<absolute path of your certificate>/<your domain name>”
The script content is as follows:
- #!/bin/sh
- ACME_CERTIFICATE_PATH=${@:1:1}
- ACME_DOMAIN_NAME=$(ls ${ACME_CERTIFICATE_PATH}/*.csr | tr -d "\n")
- ACME_DOMAIN_NAME=$(basename ${ACME_DOMAIN_NAME})
- ACME_DOMAIN_NAME=${ACME_DOMAIN_NAME//.csr/}
- SYNOLOGY_CERTIFICATE_PATH="/usr/syno/etc/certificate"
- SYNOLOGY_DEFAULT_CERTIFICATE_NAME=$(cat "${SYNOLOGY_CERTIFICATE_PATH}/_archive/DEFAULT" | tr -d "\n")
- SYNOLOGY_DEFAULT_CERTIFICATE_PATH="${SYNOLOGY_CERTIFICATE_PATH}/_archive/${SYNOLOGY_DEFAULT_CERTIFICATE_NAME}"
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/fullchain.cer' ${SYNOLOGY_DEFAULT_CERTIFICATE_PATH}/fullchain.pem"
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/${ACME_DOMAIN_NAME}.cer' ${SYNOLOGY_DEFAULT_CERTIFICATE_PATH}/cert.pem"
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/${ACME_DOMAIN_NAME}.key' ${SYNOLOGY_DEFAULT_CERTIFICATE_PATH}/privkey.pem"
- for each_file in `find ${SYNOLOGY_CERTIFICATE_PATH} -name info -not -path "${SYNOLOGY_CERTIFICATE_PATH}/_archive/*"`;do
- each_directory=$(dirname ${each_file})
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/fullchain.cer' ${each_directory}/fullchain.pem"
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/${ACME_DOMAIN_NAME}.cer' ${each_directory}/cert.pem"
- /bin/sh -c "cp '${ACME_CERTIFICATE_PATH}/${ACME_DOMAIN_NAME}.key' ${each_directory}/privkey.pem"
- done
Finally, create a new task in DSM’s “Control Panel”, “Task Schedule”, and the settings on each page are as follows, so that the certificate applied for in the container will be copied to DSM’s certificate directory on the 1st of every month:
![]() | ![]() | ![]() |
Note: Since the author is a NAS shutdown party, the NAS will shut down at 12 o’clock every night and start at 9 o’clock the next morning, so the above script does not include the function of restarting the service, you can add the service that needs to be restarted according to your own needs!