#!/usr/bin/env bash # vps-bootstrap.sh - Phase 0: turn a bare VPS into the vps-standby ArgoCD destination # # Run this ON THE VPS itself (as root, or via sudo), not against the home cluster. # Installs k3s (single node), joins the existing self-hosted Netbird mesh, and # installs cert-manager with the same Cloudflare DNS-01 ClusterIssuer pattern used # at home — so TLS issuance works identically regardless of which site is "live" # (DNS-01 only needs DNS control, not public HTTP reachability). # # This script does NOT register the cluster with ArgoCD — that's a one-time manual # step run from your workstation/home cluster once this script prints the kubeconfig # (ArgoCD can't reach the VPS until it exists, and shouldn't hold cluster-admin creds # for a box it doesn't manage yet). # # Usage: # sudo ./scripts/vps-bootstrap.sh # # Prerequisites: # - A Netbird setup key (Netbird dashboard → Settings → Setup Keys → create # a reusable, non-ephemeral key) # - A Cloudflare API token scoped to Zone:DNS:Edit for kube.huskypup.net only # (create a NEW token for this — do not reuse the one from # infrastructure/cert-manager/manifests/secret-cf-token.yaml, that one is # being rotated/retired; see Phase 0.5) # - Ubuntu/Debian VPS with a public IP, run as root set -euo pipefail NETBIRD_SETUP_KEY="${1:?Usage: $0 }" CLOUDFLARE_TOKEN="${2:?Usage: $0 }" NETBIRD_MGMT_URL="https://netbird.kube.huskypup.net" LETSENCRYPT_EMAIL="garrettstone499@gmail.com" DNS_ZONE="kube.huskypup.net" CERT_MANAGER_VERSION="v1.13.2" # matches infrastructure/cert-manager chart version at home if [ "$(id -u)" -ne 0 ]; then echo "ERROR: run as root (sudo $0 ...)" >&2 exit 1 fi echo "=================================================" echo "VPS Standby Bootstrap - Phase 0" echo "=================================================" echo "" # --- k3s ----------------------------------------------------------------- if command -v k3s >/dev/null 2>&1; then echo "✅ k3s already installed, skipping install" else echo "Installing k3s (single node)..." # Keep the built-in Traefik ingress controller — this is a lean standby box, # not a mirror of home's Istio/Envoy-Gateway mesh. servicelb is fine too # since this is a single node with a real public IP. curl -sfL https://get.k3s.io | sh -s - \ --write-kubeconfig-mode 644 \ --disable metrics-server echo "✅ k3s installed" fi echo "Waiting for k3s node to be Ready..." for i in $(seq 1 30); do if k3s kubectl get nodes 2>/dev/null | grep -q " Ready"; then echo "✅ node is Ready" break fi sleep 5 done k3s kubectl get nodes export KUBECONFIG=/etc/rancher/k3s/k3s.yaml # --- Netbird --------------------------------------------------------------- if command -v netbird >/dev/null 2>&1 && netbird status 2>/dev/null | grep -q "Management: Connected"; then echo "✅ Netbird already connected, skipping" else echo "Installing Netbird client..." curl -fsSL https://pkgs.netbird.io/install.sh | sh echo "Joining Netbird mesh (${NETBIRD_MGMT_URL})..." netbird up --management-url "${NETBIRD_MGMT_URL}" --setup-key "${NETBIRD_SETUP_KEY}" echo "✅ Netbird joined" fi echo "Note: this Netbird session is used opportunistically for backup/sync traffic" echo "while home is up. It is NOT the path used to reach this VPS when home is down —" echo "that's direct SSH on this box's public IP. See plan doc, decision #2." # --- cert-manager ------------------------------------------------------------ echo "" echo "Installing cert-manager ${CERT_MANAGER_VERSION}..." if ! command -v helm >/dev/null 2>&1; then curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash fi helm repo add jetstack https://charts.jetstack.io 2>/dev/null || true helm repo update jetstack if helm -n cert-manager status cert-manager >/dev/null 2>&1; then echo "✅ cert-manager already installed" else helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version "${CERT_MANAGER_VERSION}" \ --set installCRDs=true \ --wait --timeout 300s echo "✅ cert-manager installed" fi echo "Waiting for cert-manager webhook to be ready..." k3s kubectl -n cert-manager rollout status deployment/cert-manager-webhook --timeout=120s # --- Cloudflare DNS-01 ClusterIssuer (same pattern as home) ----------------- echo "" echo "Applying Cloudflare token Secret + ClusterIssuer..." cat <:/etc/rancher/k3s/k3s.yaml ~/vps-standby-kubeconfig.yaml" echo " Then edit the 'server:' line inside it to use this VPS's public IP" echo " instead of 127.0.0.1." echo "" echo " 2. Register it with ArgoCD:" echo " KUBECONFIG=~/vps-standby-kubeconfig.yaml argocd cluster add default --name vps-standby" echo "" echo " 3. Confirm registration:" echo " argocd cluster list" echo "" echo "This box is otherwise reachable via:" echo " - Netbird (while home's self-hosted mesh is up)" echo " - Direct SSH on its public IP (always, break-glass path)"