Tailscale certificate renewal automation on TrueNAS (AI generated script)

I would like to share an AI generated script that I successfully used to automate my TrueNAS certificates with Tailscale.

This guide shows how to automatically use a Tailscale HTTPS certificate for the TrueNAS SCALE Web UI, when Tailscale runs inside a Docker container.


Overview

What this does

  1. Runs tailscale cert inside a Docker container
  2. Writes the cert/key to a host bind-mount
  3. Imports the cert into TrueNAS
  4. Applies it to the Web UI
  5. Restarts the UI
  6. Runs automatically via cron

Requirements

  • TrueNAS SCALE
  • Docker
  • A running Tailscale container (tailscaled)
  • A host directory bind-mounted into the container at /certs

Step 1 – Create a cert directory on the host

Create a dataset or folder on your pool (example):

mkdir -p /mnt//Applications/tailscale-certs
chmod 700 /mnt//Applications/tailscale-certs

Step 2 – Bind-mount it into the Tailscale container

Your Tailscale container must mount the host directory to /certs.

Example (conceptually):

Host path: /mnt//Applications/tailscale-certs
Container: /certs

This is required for tailscale cert to write files that TrueNAS can read.

Step 3 – Create the automation script (generic)

Save this as:




/mnt/<pool>/scripts/import_tailscale_cert.sh

Script:

#!/bin/bash
set -euo pipefail

=========================

USER CONFIG (REQUIRED)

=========================

CONTAINER_NAME=“TAILSCALE_CONTAINER_NAME
TS_HOSTNAME=“TAILSCALE_DNS_NAME
HOST_CERT_DIR=“HOST_CERT_DIR
LOG_FILE=“LOG_FILE
TRUENAS_CERT_NAME=“TRUENAS_CERT_NAME

=========================

CRT=“${HOST_CERT_DIR}/ts.crt”
KEY=“${HOST_CERT_DIR}/ts.key”

export PATH=“/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”

mkdir -p “$(dirname “$LOG_FILE”)”
touch “$LOG_FILE”
exec >>“$LOG_FILE” 2>&1
echo “—– $(date -Is) starting Tailscale cert import —–”

command -v docker >/dev/null || { echo “ERROR: docker not found”; exit 2; }
command -v jq >/dev/null || { echo “ERROR: jq not found”; exit 2; }
command -v midclt >/dev/null || { echo “ERROR: midclt not found”; exit 2; }

docker ps –format ‘{{.Names}}’ | grep -qx “$CONTAINER_NAME” || {
echo “ERROR: container not running: $CONTAINER_NAME”
exit 2
}

docker exec “$CONTAINER_NAME” sh -lc ‘test -d /certs’ || {
echo “ERROR: /certs not mounted in container”
exit 2
}

docker exec “$CONTAINER_NAME” sh -lc
“tailscale cert –cert-file /certs/ts.crt –key-file /certs/ts.key “$TS_HOSTNAME””

[[ -s “$CRT” && -s “$KEY” ]] || {
echo “ERROR: certificate files missing”
exit 2
}

midclt call certificate.create “$(jq -n
–arg n “$TRUENAS_CERT_NAME”
–rawfile c “$CRT”
–rawfile k “$KEY”
‘{name:$n, create_type:“CERTIFICATE_CREATE_IMPORTED”, certificate:$c, privatekey:$k}’)” >/dev/null || true

CERT_ID=“$(midclt call certificate.query | jq -r
–arg n “$TRUENAS_CERT_NAME” ‘. | select(.name==$n) | .id’ | tail -n 1)”

[[ -n “$CERT_ID” ]] || {
echo “ERROR: failed to locate imported certificate”
exit 2
}

midclt call system.general.update “$(jq -n –argjson id “$CERT_ID”
‘{ui_certificate:$id, ui_restart_delay:1}’)” >/dev/null
midclt call system.general.ui_restart >/dev/null

echo “SUCCESS: Web UI certificate updated”

Step 4 – Make it executable

chmod 700 /mnt//scripts/import_tailscale_cert.sh

Step 5 – Run once manually

/usr/bin/bash /mnt//scripts/import_tailscale_cert.sh

You will briefly disconnect from the Web UI — this is expected.

Step 6 – Verify certificate in UI

Go to:

System Settings → Certificates

Confirm the new certificate exists and uses your Tailscale hostname.

Also check:

System Settings → General → GUI
Web Interface HTTPS Certificate

Step 7 – Create the cron job

TrueNAS UI → System Settings → Advanced → Cron Jobs → Add

/usr/bin/bash /mnt//scripts/import_tailscale_cert.sh

You can find the script on my Github repository:

https://github.com/chrislongros/truenas-tailscale-cert-automation


Leave a comment

Discover more from /root

Subscribe now to keep reading and get access to the full archive.

Continue reading