Add K3s dev deployment setup for single-node VPS

Mirrors the prod deploy-k3s/ setup but runs all services in-cluster
on a single node: PostgreSQL (replaces Neon), MinIO S3-compatible
storage (replaces B2), Redis, API, worker, and admin.

Includes fully automated setup scripts (00-init through 04-verify),
server hardening (SSH, fail2ban, ufw), Let's Encrypt TLS via Traefik,
network policies, RBAC, and security contexts matching prod.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-30 21:30:39 -05:00
parent 00fd674b56
commit 34553f3bec
52 changed files with 5319 additions and 0 deletions

235
deploy-k3s-dev/scripts/00-init.sh Executable file
View File

@@ -0,0 +1,235 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
SECRETS_DIR="${DEPLOY_DIR}/secrets"
CONFIG_FILE="${DEPLOY_DIR}/config.yaml"
log() { printf '[init] %s\n' "$*"; }
warn() { printf '[init][warn] %s\n' "$*" >&2; }
die() { printf '[init][error] %s\n' "$*" >&2; exit 1; }
# --- Prerequisites ---
command -v openssl >/dev/null 2>&1 || die "Missing: openssl"
command -v python3 >/dev/null 2>&1 || die "Missing: python3"
echo ""
echo "============================================"
echo " honeyDue Dev Server — Initial Setup"
echo "============================================"
echo ""
echo "This script will:"
echo " 1. Generate any missing random secrets"
echo " 2. Ask for anything not already filled in"
echo " 3. Create config.yaml with everything filled in"
echo ""
mkdir -p "${SECRETS_DIR}"
# --- Generate random secrets (skip if already exist) ---
generate_if_missing() {
local file="$1" label="$2" cmd="$3"
if [[ -f "${file}" && -s "${file}" ]]; then
log " ${label} — already exists, keeping"
else
eval "${cmd}" > "${file}"
log " ${label} — generated"
fi
}
log "Checking secrets..."
generate_if_missing "${SECRETS_DIR}/secret_key.txt" "secrets/secret_key.txt" "openssl rand -base64 48"
generate_if_missing "${SECRETS_DIR}/postgres_password.txt" "secrets/postgres_password.txt" "openssl rand -base64 24"
generate_if_missing "${SECRETS_DIR}/minio_root_password.txt" "secrets/minio_root_password.txt" "openssl rand -base64 24"
generate_if_missing "${SECRETS_DIR}/email_host_password.txt" "secrets/email_host_password.txt" "echo PLACEHOLDER"
log " secrets/fcm_server_key.txt — skipped (Android not ready)"
generate_if_missing "${SECRETS_DIR}/apns_auth_key.p8" "secrets/apns_auth_key.p8" "echo ''"
REDIS_PW="$(openssl rand -base64 24)"
log " Redis password — generated"
# --- Collect only what's missing ---
ask() {
local var_name="$1" prompt="$2" default="${3:-}"
local val
if [[ -n "${default}" ]]; then
read -rp "${prompt} [${default}]: " val
val="${val:-${default}}"
else
read -rp "${prompt}: " val
fi
eval "${var_name}='${val}'"
}
echo ""
echo "--- Server ---"
ask SERVER_HOST "Server IP or SSH alias" "honeyDueDevUpdate"
[[ -n "${SERVER_HOST}" ]] || die "Server host is required"
ask SERVER_USER "SSH user" "root"
ask SSH_KEY "SSH key path" "~/.ssh/id_ed25519"
echo ""
echo "--- Container Registry (GHCR) ---"
ask GHCR_USER "GitHub username" "treytartt"
[[ -n "${GHCR_USER}" ]] || die "GitHub username is required"
ask GHCR_TOKEN "GitHub PAT (read:packages, write:packages)" "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"
[[ -n "${GHCR_TOKEN}" ]] || die "GitHub PAT is required"
echo ""
echo "--- TLS ---"
ask LE_EMAIL "Let's Encrypt email" "treytartt@fastmail.com"
echo ""
echo "--- Admin Panel ---"
ask ADMIN_USER "Admin basic auth username" "admin"
ADMIN_PW="$(openssl rand -base64 16)"
# --- Known values from existing Dokku setup ---
EMAIL_USER="treytartt@fastmail.com"
APNS_KEY_ID="9R5Q7ZX874"
APNS_TEAM_ID="V3PF3M6B6U"
log ""
log "Pre-filled from existing dev server:"
log " Email user: ${EMAIL_USER}"
log " APNS Key ID: ${APNS_KEY_ID}"
log " APNS Team ID: ${APNS_TEAM_ID}"
# --- Generate config.yaml ---
log "Generating config.yaml..."
cat > "${CONFIG_FILE}" <<YAML
# config.yaml — auto-generated by 00-init.sh
# This file is gitignored — never commit it with real values.
# --- Server ---
server:
host: "${SERVER_HOST}"
user: "${SERVER_USER}"
ssh_key: "${SSH_KEY}"
# --- Domains ---
domains:
api: devapi.myhoneydue.com
admin: devadmin.myhoneydue.com
base: dev.myhoneydue.com
# --- Container Registry (GHCR) ---
registry:
server: ghcr.io
namespace: "${GHCR_USER}"
username: "${GHCR_USER}"
token: "${GHCR_TOKEN}"
# --- Database (in-cluster PostgreSQL) ---
database:
name: honeydue_dev
user: honeydue
max_open_conns: 10
max_idle_conns: 5
max_lifetime: "600s"
# --- Email (Fastmail) ---
email:
host: smtp.fastmail.com
port: 587
user: "${EMAIL_USER}"
from: "honeyDue DEV <${EMAIL_USER}>"
use_tls: true
# --- Push Notifications ---
push:
apns_key_id: "${APNS_KEY_ID}"
apns_team_id: "${APNS_TEAM_ID}"
apns_topic: com.tt.honeyDue
apns_production: false
apns_use_sandbox: true
# --- Object Storage (in-cluster MinIO) ---
storage:
minio_root_user: honeydue
bucket: honeydue-dev
max_file_size: 10485760
allowed_types: "image/jpeg,image/png,image/gif,image/webp,application/pdf"
# --- Worker Schedules (UTC hours) ---
worker:
task_reminder_hour: 14
overdue_reminder_hour: 15
daily_digest_hour: 3
# --- Feature Flags ---
features:
push_enabled: true
email_enabled: false
webhooks_enabled: false
onboarding_emails_enabled: false
pdf_reports_enabled: true
worker_enabled: true
# --- Redis ---
redis:
password: "${REDIS_PW}"
# --- Admin Panel ---
admin:
basic_auth_user: "${ADMIN_USER}"
basic_auth_password: "${ADMIN_PW}"
# --- TLS ---
tls:
mode: letsencrypt
letsencrypt_email: "${LE_EMAIL}"
# --- Apple Auth / IAP ---
apple_auth:
client_id: "com.tt.honeyDue"
team_id: "${APNS_TEAM_ID}"
iap_key_id: ""
iap_issuer_id: ""
iap_bundle_id: ""
iap_key_path: ""
iap_sandbox: true
# --- Google Auth / IAP ---
google_auth:
client_id: ""
android_client_id: ""
ios_client_id: ""
iap_package_name: ""
iap_service_account_path: ""
YAML
# --- Summary ---
echo ""
echo "============================================"
echo " Setup Complete"
echo "============================================"
echo ""
echo "Generated:"
echo " config.yaml"
echo " secrets/secret_key.txt"
echo " secrets/postgres_password.txt"
echo " secrets/minio_root_password.txt"
echo " secrets/email_host_password.txt"
echo " secrets/fcm_server_key.txt"
echo " secrets/apns_auth_key.p8"
echo ""
echo "Admin panel credentials:"
echo " Username: ${ADMIN_USER}"
echo " Password: ${ADMIN_PW}"
echo " (save these — they won't be shown again)"
echo ""
echo "Next steps:"
echo " ./scripts/01-setup-k3s.sh"
echo " ./scripts/02-setup-secrets.sh"
echo " ./scripts/03-deploy.sh"
echo " ./scripts/04-verify.sh"
echo ""