bg-tutorials

How to Install an ACME SSL Certificate on TrueNAS

TrueNAS has an ACME client built in, but it cannot authenticate to a certificate authority that requires External Account Binding, and that is what commercial CAs require. So the practical route is to issue the certificate with acme.sh on a machine you already run, then push it into TrueNAS over the API on every renewal. This guide covers that flow end to end, including which of acme.sh’s two TrueNAS deployment hooks to pick and why the answer is about to change.

Getting the automation right matters more each year. Under CA/Browser Forum ballot SC-081v3, publicly trusted TLS certificates have been capped at 200 days since March 15, 2026, dropping to 100 days on March 15, 2027 and to 47 days on March 15, 2029. A manual re-import that was an annual chore becomes a monthly one.

Why the certificate has to be issued outside TrueNAS

It is worth being precise about this, because the usual explanation is wrong and the wrong version will send you looking for the wrong workaround.

TrueNAS is not locked to Let’s Encrypt. Its ACME registration takes the directory URL as a parameter you supply, fetches whatever directory you point it at, and registers there. What it does not implement is External Account Binding, the mechanism from RFC 8555 section 7.3.4 that ties an ACME account to an account you already hold with a commercial CA. TrueNAS creates the account with nothing but a terms-of-service agreement, so there is nowhere to put a key identifier and an HMAC key.

The practical rule that follows:

  • If your CA requires EAB, which covers the commercial authorities, the built-in client cannot be used and you need the external flow on this page.
  • If your CA does not require EAB, the built-in client is a perfectly good option and needs no external machine at all. Add a DNS authenticator under Credentials > Certificates and create the certificate there. TrueNAS ships authenticators for Cloudflare, Route 53, OVH and DigitalOcean, plus a shell authenticator that runs a script of your own for any other provider.

What you will need

  • A supported TrueNAS version. The current recommendation is 25.10 Goldeye, with 25.04 Fangtooth still widely deployed and in maintenance. TrueNAS CORE is no longer under active development, so 13.x is a legacy platform: the steps below still apply to it, but plan a migration rather than a new deployment.
  • A host to run acme.sh on, any Linux, BSD or macOS machine that stays up and can reach both your CA and the NAS. It does not need to be reachable from the internet.
  • A domain name with a DNS record for the NAS, such as nas.example.com. It does not have to resolve to a public address, because DNS validation never connects to the NAS.
  • Your CA’s ACME directory URL, EAB Key ID and EAB HMAC Key, generated in your CA account portal.
  • API access to TrueNAS, covered in Step 4.

Step 1: Install acme.sh on the external host

curl https://get.acme.sh | sh -s [email protected]
source ~/.bashrc
acme.sh --version

The installer puts the client in your home directory and adds a cron entry that checks daily for certificates due for renewal. That cron job is what makes the rest of this unattended, so install acme.sh as a user that will keep existing rather than as a throwaway account.

Step 2: Register the ACME account with EAB

acme.sh --register-account \
  --server https://acme.yourca.example/v2/DV \
  --eab-kid "YOUR_EAB_KEY_ID" \
  --eab-hmac-key "YOUR_EAB_HMAC_KEY" \
  --accountemail "[email protected]"

You run this once per CA. Pass --server on every command from here on: acme.sh has defaulted to ZeroSSL since version 3.0, so omitting it quietly sends the request to the wrong authority. If registration fails complaining that the HMAC key cannot be base64-decoded, the key picked up a stray character on its way from the CA portal.

Step 3: Issue the certificate with DNS validation

Use DNS-01. A NAS normally sits behind NAT with no inbound port 80, and DNS validation never touches the box: the CA only reads a TXT record at _acme-challenge.nas.example.com, so where the NAS actually lives is irrelevant. It is also the only challenge type that can produce a wildcard.

Give acme.sh an API credential for your DNS provider so it can publish and remove the record itself. The example uses Cloudflare; acme.sh ships integrations for most providers, each with its own variables.

export CF_Token="your_cloudflare_api_token"
acme.sh --issue --dns dns_cf \
  -d nas.example.com \
  --server https://acme.yourca.example/v2/DV

Do not use manual DNS mode here, even though it looks simpler. acme.sh refuses to renew a certificate validated that way and says so in its own error text: the manual mode cannot renew automatically and you have to issue it again by hand. On a certificate that now lives 200 days and will soon live fewer, choosing manual mode means signing up to repeat this by hand for as long as the NAS exists, which defeats the entire point of the exercise. If your DNS really has no API, the better answer is a CNAME from _acme-challenge.nas.example.com to a zone that does, which acme.sh supports as alias mode.

Once issuance succeeds, the files are in ~/.acme.sh/nas.example.com/: fullchain.cer holds the server certificate plus the intermediate, nas.example.com.key is the private key, and ca.cer is the chain on its own. You do not need to copy any of them anywhere; the next step does that for you.

Step 4: Deploy into TrueNAS with acme.sh’s own hook

acme.sh ships two TrueNAS deployment hooks, and picking between them is the one real decision in this guide.

  • truenas talks to the TrueNAS REST API with an ordinary HTTPS request and a bearer token. It needs nothing installed beyond acme.sh itself, so it works from any external host, which is what this guide assumes.
  • truenas_ws talks to the newer JSON-RPC over WebSocket API. It calls the midclt command and imports the truenas_api_client Python module, both of which ship with TrueNAS rather than with a general-purpose Linux distribution, and the module is not published on PyPI. So it is straightforward on the NAS itself and awkward on a separate machine.

Use truenas today, with one thing written in your calendar: the TrueNAS REST API was deprecated in 25.04, raises deprecation alerts from 25.10.1 onward, and is removed in TrueNAS 26. When you upgrade to 26, this hook stops working and the deployment has to move to the WebSocket API. That is not a reason to avoid it now, but it is a reason to know it is coming.

First create the API key. In the TrueNAS interface, go to the API keys page at /ui/apikeys on your NAS and add a key. Modern TrueNAS ties API keys to a user account, so create a dedicated service account with only the access this needs rather than reusing an administrator. Copy the key when it is shown, because it is not displayed again.

Then deploy:

export DEPLOY_TRUENAS_APIKEY="your_truenas_api_key"
export DEPLOY_TRUENAS_HOSTNAME="nas.example.com"
export DEPLOY_TRUENAS_SCHEME="https"
acme.sh --deploy -d nas.example.com --deploy-hook truenas

Only the API key is required. The hostname defaults to localhost and the scheme to http, so set both explicitly when the NAS is anywhere other than the machine you are typing on.

What the hook does, so you can recognise its work in the interface: it checks the system state, imports the certificate with the private key as a new imported certificate, reads back the list of certificates the web interface can use, and sets the new one as the active web interface certificate. The assignment is included, so there is no separate step to make the certificate live.

acme.sh stores the hook against the domain, so from now on every successful renewal runs it again automatically. There is no scheduled task to write and nothing to copy by hand.

Step 5: Verify, and assign it to anything else

In the TrueNAS interface, go to Credentials > Certificates. The new certificate appears in the Certificates widget, alongside Certificate Signing Requests and ACME DNS-Authenticators. Check the name and the expiry date against what you just issued.

The web interface is handled by the hook. Anything else that presents TLS is configured in its own place, not centrally, so set those once and they will follow the certificate as it renews. Then confirm what the NAS actually serves, from another machine:

openssl s_client -connect nas.example.com:443 -servername nas.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

If the NAS has a public name, the SSL Checker also reports whether the intermediate certificate is being served with the leaf, which is the usual cause of a certificate that works in one client and not another.

To rehearse the renewal path rather than discovering it months later, force one and watch the hook run:

acme.sh --renew -d nas.example.com --force

Certificate authorities apply rate limits, so use --force for a single test rather than in a loop. A new certificate should appear in Credentials > Certificates and become the active one without you touching the interface.

