#!/bin/bash # Deploy Silo to silo.example.internal # # Usage: ./scripts/deploy.sh [host] # host defaults to silo.example.internal # # Prerequisites: # - SSH access to the target host # - /etc/silo/silod.env must exist on target with credentials filled in # - PostgreSQL reachable from target at psql.example.internal # - MinIO reachable from target at minio.example.internal set -euo pipefail TARGET="${1:-silo.example.internal}" DEPLOY_DIR="/opt/silo" CONFIG_DIR="/etc/silo" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="${SCRIPT_DIR}/.." echo "=== Silo Deploy to ${TARGET} ===" # --- Build locally --- echo "[1/6] Building Go binary..." cd "$PROJECT_DIR" GOOS=linux GOARCH=amd64 go build -o silod ./cmd/silod echo "[2/6] Building React frontend..." cd "$PROJECT_DIR/web" npm run build # --- Package --- echo "[3/6] Packaging..." STAGING=$(mktemp -d) trap "rm -rf $STAGING" EXIT mkdir -p "$STAGING/bin" mkdir -p "$STAGING/web" mkdir -p "$STAGING/schemas" mkdir -p "$STAGING/migrations" cp "$PROJECT_DIR/silod" "$STAGING/bin/silod" cp -r "$PROJECT_DIR/web/dist" "$STAGING/web/dist" cp "$PROJECT_DIR/schemas/"*.yaml "$STAGING/schemas/" cp "$PROJECT_DIR/migrations/"*.sql "$STAGING/migrations/" cp "$PROJECT_DIR/deployments/config.prod.yaml" "$STAGING/config.yaml" cp "$PROJECT_DIR/deployments/systemd/silod.service" "$STAGING/silod.service" cp "$PROJECT_DIR/deployments/systemd/silod.env.example" "$STAGING/silod.env.example" TARBALL=$(mktemp --suffix=.tar.gz) tar -czf "$TARBALL" -C "$STAGING" . echo " Package: $(du -h "$TARBALL" | cut -f1)" # --- Deploy --- echo "[4/6] Uploading to ${TARGET}..." scp "$TARBALL" "${TARGET}:/tmp/silo-deploy.tar.gz" echo "[5/6] Installing on ${TARGET}..." ssh "$TARGET" bash -s <<'REMOTE' set -euo pipefail DEPLOY_DIR="/opt/silo" CONFIG_DIR="/etc/silo" # Create directories sudo mkdir -p "$DEPLOY_DIR/bin" "$DEPLOY_DIR/web" "$DEPLOY_DIR/schemas" "$DEPLOY_DIR/migrations" sudo mkdir -p "$CONFIG_DIR" # Stop service if running if systemctl is-active --quiet silod 2>/dev/null; then echo " Stopping silod..." sudo systemctl stop silod fi # Extract echo " Extracting..." sudo tar -xzf /tmp/silo-deploy.tar.gz -C "$DEPLOY_DIR" sudo chmod +x "$DEPLOY_DIR/bin/silod" rm -f /tmp/silo-deploy.tar.gz # Install config if not present (don't overwrite existing) if [ ! -f "$CONFIG_DIR/config.yaml" ]; then echo " Installing default config..." sudo cp "$DEPLOY_DIR/config.yaml" "$CONFIG_DIR/config.yaml" 2>/dev/null || true fi # Install env template if not present if [ ! -f "$CONFIG_DIR/silod.env" ]; then echo " WARNING: /etc/silo/silod.env does not exist!" echo " Copying template..." sudo cp "$DEPLOY_DIR/silod.env.example" "$CONFIG_DIR/silod.env" echo " Edit /etc/silo/silod.env with your credentials before starting the service." fi # Install systemd service echo " Installing systemd service..." sudo cp "$DEPLOY_DIR/silod.service" /etc/systemd/system/silod.service # Set ownership sudo chown -R silo:silo "$DEPLOY_DIR" 2>/dev/null || true sudo chmod 600 "$CONFIG_DIR/silod.env" 2>/dev/null || true echo " Files installed to $DEPLOY_DIR" REMOTE echo "[6/6] Running migrations and starting service..." ssh "$TARGET" bash -s <<'REMOTE' set -euo pipefail DEPLOY_DIR="/opt/silo" CONFIG_DIR="/etc/silo" # Source env for migration if [ -f "$CONFIG_DIR/silod.env" ]; then set -a source "$CONFIG_DIR/silod.env" set +a fi # Run migrations if command -v psql &>/dev/null && [ -n "${SILO_DB_PASSWORD:-}" ]; then echo " Running migrations..." for f in "$DEPLOY_DIR/migrations/"*.sql; do echo " $(basename "$f")" PGPASSWORD="$SILO_DB_PASSWORD" psql \ -h psql.example.internal -p 5432 \ -U silo -d silo \ -f "$f" -q 2>&1 | grep -v "already exists" || true done echo " Migrations complete." else echo " WARNING: psql not available or SILO_DB_PASSWORD not set, skipping migrations." echo " Run migrations manually: PGPASSWORD=... psql -h psql.example.internal -U silo -d silo -f /opt/silo/migrations/NNN_name.sql" fi # Start service echo " Starting silod..." sudo systemctl daemon-reload sudo systemctl enable silod sudo systemctl start silod sleep 2 if systemctl is-active --quiet silod; then echo " silod is running!" else echo " ERROR: silod failed to start. Check: journalctl -u silod -n 50" exit 1 fi REMOTE echo "" echo "=== Deploy complete ===" echo " Backend: https://${TARGET} (port 8080)" echo " React SPA served from /opt/silo/web/dist/" echo " Logs: ssh ${TARGET} journalctl -u silod -f"