A full audit of the installer and first-run experience found the mandatory
first-run wizard (is_initial_setup gate + InitialSetup.tsx) already works
correctly end-to-end — the real gap was discoverability and drift between
the installer and current app, not the wizard itself:
- nginx's static welcome page (served on the default HTTP/HTTPS ports, the
first place any new admin looks) never mentioned the admin panel lives on
a separate port, still shipped a Korean-language switcher despite Korean
being fully removed from the product, and linked to the retired
"Argus-appliance" identity. Now surfaces a live, dynamically-derived
admin panel link and drops the dead i18n/branding.
- users.language defaulted to 'ko' at the schema level (both the column
DEFAULT and the seed admin row) — a leftover from before Korean removal,
silently affecting every new user, not just the seed account.
- Three independently-drifting install paths existed (public distribution
installer, private-repo SSH-ship installer, and a fully manual README/docs
flow). README/docs now lead with the public alleyviper/argus installer
(verified to actually exist and mirror distribution/); the manual path is
kept only as an explicit private/pre-release fallback.
- Both scripted installers auto-rotated admin/admin via the API as their
last step, silently warning (not failing) if it didn't work — inconsistent
with the manual path and capable of leaving defaults active undetected.
Removed; every install path now consistently lands on admin/admin + the
in-app wizard.
- ANIS_ADMIN_KEY was documented as required ("ARGUS fails closed without
it") but is never read anywhere in src/api — confirmed dead, not just
vestigial. Retired from env templates, compose files, and docs; ROADMAP's
existing "wire it up or retire it" item resolved for this variable.
- Proxy host creation returned an opaque 500 when given an unresolvable
forward_host (e.g. a Docker container name typed into the free-text
field — ARGUS's nginx runs in host-network mode with no embedded DNS).
nginx -t's real "host not found in upstream" failure now surfaces as an
actionable 400 instead of a generic internal error; placeholder text
fixed to stop inviting the failure. Live-verified both the failure path
(with NGINX_SKIP_TEST temporarily disabled in the sandbox to exercise the
real validation) and the no-regression path (valid IP still succeeds).
- LOG_COLLECTION silently disables the entire access-log/analytics/live-event
pipeline when set to anything but the exact string "true", with zero log
output anywhere. Added a boot-time WARN matching the existing
IsInitialSetupRequired nudge pattern.
Every fix live-verified against a genuinely fresh sandbox install
(docker/docker-compose.local-sandbox.yml, zero pre-existing volumes),
not just read from source.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
121 lines
5.8 KiB
Bash
Executable File
121 lines
5.8 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. Summary ─────────────────────────────────────────────────────────────────
|
|
# Credentials are no longer auto-rotated here — a fresh install always lands
|
|
# on admin/admin, and ARGUS itself forces a mandatory First-Run Setup Wizard
|
|
# on that first login (credential change, regional settings, guided feature
|
|
# configuration, installation validation) before the dashboard is reachable.
|
|
# Pre-rotating here just made that flow inconsistent across install paths and
|
|
# risked silently leaving defaults active if the rotation call failed.
|
|
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)"
|
|
info "Default Login: admin / admin"
|
|
warn "You will be required to set a real username/password and complete the First-Run Setup Wizard on first login."
|
|
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
|