Using Cloudflare for DDNS and TLS Certificates on Synology DSM6+
I wanted to secure my Synology NAS with a public TLS certificate, as I’ve been extending its use to include services like Pihole and DNSCrypt on my home network and resolve a public hostname. Like many people, my ISP also uses dynamic IP (though this rarely, if ever, changes). So I have two problems:
- I need a DDNS provider that I can use with my domain name (itsonpremises.dev)
- I need to use letsEncrypt to issue and roll my TLS certificates before/when they expire.
However, this led to two further problems:
- My current DDNS provider (Google domains) for my domain doesn’t support API access (though GCP does)
- 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.
Enter Cloudflare, who provide basic free plans for DNS, API access and is supported by acme.sh (https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide), which I want to use for my certificate renewals.
Configure Cloudflare for Synology DDNS
Synology doesn’t support Cloudflare by default, but JoshuaAvalon has written a script to get this configured within DSM: from https://github.com/joshuaavalon/SynologyCloudflareDDNS/
SSH into your Synology NAS and complete the following steps:
- Download DDNS script — I recommend saving as cloudflare_domainname.sh if you have multiple domains.
$ sudo wget https://raw.githubusercontent.com/joshuaavalon/SynologyCloudflareDDNS/master/cloudflareddns.sh -O /sbin/cloudflaredns_domainname.sh
2. Grant execute permissions
$ sudo chmod +x /sbin/cloudflaredns_domainname.sh
3. Push configuration to DSM DDNS provider list
$ sudo echo "[Cloudflare Domain Name]">>/etc.defaults/ddns_provider.conf
$ sudo echo " modulepath=/sbin/cloudflaredns_domainname.sh">>/etc.defaults/ddns_provider.conf
$ sudo echo " queryurl=https://www.cloudflare.com/">>/etc.defaults/ddns_provider.conf
$ sudo echo " website=https://www.cloudflare.com/">>/etc.defaults/ddns_provider.conf
Open Cloudflare dashboard for your domain name and complete the following steps:
- Get Zone ID for your domain
- Generate scoped API Token with the following permissions:
- Zone — Zone — Read
- Zone — DNS — Edit
Scope the token to your required domain name, if you have multiple Zones and/or require multiple DDNS entries for different hostnames
Return to DSM Gui and complete the following steps:
- Open Control Panel -> External Access -> DDNS
- Create “Cloudflare Domain Name”” DDNS entry in DSM Console:
- hostname: the a record of your domainname (mine syno.itsonpremises.dev)
- Username/Email: the ZoneID of your zone
- Password/Key: the scoped API token created in Cloudflare dashboard
Great stuff! DDNS should now be working, and you can move on to create the corresponding TLS certificates for your Synology NAS
Configure Synology for LetsEncrypt Certificates
I suggest the following prerequisites to save time and keep this process scoped to a dedicated service user.
- Create a new certificate administrator to run acme.sh and own the cron job for refreshing certificates.
- This user must be a member of the administrators group
- Ensure you set DENY permissions on all applications other than DSM (and restrict DSM access to your NAS IP address, if possible (localhost/127.0.0.1 is unfortunately not supported)
- Ensure the user has r/w permissions to /home(s) if you have this enabled
- You will need to Disable HTTP2, if you have this configured: Control Panel -> Network -> DSM Settings -> Disable HTTP2
SSH into your Synology NAS with your new Certadmin user and complete the following steps:
Install reload-certs.sh (recommended)
You can use this third party script to automatically restart services when certificates are changed.
$ sudo wget -O /usr/local/bin/reload-certs.sh https://github.com/bartowl/synology-stuff/raw/master/reload-certs.sh
$ sudo chmod +x /usr/local/bin/reload-certs.sh
Install acme.sh (with sudo -i)
From https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide
(updated 15/01/2024: in the code snippet below, I also run dash-dash register-account which is needed for ZeroSSL certs)
$ sudo -i
$ wget https://github.com/Neilpang/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@gmail.com"
$ sudo chown -R mycertadmin /usr/local/share/acme.sh/
$ sudo chmod 755 /usr/local/share/acme.sh
$ ./acme.sh --register-account -m "email@gmail.com"
Be sure to exit your sudo session after installation and reconnect for the following steps.
Configure Cloudflare API settings
acme.sh supports using your global Cloudflare API key, or a scoped API token. I am using a token to minimise blast radius within my Cloudflare account.
Ensure you’re no longer sudo and export your environment variables below — note the difference between CF_Key and CF_Token
$ export CF_Key="MY_SECRET_KEY_SUCH_SECRET"
$ export CF_Email="myemail@example.com"
If you generated an API Token, instead of using your global account key, set CF_Token instead (preferred, and you’re using it for DDNS anyway, right?)
$ export CF_Token="MY_SECRET_TOKEN_SUCH_SECRET"
$ export CF_Email="myemail@example.com"
For either approach, you will also need your Cloudflare Account_ID. Include your Zone_ID to scope acme.sh access further within your account.
$ export CF_Account_ID="xxxxxxxxxxxxx"
$ export CF_Zone_ID="xxxxxxxxxxxxx"
Create your certificate signing request:
cd /usr/local/share/acme.sh$ ./acme.sh --issue -d "star.example.com" \
--dns dns_cf --home \
$PWD
Install certificate on DSM
With the certificate now generated, we will use our Synology_Username Certificate Administrator to push the certificate into DSM via a webhook.
Create environment variables for this process (note the single quotes around the Syno_Password if you have used a complex/secure password):
$ export SYNO_Username="Certadmin"
$ export SYNO_Password='MyPassw0rd!'
$ export SYNO_Certificate="mydesc" # description shown in Control Panel ➡ Security ➡ Certificate
$ export SYNO_Create=1
If you already access your NAS with a secure certificate, you should set the additional variables for the hook to login correctly:
$ export SYNO_Scheme="http" # Can be set to HTTPS, defaults to HTTP
$ export SYNO_Host="localhost" # Specify if not using localhost
$ export SYNO_Port="5000" # Port of DSM WebUI (5000 for HTTP and 5001 for HTTPS)
$ export SYNO_Device_Name="Something" #required for skipping 2FA-OTP, set via script upon first run
$ export SYNO_Device_ID="SomethingElse" #required for skipping 2FA-OTP, set via script upon first run
Run the deployment command:
./acme.sh -d "star.example.com" --deploy \
--deploy-hook synology_dsm \
--reloadcmd "/usr/local/bin/reload-certs.sh" \
--dnssleep 20 \
--home $PWD
The newly issued certificate will now appear in your certificate list within DSM. Take a look in Control Panel ->Security -> Certificate(s).
Press <Configure> button to change the default certificates for your desired services to your newly issued certificate. Also, right-mouse-click and select “Edit” to set the certificate as System Default.
Setup recurring task for renewal and replace
Although acme.sh
can set up a cronjob automatically, you shouldn’t use it with your Synology NAS as DSM security advisor will give you a critical warning. Instead, opt to use the built-in task scheduler:
- Control Panel -> Task Scheduler
- Create -> Scheduled Task -> User-defined script
- Fill out the necessary information:
- General: Give the task a name and choose your newly created Certificate Admin user
- Schedule: e.g. weekly at 4:00 am on Saturday
- Task Settings: maybe set up an email notification and use one of the following scripts for Renewal.
# Renew single certificate
/usr/local/share/acme.sh/acme.sh --renew -d "star.example.com" --home /usr/local/share/acme.sh# Renew all certificates issued via acme.sh
/usr/local/share/acme.sh/acme.sh --cron --home /usr/local/share/acme.sh
This recurring task automatically renews your certificate and deploys it to your Synology NAS using the stored settings of the previous step.
export SYNO_Username="Certadmin"
export SYNO_Password='MyPassw0rd!'
export SYNO_Certificate="star.example.com"
# export SYNO_Create=1 # Only required on first-run
export SYNO_Scheme="http"
export SYNO_Host="localhost"
export SYNO_Port="5000"
cd /usr/local/share/acme.sh
/usr/local/share/acme.sh/acme.sh --renew -d "star.example.com" --home /usr/local/share/acme.sh &&
/usr/local/share/acme.sh/acme.sh -d $SYNO_Certificate --deploy \
--deploy-hook synology_dsm \
--reloadcmd "/usr/local/bin/reload-certs.sh" \
--dnssleep 20 \
--home $PWD
If you set notifications, you will get a recurring error from the script “Interrupted, exit 2” as your cert doesn’t need renewing for 3 months. Note in the codeblock above, the && operator only executes the deployment of the script *if* the renewal script runs successfully (with an exit0).
Check the text in your email to ensure it’s as expected:
Be aware that going forward, you may need to reinstall acme.sh to fix a broken environment after Synology DSM upgrade(s).
$ cd /usr/local/share/acme.sh
$ ./acme.sh --force --upgrade --nocron --home /usr/local/share/acme.sh
or manually add below line into /root/.profile
. "/usr/local/share/acme.sh/acme.sh.env"