Skip to content

Instantly share code, notes, and snippets.

@kylefmohr
Last active October 29, 2025 14:49
Show Gist options
  • Select an option

  • Save kylefmohr/9ad8243e6641a9d0568a78cb9ae26ade to your computer and use it in GitHub Desktop.

Select an option

Save kylefmohr/9ad8243e6641a9d0568a78cb9ae26ade to your computer and use it in GitHub Desktop.
Auto-renew Proxmox's Web UI HTTPS certificate using Tailscale and Tailnets
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status.
##
# This script automates renewing the Proxmox web UI TLS certificate
# using Tailscale's built-in HTTPS certificate feature.
# It is recommended to run this script using a cronjob, I'm using
# `0 2 1 */3 * /path/to/my/prox-certs.sh`
# in my crontab to run this every three months (the length of the certificate validity)
# v4: Checks for and installs jq if missing.
##
# Check for jq and install if it's missing
if ! command -v jq &> /dev/null; then
echo "jq could not be found. Installing it now..."
apt-get update
apt-get install -y jq
fi
# Get the node name (e.g., 'MyProxmoxHost1')
NODENAME=$(hostname -s)
if [ -z "$NODENAME" ]; then
echo "Error: Could not determine hostname." >&2
exit 1
fi
# Get the Tailscale tailnet name (e.g., 'marlin-pizza.ts.net')
TAILNET_NAME=$(tailscale status --json | jq -r .CurrentTailnet.MagicDNSSuffix)
if [ -z "$TAILNET_NAME" ]; then
echo "Error: Could not determine Tailnet name. Is Tailscale running?" >&2
exit 1
fi
# Construct the full domain name and define final paths
FQDN="${NODENAME}.${TAILNET_NAME}"
PVE_CERT_FILE="/etc/pve/nodes/${NODENAME}/pveproxy-ssl.pem"
PVE_KEY_FILE="/etc/pve/nodes/${NODENAME}/pveproxy-ssl.key"
# Create a temporary directory to avoid writing directly to pmxcfs
TMP_DIR=$(mktemp -d)
# Set a trap to automatically remove the temporary directory on script exit
trap 'rm -rf -- "$TMP_DIR"' EXIT
echo "Starting Proxmox certificate renewal for ${FQDN}..."
echo "1. Requesting certificate from Tailscale into temporary directory..."
tailscale cert \
--cert-file "${TMP_DIR}/cert.pem" \
--key-file "${TMP_DIR}/key.key" \
"${FQDN}"
echo "2. Copying new certificate and key into place..."
cp "${TMP_DIR}/cert.pem" "${PVE_CERT_FILE}"
cp "${TMP_DIR}/key.key" "${PVE_KEY_FILE}"
echo "3. Setting correct file permissions..."
chown root:www-data "${PVE_KEY_FILE}"
chmod 640 "${PVE_KEY_FILE}"
chown root:www-data "${PVE_CERT_FILE}"
chmod 640 "${PVE_CERT_FILE}"
echo "4. Restarting pveproxy service to apply the new certificate..."
systemctl restart pveproxy.service
echo "Success! The Proxmox certificate for ${FQDN} has been renewed."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment