#!/usr/bin/env bash # One-shot server setup for InfoXtractor. Idempotent: safe to re-run. # # Run from the Mac: # IX_POSTGRES_PASSWORD= ./scripts/setup_server.sh # # What it does on 192.168.68.42: # 1. Creates the bare git repo `/home/server/Public/infoxtractor/repos.git` if missing. # 2. Writes the post-receive hook (or updates it) and makes it executable. # 3. Creates the Postgres role + database on the shared `postgis` container. # 4. Writes `/home/server/Public/infoxtractor/app/.env` (0600) from .env.example. # 5. Verifies `qwen3:14b` is pulled in Ollama. set -euo pipefail SERVER="${IX_SERVER:-server@192.168.68.42}" APP_BASE="/home/server/Public/infoxtractor" REPOS_GIT="${APP_BASE}/repos.git" APP_DIR="${APP_BASE}/app" DB_NAME="infoxtractor" DB_USER="infoxtractor" if [ -z "${IX_POSTGRES_PASSWORD:-}" ]; then read -r -s -p "Postgres password for role '${DB_USER}': " IX_POSTGRES_PASSWORD echo fi if [ -z "${IX_POSTGRES_PASSWORD}" ]; then echo "IX_POSTGRES_PASSWORD is required." >&2 exit 1 fi echo "==> 1/5 Ensuring bare repo + post-receive hook on ${SERVER}" ssh "${SERVER}" bash -s <"${REPOS_GIT}/hooks/post-receive" <<'HOOK' #!/usr/bin/env bash set -eo pipefail APP_DIR="${APP_DIR}" LOG="/tmp/infoxtractor-deploy.log" echo "[\$(date -u '+%FT%TZ')] post-receive start" >> "\$LOG" mkdir -p "\$APP_DIR" GIT_WORK_TREE="\$APP_DIR" git --git-dir="${REPOS_GIT}" checkout -f main >> "\$LOG" 2>&1 cd "\$APP_DIR" docker compose up -d --build >> "\$LOG" 2>&1 # Deploy gate: /healthz must return 200 within 60 s. for i in \$(seq 1 30); do if curl -fsS http://localhost:8994/healthz > /dev/null 2>&1; then echo "[\$(date -u '+%FT%TZ')] healthz OK" >> "\$LOG" exit 0 fi sleep 2 done echo "[\$(date -u '+%FT%TZ')] healthz never reached OK" >> "\$LOG" docker compose logs --tail 100 >> "\$LOG" 2>&1 || true exit 1 HOOK chmod +x "${REPOS_GIT}/hooks/post-receive" EOF echo "==> 2/5 Verifying Ollama has qwen3:14b pulled" if ! ssh "${SERVER}" "docker exec ollama ollama list | awk '{print \$1}' | grep -qx 'qwen3:14b'"; then echo "FAIL: qwen3:14b not found in Ollama. Run: ssh ${SERVER} 'docker exec ollama ollama pull qwen3:14b'" >&2 exit 1 fi echo "==> 3/5 Creating Postgres role '${DB_USER}' and database '${DB_NAME}' on postgis container" # Idempotent via DO blocks; uses docker exec to avoid needing psql on the host. ssh "${SERVER}" bash -s < 4/5 Writing ${APP_DIR}/.env on the server" # Render .env from the repo's .env.example, substituting the password placeholder. LOCAL_ENV_CONTENT="$( sed "s##${IX_POSTGRES_PASSWORD}#g" \ "$(dirname "$0")/../.env.example" )" # Append the IX_TEST_MODE=production for safety (fake mode stays off). # .env is written atomically and permissioned 0600. ssh "${SERVER}" "install -d -m 0755 '${APP_DIR}' && cat > '${APP_DIR}/.env' <<'ENVEOF' ${LOCAL_ENV_CONTENT} ENVEOF chmod 0600 '${APP_DIR}/.env'" echo "==> 5/5 Checking UFW rule for port 8994 (LAN only)" ssh "${SERVER}" "sudo ufw status numbered | grep -F 8994" >/dev/null 2>&1 || { echo "NOTE: UFW doesn't yet allow 8994. Run on the server:" echo " sudo ufw allow from 192.168.68.0/24 to any port 8994 proto tcp" } echo echo "Done." echo echo "Next steps (on the Mac):" echo " git remote add server ssh://server@192.168.68.42${REPOS_GIT}" echo " git push server main" echo " ssh ${SERVER} 'tail -f /tmp/infoxtractor-deploy.log'" echo " curl http://192.168.68.42:8994/healthz" echo " python scripts/e2e_smoke.py"