forked from heavy-duty/rig
The Coolify control-plane database holds the GitHub App private key, every registered server's SSH key, and every environment value for every environment it manages. Backing it up was a manual runbook step, and the dump script lived in cast — the off-box tool, whose src never references it. It runs on the box, as root, under a scheduler: that is rig's job description. It matters beyond tidiness. The dump is forensics, not a restore path — a lost control plane is rebuilt fresh and reconciled from the manifest. So there will be a next control-plane box, and as a runbook step it was born un-backed-up, depending on someone remembering mid-incident. Now it is backed up from birth. rig installs the machinery and templates /etc/coolify-dump.env empty at 0600, never reading it back — no credential passes through rig. The script's own guards make an unfilled file fail the unit loudly rather than ship plaintext. systemd timer over cron: EnvironmentFile is the right idiom for 0600 secrets, failures surface in systemctl status instead of being mailed into the void, and Persistent=true catches a run missed while the box was down. Two hazards the cast script missed, carried into the unit: - aws-cli >= 2.23 enables default upload checksums that S3-compatible backends reject; Debian 13 ships 2.23.6, so the unit defaults both checksum knobs to when_required. - A failed pg_dump piped into age still yields a valid, tiny, encrypted file that uploads cleanly every night and looks exactly like a working backup. The script now refuses to upload an empty artifact. Closes #8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
85 lines
2.1 KiB
Bash
Executable file
85 lines
2.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.." && pwd)"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
usage: rig <command> [args]
|
|
|
|
commands:
|
|
bootstrap <control-plane|workload|runner> [--hostname <name>] [--ts-tag <tag>]
|
|
OS plumbing on a pristine Debian box: hardening, unattended-upgrades,
|
|
tailscale join. Prompts for a single-use tailnet pre-auth key
|
|
(TS_AUTHKEY env overrides the prompt). Run as root. Role runner
|
|
defaults to tag:ci and refuses tag:server.
|
|
coolify install --version <pin>
|
|
Pinned Coolify install (AUTOUPDATE=false). Control-plane box only.
|
|
coolify backup install [options]
|
|
Nightly age-encrypted dump of the control-plane database, as a
|
|
systemd timer. rig installs the machinery and templates an empty
|
|
0600 bindings file; you fill in the age recipient and S3 details.
|
|
Control-plane box only. Run as root.
|
|
runner install --repo <owner/repo> --version <pin> [options]
|
|
GitHub Actions runner as a systemd service under an unprivileged
|
|
user — outbound-only, no Docker. Prompts for the short-lived
|
|
registration token (RUNNER_TOKEN env overrides). Run as root.
|
|
|
|
install/upgrade:
|
|
curl -fsSL https://raw.githubusercontent.com/heavy-duty/rig/main/install.sh | bash
|
|
EOF
|
|
}
|
|
|
|
cmd="${1:-}"
|
|
case "$cmd" in
|
|
bootstrap)
|
|
shift
|
|
exec "$ROOT/commands/bootstrap.sh" "$@"
|
|
;;
|
|
coolify)
|
|
shift
|
|
sub="${1:-}"
|
|
case "$sub" in
|
|
install)
|
|
shift
|
|
exec "$ROOT/commands/coolify-install.sh" "$@"
|
|
;;
|
|
backup)
|
|
shift
|
|
if [ "${1:-}" != "install" ]; then
|
|
usage >&2
|
|
exit 2
|
|
fi
|
|
shift
|
|
exec "$ROOT/commands/coolify-backup-install.sh" "$@"
|
|
;;
|
|
*)
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
;;
|
|
runner)
|
|
shift
|
|
sub="${1:-}"
|
|
if [ "$sub" != "install" ]; then
|
|
usage >&2
|
|
exit 2
|
|
fi
|
|
shift
|
|
exec "$ROOT/commands/runner-install.sh" "$@"
|
|
;;
|
|
-h|--help|help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
"")
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
*)
|
|
printf 'rig: unknown command: %s\n' "$cmd" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|