When something does not work

  • Registration is rejected. Check the EAB key identifier and HMAC key for whitespace, confirm you have not re-encoded a value that was already base64url, and check that --server points at your CA rather than the default.
  • The TXT record never validates. Confirm the DNS API credential has permission to write records in that zone, then check the record is publicly visible before blaming acme.sh.
  • The deployment fails to authenticate. Re-create the API key. Keys created through the API on older versions with a method allow-list are revoked on upgrade rather than migrated, so an old key can stop working after a TrueNAS update even though nothing else changed.
  • Deployment worked, but the interface still shows the old certificate. Reload the page and check the certificate list; the hook sets the active certificate as its last action, so a failure part-way through leaves the new certificate imported but not selected.
  • It worked for months, then stopped after an upgrade. Check whether the NAS is now on TrueNAS 26, where the REST API is gone.
  • You need more detail. Add --debug to the acme.sh command to see the exchange with both the CA and the NAS.

For error strings that come from the ACME protocol rather than from acme.sh or TrueNAS, such as badNonce, unauthorized or a CAA record refusing issuance, see our guide to fixing ACME SSL certificate errors.

Frequently Asked Questions

Can I use the built-in TrueNAS ACME client with a commercial CA?

Only if that CA does not require External Account Binding. The common claim that TrueNAS supports Let’s Encrypt and nothing else is not accurate: the ACME directory URL is a field you fill in, so any ACME authority can be pointed at. The real limitation is that TrueNAS registers the account with only a terms-of-service agreement and has no field for an EAB key identifier or HMAC key, and commercial CAs require exactly those. That is why the certificate is issued externally here.

Should I use the truenas or the truenas_ws deploy hook?

truenas if acme.sh runs on a separate machine, because it needs only an HTTPS request and a bearer token. truenas_ws uses the newer WebSocket API but depends on midclt and the truenas_api_client Python module, which ship with TrueNAS and are not on PyPI, so it is much easier to run on the NAS itself. Bear in mind that the REST API behind the first hook was deprecated in 25.04 and is removed in TrueNAS 26, so this choice has a shelf life.

Does any of this still work on TrueNAS CORE?

The external issuance and the REST deployment both work on CORE 13.x, and the interface paths differ only in wording. The larger point is that CORE is no longer under active development, so if you are setting this up now on a CORE system, treat it as a stopgap and plan the migration to a current TrueNAS release rather than building further automation on it.

Can one certificate cover the web interface and other services?

Yes. Once the certificate is in Credentials > Certificates it can be selected by the web interface and by any service that presents TLS, and you only need separate certificates if those services answer to different host names. Each service keeps its own selection, so set them once; they follow the certificate through renewals rather than needing to be reassigned.

My NAS is behind CGNAT or double NAT. Can I still use ACME?

Yes, with DNS-01, which is what this guide uses throughout. HTTP-01 would need the CA to reach the NAS on port 80, which CGNAT rules out. DNS validation only requires a TXT record at _acme-challenge under your domain, so the CA never connects to the NAS at all and its address is irrelevant.

What happens if the certificate renews but never reaches TrueNAS?

TrueNAS keeps serving the last certificate it was given until something replaces it, so the renewed files sit on the external host and the NAS drifts towards an expiry warning. With the deploy hook configured this cannot happen quietly, because acme.sh runs the hook as part of the renewal and reports a failure if it does not succeed. That is the argument for using the hook rather than a reminder to re-import by hand.

Can I use a wildcard certificate?

Yes, and TrueNAS does not treat it differently from a single-name certificate as long as the key and certificate match. Issue it with DNS-01, since no CA validates a wildcard over HTTP, and deploy it the same way. Be deliberate about where else that key ends up, because a wildcard covers every subdomain it names.

For more on the protocol behind all of this, see what the ACME protocol is and our ACME SSL certificates page. To install a certificate on a NAS by hand instead, see our guide to installing an SSL certificate on a Synology NAS.

Save 10% on SSL Certificates when ordering from SSL Dragon today!

Fast issuance, strong encryption, 99.99% browser trust, dedicated support, and 25-day money-back guarantee. Coupon code: SAVE10

A detailed image of a dragon in flight
Written by

I've been writing for SSL Dragon for over 10 years, focusing entirely on SSL certificates and digital security. My job is to take complex cybersecurity topics and strip away the jargon, making sure you get the clear, practical information you need to keep your website safe.