dokploy-cluster.sh

Single-file bootstrapper for a six-node Dokploy Docker Swarm (3 managers, 3 workers) on Hetzner Cloud running Fedora 44: swarm over the Hetzner private network, Hetzner Load Balancer with /ping-gated TCP passthrough, global Traefik on the managers with Cloudflare DNS-01 certificates and Cloudflare-only origin enforcement, Tailscale SSH as the admin plane. Every design decision, verification status, and caveat lives in GUIDE.md — this script executes that tutorial's sections.

Install — downloads the toolkit into a fresh dokploy-cluster.* folder under /tmp and launches the interactive setup right away (pass a directory — … | sh -s -- <dir> — to keep the toolkit somewhere permanent):

curl -fsSL https://provision.lvq.app/dokploy/install.sh | sh

Requirements: a Hetzner Cloud project (API token) and a tailnet prepared per tutorial §2-B (tag, SSH ACL rule, tagged reusable auth key). Workstation dependencies (hcloud, jq, rsync, ssh, curl) are checked on start and the script offers to install missing ones — or answer no if you know better. Secrets enter via interactive prompt or environment, never argv.

Usage — the interactive mode drives everything:

./provision.sh up      # checks deps, prompts for secrets, datacenter, VPS types
                       # and SSH key, then runs the pipeline with guided pauses
                       # at the manual interludes (Dokploy admin UI, Cloudflare)

Or run the pipeline step by step (run bare to print it; env-driven, useful for re-runs and repairs):

TS_AUTHKEY=tskey-auth-… ./provision.sh provision
./provision.sh wait
./provision.sh swarm-init
./provision.sh dokploy-install
# Dokploy UI via Tailscale :3000 — create the admin account
./provision.sh join
ACME_EMAIL=CF_DNS_API_TOKEN=./provision.sh traefik
./provision.sh lb
# Cloudflare: SSL mode Full (strict); records → LB IP, Proxied
./provision.sh cf-allowlist
./provision.sh verify

Properties: guarded re-runs, not convergence — existing resources are skipped, drift is not reconciled. Node IPs come from the hcloud API. All scratch files live in a mktemp -d workspace that is removed on exit. traefik.yml edits are structural (PyYAML, .orig backup, fails loud on layout drift). The Cloudflare token becomes a Docker secret via stdin, never argv. Re-run cf-allowlist when Cloudflare's published ranges change; confirm the LB health-check flag names against your hcloud version before the first lb run.