Skip to content
XDigital edited this page Aug 7, 2024 · 84 revisions

HTTPS certificates for your Synology NAS using acme.sh

Since Synology introduced Let's Encrypt, many of us benefit from free SSL.

On the other hand, many of us don't want to expose port 80/443 to the Internet, including opening ports on the router. The alternative is to use the DNS-01 protocol. Sadly the Synology implementation of Let's Encrypt currently (1-Jan-2017) only supports the HTTP-01 method which requires exposing port 80 to the Internet. Also, if the domain of your NAS has an IPv6 AAAA record set, the Synology implementation of Let's Encrypt will fail.

But we can access the NAS via SSH and configure it to renew certs instead of using the web dashboard.

The following guide will use the DNS-01 protocol using the Cloudflare API, where I host my domain. However, since acme.sh supports many DNS services, you can also choose the one you like.

With the Synology DSM deployhook included in 2.8.6, it is no longer required to run acme.sh on your Synology device to rotate the certificate. acme.sh just needs to be run on something that has access to the DSM's administrative interface. Additionally, the previous deployment methods can be drastically simplified with the following instructions.

Installation of acme.sh

sudo su
cd ~
wget https://github.com/acmesh-official/acme.sh/archive/master.tar.gz
tar xvf master.tar.gz
cd acme.sh-master/
./acme.sh --install --nocron --home /usr/local/share/acme.sh --accountemail "[email protected]"
source ~/.profile

Configuring DNS

For CloudFlare, we will set two environment variables that acme.sh (specifically, the dns_cf script from the dnsapi subdirectory) will read to set the DNS record. You can get your CloudFlare API key here.

export CF_Key="MY_SECRET_KEY_SUCH_SECRET"
export CF_Email="[email protected]"

If you generated an API Token, instead of using your global account key, set CF_Token instead.

export CF_Token="MY_SECRET_TOKEN_SUCH_SECRET"
export CF_Email="[email protected]"

In case you use another DNS service, check the dnsapi directory and DNS API guide. Instructions for many DNS providers are already included. You can also find instructions on how to add another DNS service there, although that requires some software development skills.

Creating the certificate

Now it's time to create the certificate for your domain:

# These commands assume you are still working in the same terminal and have ran necessary commands described above.

cd /usr/local/share/acme.sh
export CERT_DOMAIN="your-domain.tld"
export CERT_DNS="dns_cf"
./acme.sh --issue --server letsencrypt --home . -d "$CERT_DOMAIN" --dns "$CERT_DNS" --keylength 2048

Deploy the default certificate

We will use the Synology DSM deployhook to deploy our certificate. This will override the default certificate (if you haven't set any description for it), you can learn how to create new certificates to be used for other services later in this section.

The commands in the code block in this section assume you are still working in the same terminal and executed necessary commands described above.

Deploy with temp or existing admin user

(Recommend) Deploy with auto created temp admin user

If you installed acme.sh in DSM, we recommend you to try automatic temp user auth method to deploy (DSM should already have required built-in tools, we will let you know if not):

export SYNO_USE_TEMP_ADMIN=1
./acme.sh --deploy --home . -d "$CERT_DOMAIN" --deploy-hook synology_dsm

In this way, you won't need to provide any admin credentials, the deploy sciprt itself will utilize Synology built-in utils to complete authentication, so it designed to only support locally deployment, and can't be used to deploy in docker or deploy remotely.

Script will load previous saved conf for subsequent deployments, so if you want to back to deploy with existing admin user, you need to execute export CLEAR_SYNO_USE_TEMP_ADMIN=1 first. After deploy script exits, the temp admin user should either not have been created or has already been deleted, however it may still remain if script exits unexpectedly (e.g., aborted by pressing "Ctrl+C"), in this case, you can safely delete it via "Control Panel".

Deploy with existing admin user

If you prefer to deploy with existing admin user or if the above way is not available (e.g., installed in docker, want to deploy remotely, etc.), you need to provide your own credentials:

# Single quotes prevents some escaping issues if your password or username contains certain special characters
export SYNO_USERNAME='Admin_Username'
export SYNO_PASSWORD='Admin_Password!123'
./acme.sh --deploy --home . -d "$CERT_DOMAIN" --deploy-hook synology_dsm

Note that if the user specified by SYNO_Username has enabled two-factor authentication (2FA), the script will require you to manually input the TOTP code just like you were logging in on the Web UI (if you didn't provide the code via export SYNO_OTP_CODE=XXXXXX), it will also require you to input the device name for verification (also can be provided via like export SYNO_DEVICE_NAME=CertRenewal), then obtain to store necessary info which can be used to omit the TOTP, so you won't need to do manually input again in the future.

BTW, as you may know if you used to use this script to deploy, the necessary info here now is so-called parameter "Device ID", if you are a pro user and want to obtain it manually, you still can, method in short: log into your DSM via its website, making sure you've ticked Remember this device when asked for your OTP, get the did cookie's value and set the environment variable SYNO_DEVICE_ID:

export SYNO_DEVICE_ID='YOUR VALUE'
./acme.sh --deploy --home . -d "$CERT_DOMAIN" --deploy-hook synology_dsm

Use HTTPS to deploy

When we want to use HTTPS to deploy the new certificate and connect to "localhost", we need to add the --insecure option to the deploy command to prevent curl errors. Refer to [https://github.com/acmesh-official/acme.sh/wiki/Options-and-Params]. If you enabled HTTP/2 you still receive a curl 16 error probably due to missing http2 dependencies on the NAS but the script succeeds.

# export SYNO_HOSTNAME="localhost" # Specify if not using on localhost
export SYNO_SCHEME="https"
export SYNO_PORT="5001"
./acme.sh --deploy --insecure --home . -d "$CERT_DOMAIN" --deploy-hook synology_dsm

Additionally, if you are using temp admin method to deploy, to prevent confusion, the value of SYNO_HOSTNAME must targets to current local machine (can be localhost or 127.0.0.1), however if your custom SYNO_HOSTNAME does indeed target to current local machine, you should execute export SYNO_LOCAL_HOSTNAME=1 before deploying.

Deploying additional certificates

By specifying a different SYNO_CERTIFICATE (and set SYNO_CREATE=1 for creating), we can deploy multiple certificates to the DSM.

# SYNO_Certificate is the description shown under Security -> Certificates in the DSM Control Panel
export SYNO_CERTIFICATE="A different certificate description"
export SYNO_CREATE=1 # Says to create the certificate if it doesn't exist
./acme.sh --deploy --home . -d "subdomain.$CERT_DOMAIN" --deploy-hook synology_dsm

Configuring Certificate Renewal

To auto renew the certificates in the future, you need to configure a task in the task scheduler. It is not advised to set this up as a custom cronjob (as was previously described in this wiki page) as the DSM security advisor will tell you that you have a critical warning regarding unknown cronjob(s).

In DSM control panel, open the 'Task Scheduler' and create a new scheduled task for a user-defined script.

  • General Setting: Task - Update default Cert. User - root
  • Schedule: Setup a weekly renewal. For example, 11:00 am every saturday.
  • Task setting: User-defined-script:
# renew certificates 
/usr/local/share/acme.sh/acme.sh --cron --home /usr/local/share/acme.sh

Fix a broken environment after Synology DSM upgrade

./acme.sh --force --upgrade --nocron --home .

or manually add below line into /root/.profile

. "/usr/local/share/acme.sh/acme.sh.env"
Clone this wiki locally