Hi,
I have a working ACME client setup with a wildcard Let's Encrypt certificate for my domain. Also have a working nginx based reverse proxy to three services. Those services are running on a TrueNAS SCALE 25.10.3 (latest patch) system.
While all https access to the services is working fine through nginx with A+ trusted HTTPS (reverse proxy handles upstream stuff on the LAN to TrueNAS) the services on the TrueNAS system still use selfsigned certs from the TrueNAS box.
Now, while not essential (I trust my home lan ;-)) I am trying to get the whole certificate chain proper. Just a hobby thing.
Therefore I made an API key (root) on my TrueNAS and created the automation in the ACME client. Used the websocket (not deprecated one). Filled in all the fields, which are self explanatory. Reran the automations from the commands in OPNsense but the upload errors out.
[Mon May 4 18:02:46 CEST 2026] TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable.
I tried all automation modes (none, ws and wss) but error remains. The API key is really in the appropriate field. The plugin however does not seem to set the value from the field in the environment variable.
I am a little at hand (no ssh) from my phone currently so no CLI attempt possible.
Anybody recognize this? Seems a bug...
It will be fixed on the next version. You can use the deprecated until then. Truenas 26+ deprecates it.
There was an unintended issue with our merge tooling (on a case insensitive file system) that ended up in the file not being renamed correctly although I'm not sure that's the problem here:
https://github.com/opnsense/plugins/commit/251c7a5e93
It was since hotfixed but perhaps it needs a reinstall if you caught the other version:
# opnsense-revert os-acme-client
Could be unrelated, though.
Cheers,
Franco
Quotealthough I'm not sure that's the problem here
This issue is unrelated to the rename hiccup. 😊
Quote> [Mon May 4 18:02:46 CEST 2026] TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable.
I have tested this and was unable to reproduce this issue.
Please try again and provide the full ACME Log and all "AcmeClient" entries from the System Log.
QuoteI have tested this and was unable to reproduce this issue.
Please try again and provide the full ACME Log and all "AcmeClient" entries from the System Log.
I can do this when I have computer access again in a few days.
However, sopex mentions it will be fixed in the next version.... This indicates bug...
Maybe the setenv variable had been set in your case earlier and therefore it works? Is that possible?
Regardless, i'll dig into it in a few days time and help out isolating any issue. Thanks
Quote from: Rene78 on May 05, 2026, 07:16:09 PMHowever, sopex mentions it will be fixed in the next version.... This indicates bug...
I made the truenas websocket addition and it was working, but then there were some complications with the naming conventions that fraenki fixed.
So I jumped the gun, and thought something broke there.
But if Frankie says it's not that, he is correct.
QuoteBut if Frankie says it's not that, he is correct.
Copy all. I'll try and get all the logs on the forum asap.
OK... So, I flicked open my iPad and tried again, as suggested.
Firstly I tested the deprecated API system. That worked as expected when filling in the values and with a new API-key. Used the HTTPS scheme and it exported the certificate as it should. No errors. Ohh, and leaving out the "X-" integer index does break the API and generated an API key error. Tested both, so answered my own question.
ACME log working:
2026-05-05T20:59:25acme.sh [Tue May 5 20:59:25 CEST 2026] Success
2026-05-05T20:59:25acme.sh [Tue May 5 20:59:25 CEST 2026] Reloading TrueNAS web UI
2026-05-05T20:59:25acme.sh [Tue May 5 20:59:25 CEST 2026] Deleting old certificate
2026-05-05T20:59:25acme.sh [Tue May 5 20:59:25 CEST 2026] FTP certificate is not configured or is not the same as TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] Checking if FTP certificate is the same as the TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] S3 certificate is not configured or is not the same as TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] Checking if S3 certificate is the same as the TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] WebDAV certificate is not configured or is not the same as TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] Checking if WebDAV certificate is the same as the TrueNAS web UI
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] Current activate certificate ID: 5
2026-05-05T20:59:24acme.sh [Tue May 5 20:59:24 CEST 2026] Fetching list of installed certificates
2026-05-05T20:59:21acme.sh [Tue May 5 20:59:21 CEST 2026] Uploading new certificate to TrueNAS
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] Getting current active certificate from TrueNAS
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] Detected TrueNAS system version: unknown
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] Detected TrueNAS system os: unknown
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] Getting TrueNAS version
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] TrueNAS system state: "READY".
2026-05-05T20:59:20acme.sh [Tue May 5 20:59:20 CEST 2026] Testing Connection TrueNAS
Knowing that the deprecated API HTTPS scheme works gives confidence in the input fields. Using the same API key, but now with the websocket (ws, wss, none) results in a different error now. The environment variables seem OK, but it is 100% the same API key that works in HTTPS scheme. I cloned the working HTTPS one. And double checked.
The ACME log:
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Error encountered while deploying.
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Error deploying for domain: *.<REDACTED>.nl
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Verify API key.
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL.
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] TrueNAS is not ready.
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Checking TrueNAS health...
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Environment variables: OK
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Checking environment variables...
System log in ACME client:
2026-05-05T21:12:22opnsense AcmeClient: running acme.sh deploy hook failed (acme_truenas_ws)
2026-05-05T21:12:22opnsense AcmeClient: AcmeClient: The shell command returned exit code '1': '/usr/local/sbin/acme.sh --deploy --syslog 6 --log-level 1 --server 'letsencrypt' --home '/var/etc/acme-client/home' --cert-home '/var/etc/acme-client/cert-home/67e6acd371dce3.58753914' --certpath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/cert.pem' --keypath '/var/etc/acme-client/keys/67e6acd371dce3.58753914/private.key' --capath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/chain.pem' --fullchainpath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/fullchain.pem' --domain '*.<REDACTED>.nl' --ecc --deploy-hook truenas_ws --insecure'
2026-05-05T21:12:22opnsense AcmeClient: running automation (acme.sh): TrueNAS-export
2026-05-05T21:12:22opnsense AcmeClient: running automations for certificate: *.<REDACTED>.nl
Yesterday the ACME logs were different doing the same. Does this has something to do with setenv being done once (at the HTTPS scheme that worked) and that the system now has an API key but with older value..? I tested the old scheme first today to check my understanding before retrying the Websocket with new key. So, initialization thing?
AMCE logs yesterday:
2026-05-04T20:48:12acme.sh [Mon May 4 20:48:12 CEST 2026] Error encountered while deploying.
2026-05-04T20:48:12acme.sh [Mon May 4 20:48:12 CEST 2026] Error deploying for domain: *.<REDACTED>.nl
2026-05-04T20:48:12acme.sh [Mon May 4 20:48:12 CEST 2026] TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable.
2026-05-04T20:48:12acme.sh [Mon May 4 20:48:12 CEST 2026] Checking environment variables...
System logs yesterday:
2026-05-04T20:48:12opnsense AcmeClient: running acme.sh deploy hook failed (acme_truenas_ws)
2026-05-04T20:48:12opnsense AcmeClient: AcmeClient: The shell command returned exit code '1': '/usr/local/sbin/acme.sh --deploy --syslog 6 --log-level 1 --server 'letsencrypt' --home '/var/etc/acme-client/home' --cert-home '/var/etc/acme-client/cert-home/67e6acd371dce3.58753914' --certpath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/cert.pem' --keypath '/var/etc/acme-client/keys/67e6acd371dce3.58753914/private.key' --capath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/chain.pem' --fullchainpath '/var/etc/acme-client/certs/67e6acd371dce3.58753914/fullchain.pem' --domain '*.<REDACTED>.nl' --ecc --deploy-hook truenas_ws --insecure'
2026-05-04T20:48:12opnsense AcmeClient: running automation (acme.sh): TrueNAS_cert
2026-05-04T20:48:12opnsense AcmeClient: running automations for certificate: *.<REDACTED>.nl
Quote2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Verify API key.
2026-05-05T21:12:22acme.sh [Tue May 5 21:12:22 CEST 2026] Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL.
If you're seeing this message, it means that os-acme-client is working perfectly fine.
This error message is raised by acme.sh when a communication error with your TrueNAS occured:
https://github.com/acmesh-official/acme.sh/blob/7735cdf3abe84bce8c1e37e7fa46c71e38606262/deploy/truenas_ws.sh#L219
This code checks the "system.ready" TrueNAS API endpoint and seems to receive an error or invalid result.
I can't give you any advice for setting up TrueNAS. Maybe you need to configure something to make the TrueNAS websocket API work.
Hmmm... okay.. wasn't aware that TrueNAS API needed any configuration, but I'll dive into that one next. Thanks! I'll report back when I find something.
If you want to dive even deeper: try to query the TrueNAS API endpoint "system.ready" using `curl` and your API key. The API documentation is available here:
https://www.truenas.com/docs/api/scale_websocket_api.html
It should make the root cause more obvious, but crafting the `curl` command might be a challenge.
Quote from: fraenki on May 06, 2026, 01:42:23 PMIf you want to dive even deeper: try to query the TrueNAS API endpoint "system.ready" using `curl` and your API key. The API documentation is available here:
https://www.truenas.com/docs/api/scale_websocket_api.html
It should make the root cause more obvious, but crafting the `curl` command might be a challenge.
I'll start by fiddling with cli on the TrueNAS box, the api client. See where I end up there
Quote from: fraenki on May 06, 2026, 01:42:23 PMIf you want to dive even deeper: try to query the TrueNAS API endpoint "system.ready" using `curl` and your API key. The API documentation is available here:
https://www.truenas.com/docs/api/scale_websocket_api.html
It should make the root cause more obvious, but crafting the `curl` command might be a challenge.
Hi Fraenki,
I have the same problem as OP and when I copied the command from the logs and tried running it manually from an SSH shell (with the environment variables set) I got the follwing output:
root@router:/ # /usr/local/sbin/acme.sh --deploy --syslog 6 --log-level 1 --server 'letsencrypt' --home '/var/etc/acme-client/home' --cert-home '/var/etc/acme-client/cert-home/689ca6dd3b9044.57803608' --certpath '/var/etc/acme-client/certs/689ca6dd3b9044.57803608/cert.pem' --keypath '/var/etc/acme-client/keys/689ca6dd3b9044.57803608/private.key' --capath '/var/etc/acme-client/certs/689ca6dd3b9044.57803608/chain.pem' --fullchainpath '/var/etc/acme-client/certs/689ca6dd3b9044.57803608/fullchain.pem' --domain 'truenas.mgmt.lofjard.se' --ecc --deploy-hook truenas_ws --insecure
[Thu May 14 14:56:38 CEST 2026] Checking environment variables...
[Thu May 14 14:56:38 CEST 2026] Environment variables: OK
[Thu May 14 14:56:38 CEST 2026] Checking TrueNAS health...
/usr/local/sbin/acme.sh: midclt: not found
[Thu May 14 14:56:38 CEST 2026] TrueNAS is not ready.
[Thu May 14 14:56:38 CEST 2026] Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL.
[Thu May 14 14:56:38 CEST 2026] Verify API key.
[Thu May 14 14:56:38 CEST 2026] Error deploying for domain: truenas.mgmt.lofjard.se
[Thu May 14 14:56:38 CEST 2026] Error encountered while deploying.
A quick "find / | grep midclt" returns nothing. Is my install broken or is there a file missing from the ACME plugin?
https://github.com/truenas/midcli ???
Cheers,
Franco
Quote from: franco on May 18, 2026, 09:02:21 AMhttps://github.com/truenas/midcli ???
Cheers,
Franco
Nope (I found that one as well since it looked like a spelling error initially)
It seems to be a part of this:
https://github.com/truenas/api_client
In either case it looks like it expects TrueNAS as OS, not OPNsense.
Cheers,
Franco
Quote from: ceel on May 14, 2026, 03:10:38 PM[Thu May 14 14:56:38 CEST 2026] Checking TrueNAS health...
/usr/local/sbin/acme.sh: midclt: not found
QuoteIt seems to be a part of this:
https://github.com/truenas/api_client
Thanks for finding this apparently missing API client. I reproduced this missing midclt also from a shell. Not sure why it does not show up in the system logs though. ;-)
Quote from: franco on May 18, 2026, 09:38:40 AMIn either case it looks like it expects TrueNAS as OS, not OPNsense.
Cheers,
Franco
What's in a name... the TrueNAS client apparently called midcli and the one ceel references (https://github.com/truenas/api_client) is midclt. To make it more confusing both the clients seem to be preinstalled on a TrueNAS box according to the GitHub documentation.
Anyway,
- the midcli is the NAS cli interface —> that is preinstalled and can only be used (in my understanding) on the TrueNAS box.
- The midclt is not installed by default, at least not on my TrueNAS scale box (25.10.3.1). It is compatible with TrueNAS SCALE (Debian based) according to the docs both also to run from non-TrueNAS clients. "TrueNAS comes with this client preinstalled, but it is also possible to use the TrueNAS websocket client from a non-TrueNAS host."
Hence, imho the midclt could be used (assumption here, if the code works on FreeBSD...) to complete the deployment task.
Shouldn't the automation "simply" use SSH to execute whatever is necessary on the TrueNAS system, including midclt?
Quote from: Patrick M. Hausen on May 19, 2026, 09:11:40 AMShouldn't the automation "simply" use SSH to execute whatever is necessary on the TrueNAS system, including midclt?
I am not skilled enough to check what the acme client and plugin does on OPNSense (use local midctl OR remote calling through SSH or something else HTTP calls etc.). What I understand is that midctl is/was intended to make calling the TrueNAS API as easy as possible.
Sadly it's just mid.
(Sorry had to make that joke.)
Hi,
Did anyone find a solution to this?
I "fixed" it by using the ACME plugin on the truenas scale box. I am using easydns as provider and decided to go for a script to set the DNS records. after some fiddling I was able to get that working.
#!/bin/sh
# ============================================================
# TrueNAS SCALE ACME Shell Authenticator for easyDNS
#
# Script:
# /mnt/Pool/Scripts/ACME/acmedns.sh
#
#:
#
# TrueNAS-Format:
# acmedns.sh set scale.domain.com _acme-challenge.scale.domain.com TOKEN
# acmedns.sh unset scale.domain.com _acme-challenge.scale.domain.com TOKEN
#
# Fallback-Format:
# acmedns.sh set _acme-challenge.scale.domain.com TOKEN
# acmedns.sh unset _acme-challenge.scale.domain.com TOKEN
# ============================================================
set -eu
LOG_DIR="/mnt/Pool/Scripts/ACME"
LOG_FILE="${LOG_DIR}/acmedns.log"
MAX_LOG_BYTES=$((1024 * 1024))
API_BASE="https://rest.easydns.net"
EASYDNS_DOMAIN="domain.com"
EASYDNS_TTL=300
EASYDNS_TOKEN_FILE="/mnt/Pool/Scripts/ACME/easydns.token"
EASYDNS_KEY_FILE="/mnt/Pool/Scripts/ACME/easydns.key"
PROPAGATION_SLEEP=60
mkdir -p "$LOG_DIR"
rotate_log_if_needed() {
if [ -f "$LOG_FILE" ]; then
size="$(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)"
if [ "$size" -gt "$MAX_LOG_BYTES" ]; then
: > "$LOG_FILE"
fi
fi
}
log() {
echo "[$(date '+%F %T')] $*" >> "$LOG_FILE"
}
fail() {
log "ERROR: $*"
exit 1
}
rotate_log_if_needed
[ -f "$EASYDNS_TOKEN_FILE" ] || fail "Missing EasyDNS token file: $EASYDNS_TOKEN_FILE"
[ -f "$EASYDNS_KEY_FILE" ] || fail "Missing EasyDNS key file: $EASYDNS_KEY_FILE"
EASYDNS_TOKEN="$(tr -d '\r\n' < "$EASYDNS_TOKEN_FILE")"
EASYDNS_KEY="$(tr -d '\r\n' < "$EASYDNS_KEY_FILE")"
[ -n "$EASYDNS_TOKEN" ] || fail "EasyDNS token file is empty"
[ -n "$EASYDNS_KEY" ] || fail "EasyDNS key file is empty"
record_to_host() {
record="$1"
# trailing dot entfernen und lowercase
record="$(printf '%s' "$record" | sed 's/\.$//' | tr '[:upper:]' '[:lower:]')"
case "$record" in
*."$EASYDNS_DOMAIN")
printf '%s\n' "${record%.$EASYDNS_DOMAIN}"
;;
"$EASYDNS_DOMAIN")
printf '%s\n' "@"
;;
*)
fail "Challenge record '$record' is not inside zone '$EASYDNS_DOMAIN'"
;;
esac
}
json_body_for_add() {
host="$1"
token="$2"
python3 - "$host" "$EASYDNS_DOMAIN" "$EASYDNS_TTL" "$token" <<'PY'
import sys, json
host = sys.argv[1]
domain = sys.argv[2]
ttl = int(sys.argv[3])
token = sys.argv[4]
body = {
"host": host,
"domain": domain,
"ttl": ttl,
"prio": 0,
"type": "txt",
"rdata": token,
}
print(json.dumps(body, separators=(",", ":")))
PY
}
api_get_records() {
curl -fsS \
-u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
--connect-timeout 15 \
--max-time 60 \
"${API_BASE}/zones/records/all/${EASYDNS_DOMAIN}?format=json"
}
api_add_txt() {
body="$1"
curl -fsS \
-u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
-X PUT \
--connect-timeout 15 \
--max-time 60 \
-H "Content-Type: application/json" \
-d "$body" \
"${API_BASE}/zones/records/add/${EASYDNS_DOMAIN}/txt?format=json"
}
api_delete_record() {
id="$1"
log "Trying DELETE with confirm body for id=$id"
if curl -fsS \
-u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
-X DELETE \
--connect-timeout 15 \
--max-time 60 \
-H "Content-Type: application/json" \
-d '{"confirm":"DELETE"}' \
"${API_BASE}/zones/records/${EASYDNS_DOMAIN}/${id}?format=json" >> "$LOG_FILE" 2>&1; then
log "DELETE with confirm body succeeded for id=$id"
return 0
fi
log "DELETE with confirm body failed for id=$id, trying fallback DELETE without body"
curl -fsS \
-u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
-X DELETE \
--connect-timeout 15 \
--max-time 60 \
"${API_BASE}/zones/records/${EASYDNS_DOMAIN}/${id}?format=json" >> "$LOG_FILE" 2>&1
log "Fallback DELETE succeeded for id=$id"
}
find_txt_record_ids() {
host="$1"
token="${2:-}"
records_json="$3"
printf '%s' "$records_json" | python3 - "$host" "$token" <<'PY'
import sys, json
host = sys.argv[1].lower()
token = sys.argv[2]
try:
data = json.load(sys.stdin)
except Exception as e:
print(f"JSON_ERROR:{e}", file=sys.stderr)
sys.exit(2)
for r in data.get("data", []):
rtype = str(r.get("type", "")).lower()
rhost = str(r.get("host", "")).lower()
rrdata = r.get("rdata", r.get("rData", ""))
rrdata = str(rrdata).strip()
rrdata_unquoted = rrdata.strip("\"")
if rtype == "txt" and rhost == host:
if not token or rrdata == token or rrdata_unquoted == token:
rid = r.get("id")
if rid is not None:
print(rid)
PY
}
delete_txt_record() {
host="$1"
token="${2:-}"
log "Searching TXT records for host=$host token=${token:-none}"
records_json="$(api_get_records)"
log "easyDNS records fetched"
ids="$(find_txt_record_ids "$host" "$token" "$records_json" || true)"
if [ -z "$ids" ] && [ -n "$token" ]; then
log "No TXT record found with exact token. Searching again by host only."
ids="$(find_txt_record_ids "$host" "" "$records_json" || true)"
fi
if [ -z "$ids" ]; then
log "No matching TXT record found for host=$host"
return 0
fi
echo "$ids" | while IFS= read -r id; do
[ -z "$id" ] && continue
log "Deleting TXT record host=$host id=$id"
api_delete_record "$id"
log "Delete completed for TXT record id=$id"
sleep 2
done
}
set_record() {
challenge_fqdn="$1"
token="$2"
host="$(record_to_host "$challenge_fqdn")"
log "SET requested"
log "Challenge FQDN=$challenge_fqdn"
log "Zone=$EASYDNS_DOMAIN"
log "Host=$host"
delete_txt_record "$host" "$token" || true
body="$(json_body_for_add "$host" "$token")"
log "Adding TXT record host=$host ttl=$EASYDNS_TTL"
api_add_txt "$body" >> "$LOG_FILE" 2>&1
log "TXT record added for host=$host"
log "Waiting ${PROPAGATION_SLEEP}s for DNS propagation"
sleep "$PROPAGATION_SLEEP"
log "SET completed"
}
unset_record() {
challenge_fqdn="$1"
token="${2:-}"
host="$(record_to_host "$challenge_fqdn")"
log "UNSET requested"
log "Challenge FQDN=$challenge_fqdn"
log "Zone=$EASYDNS_DOMAIN"
log "Host=$host"
log "Token=${token:-none}"
delete_txt_record "$host" "$token"
log "UNSET completed"
}
# ------------------------------------------------------------
# Parameter Parsing
# ------------------------------------------------------------
mode="${1:-}"
arg2="${2:-}"
arg3="${3:-}"
arg4="${4:-}"
domain_fqdn=""
challenge_fqdn=""
txt_token=""
log "============================================================"
log "Raw args: mode='${mode:-}' arg2='${arg2:-}' arg3='${arg3:-}' arg4='${arg4:-}'"
case "$mode" in
set)
case "$arg2" in
_acme-challenge*)
# Fallback-Format:
# set challenge token
challenge_fqdn="$arg2"
txt_token="$arg3"
;;
*)
# TrueNAS-Format:
# set domain challenge token
domain_fqdn="$arg2"
challenge_fqdn="$arg3"
txt_token="$arg4"
;;
esac
[ -n "$challenge_fqdn" ] || fail "Missing challenge FQDN argument"
[ -n "$txt_token" ] || fail "Missing TXT token argument"
set_record "$challenge_fqdn" "$txt_token"
;;
unset)
case "$arg2" in
_acme-challenge*)
# Fallback-Format:
# unset challenge token
challenge_fqdn="$arg2"
txt_token="$arg3"
;;
*)
# TrueNAS-Format:
# unset domain challenge token
domain_fqdn="$arg2"
challenge_fqdn="$arg3"
txt_token="$arg4"
;;
esac
[ -n "$challenge_fqdn" ] || fail "Missing challenge FQDN argument"
unset_record "$challenge_fqdn" "$txt_token"
;;
*)
fail "Unknown mode '$mode'. Expected 'set' or 'unset'."
;;
esac
exit 0
and then use this script when requesting the certificate. The only thing that is not working is the automatic cleanup of the DNS recored, therefore I created this script:'
#!/bin/sh
set -eu
LOG_DIR="/mnt/Pool/Scripts/ACME"
LOG_FILE="${LOG_DIR}/cleanup-acme-txt.log"
API_BASE="https://rest.easydns.net"
EASYDNS_DOMAIN="domain.com"
EASYDNS_TOKEN_FILE="/mnt/Pool/Scripts/ACME/easydns.token"
EASYDNS_KEY_FILE="/mnt/Pool/Scripts/ACME/easydns.key"
DRY_RUN=0
if [ "${1:-}" = "--dry-run" ]; then
DRY_RUN=1
fi
mkdir -p "$LOG_DIR"
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG_FILE"
}
fail() {
log "ERROR: $*"
exit 1
}
[ -f "$EASYDNS_TOKEN_FILE" ] || fail "Token file missing: $EASYDNS_TOKEN_FILE"
[ -f "$EASYDNS_KEY_FILE" ] || fail "Key file missing: $EASYDNS_KEY_FILE"
EASYDNS_TOKEN="$(tr -d '\r\n' < "$EASYDNS_TOKEN_FILE")"
EASYDNS_KEY="$(tr -d '\r\n' < "$EASYDNS_KEY_FILE")"
[ -n "$EASYDNS_TOKEN" ] || fail "Token file is empty"
[ -n "$EASYDNS_KEY" ] || fail "Key file is empty"
TMP_RECORDS="$(mktemp)"
TMP_IDS="$(mktemp)"
cleanup_tmp() {
rm -f "$TMP_RECORDS" "$TMP_IDS"
}
trap cleanup_tmp EXIT INT TERM
log "============================================================"
log "Starting ACME TXT cleanup for zone: $EASYDNS_DOMAIN"
if [ "$DRY_RUN" -eq 1 ]; then
log "Mode: DRY-RUN - nothing will be deleted"
else
log "Mode: DELETE - matching records will be deleted"
fi
to run this once a week to clean up the old records. It is not as smart as centralizing the task from opnsense but it does the job.
I ended up setting up ACME in TrueNAS instead.
Did this ever get resolved or anyone find out the actual cause?
My problem is that I did setup the (new) websocket cert push, and I know it worked fine as I swapped over to that cert. Now it needed a renew, and for some reason it failed to push, showing the same symptoms as described here.
I do NOT want to run letsencrypt on the TrueNAS box as well. That's the whole point of having it on the router/firewall.
To be more explicit:
The only normally accessible error in the log is this:
AcmeClient: AcmeClient: The shell command returned exit code '1': '/usr/local/sbin/acme.sh ...When manually running that command that fails, I get the same errors the others posted (TrueNAS is not ready. and all that). to my knowledge, the TrueNAS API also doesn't need (or allow) any configuration. I'm currently still on 25.10.3.1, but .4 seems available.
So what gives?