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 — the toolkit executes that tutorial's
sections. provision.sh is the entry point;
common.sh holds the TUI, config and shared helpers, and
each pipeline step lives in its own cmd-<step>.sh
alongside it.
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 the Hetzner project (hcloud
# context), resource name prefix + extra labels, secrets,
# Cloudflare zone + wildcard record, datacenter, VPS types
# and SSH key, then runs the pipeline with guided pauses
# at the manual interludes (Tailscale, Dokploy admin UI)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
CF_DNS_API_TOKEN=… CF_ZONE=example.com CF_RECORD='*.apps' ./provision.sh cf-dns
./provision.sh verifyHetzner resources are named <prefix>-mgr-1,
<prefix>-net, <prefix>-lb, … and
labeled cluster=<prefix> — set the prefix and extra
labels interactively in up, or via PREFIX=… /
LABELS="team=infra env=prod" for step runs.
cf-dns sets the zone's SSL mode to Full (strict) and
upserts the proxied wildcard record → LB IP through the Cloudflare API;
the token then needs Zone:Read + DNS:Edit + Zone Settings:Edit.
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. Confirm the LB health-check flag names against your
hcloud version before the first lb run.