feat: self-provisioning deploy.sh — auto-installs sops+age, generates key

On first deploy to a new server, deploy.sh:
1. Installs age and sops binaries if missing
2. Generates an age keypair if missing
3. Prints the public key and exits with instructions

All checks are idempotent — subsequent deploys skip to decryption.
Removed duplicate sops/age setup from setup_server.sh (deploy.sh handles it).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-23 18:13:06 +01:00
parent dcc1c15d05
commit e4bd9378f5
2 changed files with 50 additions and 48 deletions

View File

@@ -1,8 +1,53 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# ── Ensure sops + age are installed ───────────────────────
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH_SOPS="amd64"; ARCH_AGE="amd64" ;;
aarch64) ARCH_SOPS="arm64"; ARCH_AGE="arm64" ;;
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
esac
if ! command -v age &>/dev/null; then
echo "==> Installing age..."
AGE_VERSION="v1.3.1"
curl -fsSL "https://dl.filippo.io/age/${AGE_VERSION}?for=linux/${ARCH_AGE}" -o /tmp/age.tar.gz
tar -xzf /tmp/age.tar.gz -C /usr/local/bin --strip-components=1 age/age age/age-keygen
chmod +x /usr/local/bin/age /usr/local/bin/age-keygen
rm /tmp/age.tar.gz
fi
if ! command -v sops &>/dev/null; then
echo "==> Installing sops..."
SOPS_VERSION="v3.12.1"
curl -fsSL "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.${ARCH_SOPS}" -o /usr/local/bin/sops
chmod +x /usr/local/bin/sops
fi
# ── Ensure age keypair exists ─────────────────────────────
AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-/opt/padelnomics/age-key.txt}"
export SOPS_AGE_KEY_FILE="$AGE_KEY_FILE"
if [ ! -f "$AGE_KEY_FILE" ]; then
echo "==> Generating age keypair..."
age-keygen -o "$AGE_KEY_FILE" 2>&1
chmod 600 "$AGE_KEY_FILE"
AGE_PUB=$(grep "public key:" "$AGE_KEY_FILE" | awk '{print $NF}')
echo ""
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!! NEW SERVER — add this public key to .sops.yaml: !!"
echo "!! !!"
echo "!! $AGE_PUB !!"
echo "!! !!"
echo "!! Then run: sops updatekeys .env.prod.sops !!"
echo "!! Commit, push, and re-deploy. !!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo ""
exit 1
fi
# ── Decrypt secrets ─────────────────────────────────────── # ── Decrypt secrets ───────────────────────────────────────
export SOPS_AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-/opt/padelnomics/age-key.txt}"
sops --input-type dotenv --output-type dotenv -d .env.prod.sops > .env sops --input-type dotenv --output-type dotenv -d .env.prod.sops > .env
chmod 600 .env chmod 600 .env

View File

@@ -38,45 +38,8 @@ else
echo "Deploy key already exists, skipping" echo "Deploy key already exists, skipping"
fi fi
# Install sops + age (encrypted secrets) # NOTE: sops + age installation and keypair generation is handled by deploy.sh
AGE_KEY_FILE="$APP_DIR/age-key.txt" # (self-provisioning on first run). No need to install here.
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH_SOPS="amd64"; ARCH_AGE="amd64" ;;
aarch64) ARCH_SOPS="arm64"; ARCH_AGE="arm64" ;;
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
esac
if ! command -v age &>/dev/null; then
echo "Installing age..."
AGE_VERSION="v1.3.1"
curl -fsSL "https://dl.filippo.io/age/${AGE_VERSION}?for=linux/${ARCH_AGE}" -o /tmp/age.tar.gz
tar -xzf /tmp/age.tar.gz -C /usr/local/bin --strip-components=1 age/age age/age-keygen
chmod +x /usr/local/bin/age /usr/local/bin/age-keygen
rm /tmp/age.tar.gz
echo "Installed age $(age --version)"
else
echo "age already installed, skipping"
fi
if ! command -v sops &>/dev/null; then
echo "Installing sops..."
SOPS_VERSION="v3.12.1"
curl -fsSL "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.${ARCH_SOPS}" -o /usr/local/bin/sops
chmod +x /usr/local/bin/sops
echo "Installed sops $(sops --version)"
else
echo "sops already installed, skipping"
fi
# Generate age keypair for this server (used by deploy.sh to decrypt secrets)
if [ ! -f "$AGE_KEY_FILE" ]; then
age-keygen -o "$AGE_KEY_FILE" 2>&1
chmod 600 "$AGE_KEY_FILE"
echo "Generated age key: $AGE_KEY_FILE"
else
echo "Age key already exists: $AGE_KEY_FILE"
fi
# Install rclone (landing zone backup to R2) # Install rclone (landing zone backup to R2)
if ! command -v rclone &>/dev/null; then if ! command -v rclone &>/dev/null; then
@@ -110,14 +73,8 @@ echo "1. Add this deploy key to GitLab (Settings → Repository → Deploy Keys,
echo "" echo ""
cat "$KEY_PATH.pub" cat "$KEY_PATH.pub"
echo "" echo ""
echo "2. Add this server's age public key to .sops.yaml (comma-separated with existing keys):" echo "2. Clone the repo:"
echo ""
grep "public key:" "$AGE_KEY_FILE" | awk '{print $NF}'
echo ""
echo " Then re-encrypt prod secrets: sops updatekeys .env.prod.sops"
echo ""
echo "3. Clone the repo:"
echo " git clone git@gitlab.com:YOUR_USER/padelnomics.git $APP_DIR" echo " git clone git@gitlab.com:YOUR_USER/padelnomics.git $APP_DIR"
echo "" echo ""
echo "4. Deploy:" echo "3. Deploy (first run installs sops+age and generates server keypair):"
echo " cd $APP_DIR && bash deploy.sh" echo " cd $APP_DIR && bash deploy.sh"