Tailscale certificate 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 certificate directory on the host

Create a dataset or directory on your pool:

mkdir -p /mnt/<pool>/Applications/tailscale-certs
chmod 700 /mnt/<pool>/Applications/tailscale-certs

Step 2 – Bind-mount it into the Tailscale container

Your Tailscale container must mount the host directory to /certs. This can be done by editing the Tailscale App and adding a Host Path.

Conceptually:

Host path:      /mnt/<pool>/Applications/tailscale-certs
Container path: /certs

This is required so the TrueNAS host can read the files generated by tailscale cert.


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"

# Cron-safe PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Log from inside the script (cron may discard output)
mkdir -p "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
exec >>"$LOG_FILE" 2>&1
echo "----- $(date -Is) starting Tailscale cert import -----"

# Dependency checks
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; }

# Ensure container is running
docker ps --format '{{.Names}}' | grep -qx "$CONTAINER_NAME" || {
  echo "ERROR: container not running: $CONTAINER_NAME"
  exit 2
}

# Ensure /certs mount exists
docker exec "$CONTAINER_NAME" sh -lc 'test -d /certs' || {
  echo "ERROR: /certs not mounted in container"
  exit 2
}

# Request or renew certificate
docker exec "$CONTAINER_NAME" sh -lc \
  "tailscale cert --cert-file /certs/ts.crt --key-file /certs/ts.key \"$TS_HOSTNAME\""

# Verify files on host
[[ -s "$CRT" && -s "$KEY" ]] || {
  echo "ERROR: certificate files missing on host"
  exit 2
}

# Import into TrueNAS certificate store
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

# Look up certificate ID by name (robust across TrueNAS versions)
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
}

# Apply certificate to Web UI and restart UI
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 the script executable

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

Step 5 – Run once manually

/usr/bin/bash /mnt/<pool>/scripts/import_tailscale_cert.sh

A short Web UI disconnect is expected.


Step 6 – Verify in the UI

  • System Settings → Certificates

  • System Settings → General → GUI → Web Interface HTTPS Certificate

Confirm the new certificate is selected.


Step 7 – Create the cron job

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

Command

/usr/bin/bash /mnt/<pool>/scripts/import_tailscale_cert.sh

You can find the script on my Github repository: