#!/usr/bin/env bash # Regenerate all per-VPS secrets in .env. Run ONCE per new VPS deployment. # Backs up the existing .env first. # # Generates: # POSTGRES_PASSWORD, JWT_SECRET, DASHBOARD_PASSWORD, # SECRET_KEY_BASE, VAULT_ENC_KEY, MEILI_MASTER_KEY, # IMGPROXY_KEY, IMGPROXY_SALT, # ANON_KEY and SERVICE_ROLE_KEY (JWTs signed with JWT_SECRET) # # Usage: ./gen-secrets.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" STACK_DIR="$(dirname "$SCRIPT_DIR")" ENV_FILE="${STACK_DIR}/.env" if [ ! -f "$ENV_FILE" ]; then echo "❌ $ENV_FILE not found. Copy .env.example to .env first." exit 1 fi cp "$ENV_FILE" "${ENV_FILE}.backup.$(date +%s)" echo "✓ backed up to ${ENV_FILE}.backup." POSTGRES_PASSWORD=$(openssl rand -hex 32 | head -c 48) JWT_SECRET=$(openssl rand -hex 64) DASHBOARD_PASSWORD=$(openssl rand -base64 24 | tr -d '/=+') SECRET_KEY_BASE=$(openssl rand -hex 64) VAULT_ENC_KEY=$(openssl rand -hex 32 | head -c 32) MEILI_MASTER_KEY=$(openssl rand -hex 32) IMGPROXY_KEY=$(openssl rand -hex 64) IMGPROXY_SALT=$(openssl rand -hex 64) # Generate Supabase ANON_KEY and SERVICE_ROLE_KEY (HS256 JWTs) # Standard payload Supabase expects: # iss: supabase ref: role: anon|service_role # iat: now exp: now + 10 years generate_jwt() { local role="$1" local now=$(date +%s) local exp=$((now + 315360000)) # +10 years local header_b64=$(printf '%s' '{"alg":"HS256","typ":"JWT"}' | openssl base64 -A | tr -d '=' | tr '/+' '_-') local payload_b64=$(printf '{"iss":"supabase","ref":"disclosure","role":"%s","iat":%s,"exp":%s}' "$role" "$now" "$exp" | openssl base64 -A | tr -d '=' | tr '/+' '_-') local signing_input="${header_b64}.${payload_b64}" local sig=$(printf '%s' "$signing_input" | openssl dgst -sha256 -hmac "$JWT_SECRET" -binary | openssl base64 -A | tr -d '=' | tr '/+' '_-') echo "${signing_input}.${sig}" } ANON_KEY=$(generate_jwt "anon") SERVICE_ROLE_KEY=$(generate_jwt "service_role") # Replace values in .env (only the lines that match these keys) replace() { local key="$1" value="$2" # macOS sed needs '' after -i; this is portable enough for both BSD and GNU if sed --version >/dev/null 2>&1; then sed -i "s|^${key}=.*|${key}=${value}|" "$ENV_FILE" else sed -i '' "s|^${key}=.*|${key}=${value}|" "$ENV_FILE" fi } replace POSTGRES_PASSWORD "$POSTGRES_PASSWORD" replace JWT_SECRET "$JWT_SECRET" replace DASHBOARD_PASSWORD "$DASHBOARD_PASSWORD" replace SECRET_KEY_BASE "$SECRET_KEY_BASE" replace VAULT_ENC_KEY "$VAULT_ENC_KEY" replace MEILI_MASTER_KEY "$MEILI_MASTER_KEY" replace IMGPROXY_KEY "$IMGPROXY_KEY" replace IMGPROXY_SALT "$IMGPROXY_SALT" replace ANON_KEY "$ANON_KEY" replace SERVICE_ROLE_KEY "$SERVICE_ROLE_KEY" echo "✓ secrets rotated in $ENV_FILE" echo "" echo "ANON_KEY (length=${#ANON_KEY}): ${ANON_KEY:0:40}…" echo "SERVICE_ROLE_KEY (length=${#SERVICE_ROLE_KEY}): ${SERVICE_ROLE_KEY:0:40}…" echo "" echo "Both are JWTs signed with JWT_SECRET. Supabase uses them to authorize requests." echo "Distribute ANON_KEY to clients (NEXT_PUBLIC_SUPABASE_ANON_KEY)." echo "Keep SERVICE_ROLE_KEY private (server-only — bypasses RLS)."