Builds the customer-facing distribution: a curated distribution/ directory containing only what an end customer needs (production docker-compose.yml with no build: sections, install.sh/update.sh/uninstall.sh/healthcheck.sh/ backup.sh/restore.sh, a customer-facing CHANGELOG.md, and README/LICENSE/ NOTICE/THIRD_PARTY_LICENSES) — pushed as the initial content of the new public alleyviper/argus repo. install.sh: detects OS, validates Docker/Compose, fetches all deployment files, generates a secure DB password, creates the required Docker network, pulls images, starts the stack, waits for health, and rotates the default admin/admin credentials via the auth API — printing the generated password once at the end. update.sh/healthcheck.sh/backup.sh/restore.sh/uninstall.sh formalize what was previously ad-hoc README snippets into real, safe-by-default scripts (uninstall.sh keeps data unless --remove-data is explicitly passed and confirmed; restore.sh requires typed confirmation and documents that it targets a fresh install, not a live merge). Added a sync-distribution job to release.yml: after a successful release, mirrors distribution/ into the public repo and creates a matching (customer-facing, commit-log-free) release marker there. Needs a one-time setup step — a fine-grained PAT scoped to alleyviper/argus added as the ARGUS_PUBLIC_REPO_TOKEN secret — the job cleanly no-ops until that's added. Not yet done: GHCR package visibility (argus-secure-api/-ui/-nginx) is still private, which blocks a genuine end-to-end curl-install test from a clean, unauthenticated environment — deferred at the user's request until they flip it manually (GitHub does not expose this via API).
145 lines
6.7 KiB
Bash
Executable File
145 lines
6.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# ARGUS installer — fetches the production compose stack, generates secrets,
|
|
# starts the platform, and prints your admin credentials.
|
|
#
|
|
# curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/install.sh | bash
|
|
#
|
|
set -euo pipefail
|
|
|
|
REPO_RAW_BASE="https://raw.githubusercontent.com/alleyviper/argus/main"
|
|
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
|
|
NETWORK_NAME="argus-network"
|
|
|
|
# ── Output helpers ────────────────────────────────────────────────────────────
|
|
bold() { printf '\033[1m%s\033[0m\n' "$1"; }
|
|
info() { printf ' %s\n' "$1"; }
|
|
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
|
|
warn() { printf ' \033[33m!\033[0m %s\n' "$1"; }
|
|
fail() { printf ' \033[31m✗\033[0m %s\n' "$1" >&2; exit 1; }
|
|
|
|
bold "ARGUS Installer"
|
|
echo
|
|
|
|
# ── 1. OS detection (informational — Linux is the supported target) ──────────
|
|
OS="$(uname -s)"
|
|
case "$OS" in
|
|
Linux) ok "Detected Linux" ;;
|
|
Darwin) warn "Detected macOS — supported for local evaluation via Docker Desktop, not for production deployment." ;;
|
|
*) warn "Unrecognized OS ($OS) — proceeding, but only Linux is officially supported." ;;
|
|
esac
|
|
|
|
# ── 2. Docker / Compose availability ──────────────────────────────────────────
|
|
command -v docker >/dev/null 2>&1 || fail "Docker is not installed. Install Docker first: https://docs.docker.com/engine/install/"
|
|
docker info >/dev/null 2>&1 || fail "Docker is installed but not running (or this user lacks permission). Start Docker / add your user to the docker group, then re-run."
|
|
docker compose version >/dev/null 2>&1 || fail "Docker Compose v2 (the 'docker compose' plugin) is required. See https://docs.docker.com/compose/install/"
|
|
ok "Docker and Docker Compose are available"
|
|
|
|
# ── 3. Fetch deployment files ──────────────────────────────────────────────────
|
|
mkdir -p "$INSTALL_DIR/docker-socket-proxy"
|
|
cd "$INSTALL_DIR"
|
|
|
|
fetch() {
|
|
curl -fsSL "$REPO_RAW_BASE/$1" -o "$2" || fail "Failed to download $1"
|
|
}
|
|
|
|
fetch "docker-compose.yml" "docker-compose.yml"
|
|
fetch "docker-socket-proxy/haproxy.cfg.template" "docker-socket-proxy/haproxy.cfg.template"
|
|
for script in update.sh uninstall.sh healthcheck.sh backup.sh restore.sh; do
|
|
fetch "$script" "$script"
|
|
chmod +x "$script"
|
|
done
|
|
if [ ! -f .env ]; then
|
|
fetch ".env.example" ".env"
|
|
ok "Fetched deployment files into $INSTALL_DIR"
|
|
else
|
|
ok "Fetched compose file (kept your existing .env)"
|
|
fi
|
|
|
|
# ── 4. Generate secrets (first install only — never overwrite an existing .env) ──
|
|
if grep -q '^DB_PASSWORD=change-me-in-production' .env 2>/dev/null; then
|
|
DB_PASSWORD="$(openssl rand -base64 24 | tr -d '\n')"
|
|
sed -i.bak "s#^DB_PASSWORD=.*#DB_PASSWORD=${DB_PASSWORD}#" .env && rm -f .env.bak
|
|
ok "Generated a secure database password"
|
|
fi
|
|
|
|
# ── 5. Docker network ─────────────────────────────────────────────────────────
|
|
if docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then
|
|
ok "Docker network '$NETWORK_NAME' already exists"
|
|
else
|
|
docker network create "$NETWORK_NAME" >/dev/null
|
|
ok "Created Docker network '$NETWORK_NAME'"
|
|
fi
|
|
|
|
# ── 6. Pull and start ──────────────────────────────────────────────────────────
|
|
bold "Pulling images and starting ARGUS..."
|
|
docker compose pull
|
|
docker compose up -d
|
|
echo
|
|
|
|
# ── 7. Wait for the API to become healthy ─────────────────────────────────────
|
|
API_HOST_PORT="$(grep -oP '^API_HOST_PORT=\K.*' .env 2>/dev/null || true)"
|
|
API_HOST_PORT="${API_HOST_PORT:-9080}"
|
|
bold "Waiting for ARGUS to finish starting (this can take a few minutes on first boot)..."
|
|
READY=false
|
|
for _ in $(seq 1 90); do
|
|
if curl -fsS "http://127.0.0.1:${API_HOST_PORT}/health" >/dev/null 2>&1; then
|
|
READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$READY" != "true" ]; then
|
|
warn "ARGUS did not report healthy within 7.5 minutes."
|
|
warn "Check container status with: docker compose -f $INSTALL_DIR/docker-compose.yml ps"
|
|
warn "and logs with: docker compose -f $INSTALL_DIR/docker-compose.yml logs api"
|
|
exit 1
|
|
fi
|
|
ok "ARGUS is up"
|
|
|
|
# ── 8. Rotate the default admin credentials ───────────────────────────────────
|
|
ADMIN_USER="admin"
|
|
ADMIN_PASSWORD="Ax9!$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 20)"
|
|
API_BASE="http://127.0.0.1:${API_HOST_PORT}/api/v1"
|
|
|
|
LOGIN_RESP="$(curl -fsS -X POST "${API_BASE}/auth/login" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"username":"admin","password":"admin"}' 2>/dev/null || true)"
|
|
TOKEN="$(printf '%s' "${LOGIN_RESP}" | grep -oP '"token"\s*:\s*"\K[^"]+' || true)"
|
|
|
|
CREDS_ROTATED=false
|
|
if [ -n "$TOKEN" ]; then
|
|
CHANGE_RESP="$(curl -fsS -o /dev/null -w '%{http_code}' -X POST "${API_BASE}/auth/change-credentials" \
|
|
-H 'Content-Type: application/json' \
|
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
-d "{\"current_password\":\"admin\",\"new_username\":\"${ADMIN_USER}\",\"new_password\":\"${ADMIN_PASSWORD}\",\"new_password_confirm\":\"${ADMIN_PASSWORD}\"}" 2>/dev/null || echo "000")"
|
|
if [ "$CHANGE_RESP" = "200" ]; then
|
|
CREDS_ROTATED=true
|
|
ok "Rotated the default admin password"
|
|
fi
|
|
fi
|
|
if [ "$CREDS_ROTATED" != "true" ]; then
|
|
warn "Could not auto-rotate admin credentials (already changed on a prior run?). Log in with your existing credentials, or admin/admin on a genuinely fresh install."
|
|
fi
|
|
|
|
# ── 9. Summary ─────────────────────────────────────────────────────────────────
|
|
UI_PORT="$(grep -oP '^UI_PORT=\K.*' .env 2>/dev/null || true)"
|
|
UI_PORT="${UI_PORT:-81}"
|
|
|
|
echo
|
|
bold "ARGUS is installed and running."
|
|
echo
|
|
info "Admin Panel: https://localhost:${UI_PORT} (accept the self-signed certificate)"
|
|
if [ "$CREDS_ROTATED" = "true" ]; then
|
|
info "Username: ${ADMIN_USER}"
|
|
info "Password: ${ADMIN_PASSWORD}"
|
|
warn "Save this password now — it is not stored anywhere and cannot be recovered."
|
|
else
|
|
info "Log in with your existing admin credentials."
|
|
fi
|
|
echo
|
|
info "Configuration: ${INSTALL_DIR}/.env and ${INSTALL_DIR}/docker-compose.yml"
|
|
info "Upgrade: cd ${INSTALL_DIR} && docker compose pull && docker compose up -d"
|
|
info "Backups: see https://github.com/alleyviper/argus#backups"
|
|
echo
|