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 | shRequirements: 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 verifyProperties: 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.