#!/usr/bin/env bash # # regenerate-epicnabbo-chain.sh # # Builds a complete TLS chain (leaf + Let's Encrypt intermediate) for # epicnabbo.nl and writes it next to the Traefik dynamic config so the # origin presents a full chain to Cloudflare. # # Why: Traefik's ACME resolver stored the leaf certificate in # /letsencrypt/acme.json without the issuing intermediate. When Cloudflare # talks to the origin in "Full (strict)" mode it cannot build the chain and # returns HTTP 525 (SSL handshake failed), which broke every asset on the # site (JS/CSS chunks, the Nitro client, etc.). Serving the full chain from # a file-based certificate fixes the handshake. # # Usage (run on the host as root): # ./infra/traefik/regenerate-epicnabbo-chain.sh # # The generated files (epicnabbo-fullchain.pem / epicnabbo-key.pem) contain # the private key and MUST NOT be committed to git. set -euo pipefail TRAEFIK_DYNAMIC="/docker/proxyserver/dynamic" ACME_JSON="/docker/proxyserver/letsencrypt/acme.json" INTERMEDIATE_URL="http://yr2.i.lencr.org/" if [ ! -f "$ACME_JSON" ]; then echo "acme.json not found at $ACME_JSON" >&2 exit 1 fi WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT # Extract the epicnabbo.nl leaf certificate + private key from acme.json. docker exec traefik cat /letsencrypt/acme.json 2>/dev/null > "$WORK/acme.json" python3 - "$WORK/acme.json" "$WORK/leaf.pem" "$WORK/key.pem" <<'PY' import sys, json, base64 path, leaf_out, key_out = sys.argv[1], sys.argv[2], sys.argv[3] data = json.load(open(path)) found = False for _resolver, v in data.items(): for c in (v.get("Certificates") or []): if c.get("domain", {}).get("main") == "epicnabbo.nl": open(leaf_out, "wb").write(base64.b64decode(c["certificate"])) open(key_out, "wb").write(base64.b64decode(c["key"])) found = True break if found: break if not found: sys.exit("epicnabbo.nl certificate not found in acme.json") PY # Fetch the Let's Encrypt YR2 intermediate (issuer of the leaf). curl -fsSL "$INTERMEDIATE_URL" -o "$WORK/intermediate.der" openssl x509 -inform der -in "$WORK/intermediate.der" -out "$WORK/intermediate.pem" # Assemble leaf + intermediate into a full chain. cat "$WORK/leaf.pem" "$WORK/intermediate.pem" > "$TRAEFIK_DYNAMIC/epicnabbo-fullchain.pem" cp "$WORK/key.pem" "$TRAEFIK_DYNAMIC/epicnabbo-key.pem" chmod 644 "$TRAEFIK_DYNAMIC/epicnabbo-fullchain.pem" "$TRAEFIK_DYNAMIC/epicnabbo-key.pem" echo "Regenerated full chain at $TRAEFIK_DYNAMIC/epicnabbo-fullchain.pem" echo "Restart Traefik for the change to take effect."