Simple tool to manage ACME Cert (Only Supported DNS-01).
- Support multiple DNS Providers based on CertMagic
- Support custom obtain hook script
- Automatically renew certificates and execute hook scripts
- Support ECC certificate (KeyType can be set)
- Support multiple CA(Let's Encrypt/ZeroSSL)
- Optional DNS providers at compile time (can be used to reduce file size)
- No other dependencies except libc (support muslc)
- Optional Synology DSM package with a native wizard UI and automatic certificate deployment to DSM
~ ❯❯❯ dnsacme --help
Simple tool to manage ACME Cert (Only Supported DNS-01)
Usage:
dnsacme [flags]
Examples:
dnsacme --domain='*.example.com' --email='your.example.com' --dns=cloudflare --dns-config=CLOUDFLARE_API_TOKEN=xxxxxxxxxxxxxx
Flags:
-d, --domain strings ACME cert domains
-m, --email string ACME email
--storage-dir string ACME cert status storage directory (default "/root/.config/certmagic")
-t, --key-type string ACME cert key type (default "P384")
-p, --dns string ACME DNS provider
--dns-config stringToString ACME DNS provider config map (default [])
--zerossl Obtain cert with ZeroSSL CA (default true)
--obtaining-hook string CertMagic obtaining hook command
--obtained-hook string CertMagic obtained hook command
--failed-hook string CertMagic obtain failed hook command
-l, --list-providers List supported DNS providers
--eab-keyid string ACME Custom EABKeyID
--eab-mackey string ACME Custom EABHMACKey
-h, --help help for dnsacme
-v, --version version for dnsacmednsacme is also available as a native package for Synology DSM 7.0 and later. The package adds a wizard to the DSM main menu, imports certificates through the DSM WebAPI, and runs an unprivileged background daemon for automatic renewal.
- Configure the certificate, DNS provider, and DSM deployment from a native ExtJS wizard.
- Optionally validate a certificate configuration against the Let's Encrypt staging CA without deploying it.
- Import the first certificate into DSM, optionally create it or set it as the DSM default, then re-import future renewals automatically.
- Keep production and staging certificates in separate storage directories.
- Preserve package configuration, certificate storage, and logs across package upgrades. The uninstall wizard also keeps them by default and removes them only when the user explicitly selects the delete option.
Build the package (produces one SPK per architecture):
task synology
# build/dnsacme-synology-amd64.spk x86_64
# build/dnsacme-synology-arm64.spk aarch64task synology is the lightweight first-party builder and remains the source of
the SPKs uploaded by the repository release workflow.
The first-party build intentionally produces only the common amd64 and arm64
SPKs. The SynoCommunity recipe can build additional packages from source for
Go-supported 32-bit architectures. Check that the Synology-tagged source remains
portable to 386, ARMv5, ARMv7, amd64 with GOAMD64=v1, and arm64 with:
task synology-arch-checkThis check uses temporary outputs and does not add files to build.
To reproduce a SynoCommunity package with its official build environment, point
the optional task at an external spksrc checkout that contains spk/dnsacme:
SPKSRC_DIR=~/github/spksrc task synology-spksrc -- arch-x64-7.2This command requires Docker, builds the DNSACME version declared by that
checkout's recipe, and writes the result under $SPKSRC_DIR/packages. Set
SPKSRC_IMAGE to override the default SynoCommunity container image. This
reproduction task is not part of release-build and does not replace the
first-party release packaging flow.
Install the SPK for your NAS architecture through Package Center > Manual Install or over SSH:
sudo /usr/syno/bin/synopkg install dnsacme-synology-amd64.spkOpen DNSACME from the DSM main menu after installation. The normal setup flow is:
- Enter the certificate domain and ACME account email.
- Select a DNS provider and enter its credentials.
- Configure the local DSM account and certificate import options.
- Optionally run Test Run. This requests a fresh staging certificate and verifies DSM login, but does not import the certificate. After a successful test, wait at least 10 minutes before applying so DNS caches can discard the staging challenge.
- Run Apply whenever you are ready. This requests the selected production certificate and imports it into DSM. You may apply directly without a staging test, after acknowledging that a production validation failure can count against CA rate limits.
Certificate deployment follows the same approach as the acme.sh Synology deploy hook: DNSACME signs in to the local DSM WebAPI and asks DSM to import and assign the certificate. DSM restricts these API operations to administrators, so an administrator account is required. The alternative would be editing DSM's certificate files directly, which requires root access and can damage DSM certificate data if a path, permission, or file is changed incorrectly. DNSACME therefore keeps its daemon unprivileged and uses the DSM WebAPI instead of modifying certificate files on disk.
- acme.sh: DSM WebAPI login, certificate lookup and administrator permission check, and certificate import.
- DNSACME: DSM WebAPI login, exact certificate lookup, and certificate import.
The standalone SPK uses the same sc-dnsacme:synocommunity service identity as the
SynoCommunity package. Older standalone releases used a different account, so retained
configuration or certificate files may remain unreadable after switching between an old
standalone package and a SynoCommunity package. DNSACME does not request root package
hooks to modify these files automatically because DSM warns about and may reject such
packages.
If the package log reports permission denied after an upgrade, connect to DSM over SSH
with an administrator account. First verify that these commands resolve only to the
DNSACME package directories under @appdata, @appconf, and @apphome:
readlink -f /var/packages/dnsacme/var
readlink -f /var/packages/dnsacme/etc
readlink -f /var/packages/dnsacme/homeAfter checking the paths, repair their ownership and restart the package:
sudo chown -hR -P sc-dnsacme:synocommunity \
"$(readlink -f /var/packages/dnsacme/var)" \
"$(readlink -f /var/packages/dnsacme/etc)" \
"$(readlink -f /var/packages/dnsacme/home)"
sudo /usr/syno/bin/synopkg restart dnsacmeThe renewal daemon remains idle until Apply succeeds for the current configuration. Changing the domain, DNS credentials, DSM deployment target, or CA mode invalidates the previous Test and Apply results. Testing remains optional, while a successful production Apply is always required before automatic renewal starts for the changed configuration.
The package service runs dnsacme synology daemon as a foreground process under
DSM's package service manager. Its built-in help is available with:
/var/packages/dnsacme/target/bin/dnsacme synology --help
/var/packages/dnsacme/target/bin/dnsacme synology daemon --help- DSM version: 7.0 or later.
- Architectures:
x86_64(amd64, GOAMD64 v1) andaarch64(arm64). - Runtime user: the DSM package account, not root.
- Configuration:
/var/packages/dnsacme/etc/config.yamlwith mode0600. - Certificate and log data:
/var/packages/dnsacme/var. - Project link: github.com/mritd/dnsacme.
The release task requires a vMAJOR.MINOR.PATCH semantic version tag. It builds every
Linux binary and Synology SPK, synchronizes the SPK version with the tag, writes
build/SHA256SUMS, tags the current commit, pushes the tag, creates the GitHub
Release, and uploads every file from build:
task release -- v1.2.3By default the latest commit message becomes the release notes. Automated callers can
provide AI-generated notes with --notes-file, RELEASE_NOTES_FILE, or RELEASE_NOTES:
task release -- v1.2.3 --notes-file /tmp/release.mdThe GitHub Release title defaults to the tag itself, such as v1.2.3.
Regular builds exclude Synology DSM support. Enable it explicitly when building a DSM-capable binary:
go build -tags synologytask synology enables this tag automatically when producing SPK packages.
Currently dnsacme supports 8 DNS providers (theoretically more, and some have not been added yet),
the providers supported by the --dns option are defined in internal/provider/provider.go:
const (
AliDNS = "alidns"
Azure = "azure"
Cloudflare = "cloudflare"
DuckDNS = "duckdns"
Gandi = "gandi"
GoDaddy = "godaddy"
HuaweiCloud = "huaweicloud"
TencentCloud = "tencentcloud"
)For each DNS provider has different configuration, the --dns-config option can be specified multiple times:
dnsacme --dns alidns --dns-config=ALIDNS_ACCKEYID=xxxxxx --dns-config=ALIDNS_ACCKEYSECRET=xxxxxx ...The configuration keys for each DNS provider are defined in internal/provider/provider.go:
const (
AliDNSAccessKeyID = "ALIDNS_ACCKEYID"
AliDNSAccessKeySecret = "ALIDNS_ACCKEYSECRET"
AliDNSRegionID = "ALIDNS_REGIONID"
AzureTenantID = "AZURE_TENANTID"
AzureClientID = "AZURE_CLIENTID"
AzureClientSecret = "AZURE_CLIENTSECRET"
AzureSubscriptionID = "AZURE_SUBSCRIPTIONID"
AzureResourceGroupName = "AZURE_RESOURCEGROUPNAME"
GandiAPIToken = "GANDI_API_TOKEN"
CloudflareAPIToken = "CLOUDFLARE_API_TOKEN"
GoDaddyAPIToken = "GODADDY_API_TOKEN"
DuckDNSAPIToken = "DUCKDNS_API_TOKEN"
DuckDNSOverrideDomain = "DUCKDNS_OVERRIDE_DOMAIN"
HuaweiCloudAccessKeyID = "HUAWEICLOUD_ACCKEYID"
HuaweiCloudAccessKeySecret = "HUAWEICLOUD_ACCKEYSECRET"
HuaweiCloudRegionID = "HUAWEICLOUD_REGIONID"
TencentCloudAccessKeyID = "TENCENTCLOUD_ACCKEYID"
TencentCloudAccessKeySecret = "TENCENTCLOUD_ACCKEYSECRET"
)Currently, I don't use all DNS providers, so the configuration for some DNS providers is not verified in the code; ** for example, some parameters are required, but you don't set them, then an error in the CertMagic library will be returned. **
cert_obtaining(--obtaining-hook) A certificate is about to be obtainedrenewal: Whether this is a renewalidentifier: The name on the certificateforced: Whether renewal is being forced (if renewal)remaining: Time left on the certificate (if renewal)issuer: The previous or current issuer
cert_obtained(--obtained-hook) A certificate was successfully obtainedrenewal: Whether this is a renewalidentifier: The name on the certificateremaining: Time left on the certificate (if renewal)issuer: The previous or current issuerstorage_key: The path to the cert resources within storage
cert_failed(--failed-hook) An attempt to obtain a certificate failedrenewal: Whether this is a renewalidentifier: The name on the certificateremaining: Time left on the certificate (if renewal)issuer: The previous or current issuerstorage_key: The path to the cert resources within storageerror: The (final) error message
When CertMagic returns the target Events, the corresponding hook command will be executed, and you can write scripts to handle the corresponding events.
When the hook is executing, you can get the domain name from the environment through the ACME_IDENTIFIER variable;
When --obtained-hook is executing, you can also get the absolute path of the certificate and key through ACME_CERT_PATH and the ACME_KEY_PATH variable.
--obtained-hook will be executed after each successful startup.
Other DNS providers can be deleted by specifying the DNS provider at compile time, which will reduce the file size:
# Only include godaddy and cloudflare DNS providers
go build -trimpath -ldflags '-w -s' -tags=slim,godaddy,cloudflareSome users may need to use environment variables to define configuration, for example in the dcoker container.
dnsacme uses environment variables prefixed with ACME_, which are defined as follows:
| ENV KEY | FLAG | Example |
|---|---|---|
ACME_DOMAIN |
--domain |
a.example.com b.example.com |
ACME_STORAGE_DIR |
--storage-dir |
/tpm/acme |
ACME_KEY_TYPE |
--key-type |
rsa8192 |
ACME_DNS_PROVIDER |
--dns |
alidns |
ACME_DNS_CONFIG |
--dns-config |
{"ALIDNS_ACCKEYID": "xxxxx", "ALIDNS_ACCKEYSECRET": "xxxxx"} |
ACME_ZEROSSL |
--zerossl |
true |
ACME_OBTAINING_HOOK |
--obtaining-hook |
/opt/scripts/acme-obtaining-hook.sh |
ACME_OBTAINED_HOOK |
--obtained-hook |
/opt/scripts/acme-obtained-hook.sh |
ACME_FAILED_HOOK |
--failed-hook |
/opt/scripts/acme-failed-hook.sh |
DNSACME is licensed under the Apache License 2.0. See NOTICE for attribution information and TRADEMARKS.md for the project name and logo policy.