Wednesday, August 19, 2026 76°F Knoxville
Mon–Fri 9–5 ET Answered by a human
Infrastructure · IMPLEMENTED

Automating Wildcard SSL Certificates on Synology NAS with acme.sh

How to run acme.sh on a Synology NAS: wildcard Let's Encrypt via Cloudflare DNS-01, then the synology_dsm hook so certs survive DSM updates.

*.domainCASE REPORT

How do I install acme.sh on Synology?

Install acme.sh in a home directory on the Synology NAS, not /root/.acme.sh. DSM’s built-in Let’s Encrypt tool cannot issue a wildcard and needs port 80 open. Use Cloudflare DNS-01 for the Let’s Encrypt DNS challenge, then the synology_dsm deploy hook so the acme.sh certificate lands in DSM and survives DSM updates.

Why can't Synology issue a wildcard Let's Encrypt certificate?

DSM’s built-in Let’s Encrypt tool issues one public hostname over HTTP-01. It will not issue *.int.example.com, it will not validate a name that is not reachable from the internet, and it wants port 80 open to do the challenge. A Synology wildcard certificate needs an acme.sh client and a Let’s Encrypt DNS challenge, not the built-in tool.

The NAS hosts internal names: DSM itself, dashboards, a reverse proxy for a few services behind the firewall. Those names needed a trusted cert with no extra hole in the edge. Cutting a cert per name in DSM meant either exposing those names on 80/443 or living with browser warnings. So we stood up acme.sh as a network infrastructure job.

acme.sh is a shell ACME client. Cloudflare’s DNS API writes the TXT record for the challenge. The synology_dsm deploy hook pushes the finished cert into DSM and restarts the services that use it. No Python runtime, no port 80, no clicking through Certificate Manager on renew day.

Where should the acme.sh client live on a Synology NAS?

Not in /root/.acme.sh. That is the default, and it is a bad place on a Synology: DSM updates have wiped it, and it does not back up with the rest of the admin home. Install acme.sh into a sysadmin home directory and split certs from config.

install-acme.sh
mkdir -p /var/services/homes/sysadmin/acme.sh/acme_certs
mkdir -p /var/services/homes/sysadmin/acme.sh/acme_config

curl https://get.acme.sh | sh -s email=admin@example.com \
  --home /var/services/homes/sysadmin/acme.sh/acme_config \
  --config-home /var/services/homes/sysadmin/acme.sh/acme_config \
  --cert-home /var/services/homes/sysadmin/acme.sh/acme_certs

--home is the scripts. --config-home is account config and logs. --cert-home is the issued certs. The email registers the ACME account so Let’s Encrypt has somewhere to send expiry mail.

How do you test acme.sh --staging without hitting the rate limit?

Run acme.sh --staging first. Production allows five certificates per registered domain per week. A fresh zone and a typo in the DNS plugin will burn that before the pipeline works.

issue-staging.sh
CF_Token="YOUR_CLOUDFLARE_API_TOKEN" \
CF_Email="admin@example.com" \
SYNO_USE_TEMP_ADMIN=1 \
/var/services/homes/sysadmin/acme.sh/acme_config/acme.sh \
  --home /var/services/homes/sysadmin/acme.sh/acme_config \
  --cert-home /var/services/homes/sysadmin/acme.sh/acme_certs \
  --config-home /var/services/homes/sysadmin/acme.sh/acme_config \
  --staging \
  --issue \
  -d '*.int.example.com' \
  --dns dns_cf

--staging hits the untrusted Let’s Encrypt staging directory. --dns dns_cf is the Cloudflare plugin. CF_Token and CF_Email are what the plugin uses to write the TXT record at _acme-challenge.int.example.com. -d '*.int.example.com' is the wildcard. Nothing on this NAS has to listen on port 80.

How do you issue the production wildcard?

Same acme.sh command. Drop --staging and point --server at the production directory.

issue-prod.sh
CF_Token="YOUR_CLOUDFLARE_API_TOKEN" \
CF_Email="admin@example.com" \
SYNO_USE_TEMP_ADMIN=1 \
/var/services/homes/sysadmin/acme.sh/acme_config/acme.sh \
  --home /var/services/homes/sysadmin/acme.sh/acme_config \
  --cert-home /var/services/homes/sysadmin/acme.sh/acme_certs \
  --config-home /var/services/homes/sysadmin/acme.sh/acme_config \
  --server https://acme-v02.api.letsencrypt.org/directory \
  --issue \
  -d '*.int.example.com' \
  --dns dns_cf

Staging is https://acme-staging-v02.api.letsencrypt.org/directory. Production is https://acme-v02.api.letsencrypt.org/directory. Do not mix them. A staging cert will not be trusted in a browser. That is the point of the test.

How do you automate SSL renewal with the synology_dsm deploy hook?

One acme.sh command, root, in Task Scheduler. acme.sh only renews when the cert has fewer than 30 days left, so a daily run is a no-op most mornings. On the morning it matters, --renew plus --deploy-hook synology_dsm installs the new cert and restarts the services that use it.

renew-deploy.sh
CF_Token="YOUR_CLOUDFLARE_API_TOKEN" \
CF_Email="admin@example.com" \
SYNO_USE_TEMP_ADMIN=1 \
/var/services/homes/sysadmin/acme.sh/acme_config/acme.sh \
  --home /var/services/homes/sysadmin/acme.sh/acme_config \
  --cert-home /var/services/homes/sysadmin/acme.sh/acme_certs \
  --config-home /var/services/homes/sysadmin/acme.sh/acme_config \
  --renew \
  --server https://acme-v02.api.letsencrypt.org/directory \
  --deploy \
  --deploy-hook synology_dsm \
  -d '*.int.example.com'

In DSM: Control Panel > Task Scheduler > Create > Scheduled Task > User-defined script. The user has to be root or the DSM deploy fails. Daily at 3:00 AM is fine.

How does SYNO_USE_TEMP_ADMIN work with the acme.sh Synology hook?

SYNO_USE_TEMP_ADMIN=1. The synology_dsm deploy hook cannot log in as a 2FA admin, so it creates a temporary admin, pushes the cert, and deletes that account. It exists for those few seconds of the deploy, not as a standing user.

Create a scoped Cloudflare API token, not a Global API Key. Permission is Zone > DNS > Edit, locked to the one zone. acme.sh writes the token into acme_config/account.conf and sets the file to 600. Back that directory up with the rest of the home share.

Outcome

One wildcard Let’s Encrypt cert covers the internal names on the Synology NAS. Port 80 stays closed. acme.sh renewals run at 3 AM, the synology_dsm hook lands them in DSM, and services pick up the new cert. The last time anyone clicked through DSM Certificate Manager on this NAS was the day we set this up.

Key takeaways