Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

226 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dnsacme

English | 简体中文

Simple tool to manage ACME Cert (Only Supported DNS-01).

Screenshots

Details 02-certificate 03-dns-provider 04-auto-update 05-validate-apply 01-running

Features

  • 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

Usage

~ ❯❯❯ 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 dnsacme

Synology DSM Package

dnsacme 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   aarch64

task 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-check

This 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.2

This 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.spk

Open DNSACME from the DSM main menu after installation. The normal setup flow is:

  1. Enter the certificate domain and ACME account email.
  2. Select a DNS provider and enter its credentials.
  3. Configure the local DSM account and certificate import options.
  4. 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.
  5. 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.

Why a DSM administrator password is required

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.

Audit references

Repairing permissions after switching package sources

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/home

After 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 dnsacme

The 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

Advanced options

Package details

  • DSM version: 7.0 or later.
  • Architectures: x86_64 (amd64, GOAMD64 v1) and aarch64 (arm64).
  • Runtime user: the DSM package account, not root.
  • Configuration: /var/packages/dnsacme/etc/config.yaml with mode 0600.
  • Certificate and log data: /var/packages/dnsacme/var.
  • Project link: github.com/mritd/dnsacme.

Publishing a release

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.3

By 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.md

The 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 synology

task synology enables this tag automatically when producing SPK packages.

DNS Config

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. **

Hook Command

  • cert_obtaining(--obtaining-hook) A certificate is about to be obtained
    • renewal: Whether this is a renewal
    • identifier: The name on the certificate
    • forced: 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 obtained
    • renewal: Whether this is a renewal
    • identifier: The name on the certificate
    • remaining: Time left on the certificate (if renewal)
    • issuer: The previous or current issuer
    • storage_key: The path to the cert resources within storage
  • cert_failed(--failed-hook) An attempt to obtain a certificate failed
    • renewal: Whether this is a renewal
    • identifier: The name on the certificate
    • remaining: Time left on the certificate (if renewal)
    • issuer: The previous or current issuer
    • storage_key: The path to the cert resources within storage
    • error: 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.

⚠️Note: You need to ensure that all hook scripts can be executed repeatedly (idempotent), because they may be called multiple times. For example, --obtained-hook will be executed after each successful startup.

Reduced size

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,cloudflare

ENV Config

Some 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

License

DNSACME is licensed under the Apache License 2.0. See NOTICE for attribution information and TRADEMARKS.md for the project name and logo policy.

About

Simple tool to manage ACME Cert(Only Supported DNS-01)

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages