Author SHA1 Message Date
alleyviperandroot 5bdfd99c4d feat(anis): auto-provision ANIS Community Edition on fresh installs (Phase 4)
Changed the ANIS_URL default from the docker-internal
"http://argus-anis:8090" to the public Community Edition hub
(https://anis.weboria.eu). That internal default was dead on arrival for
every real deployment path: neither docker/docker-compose.yml nor
distribution/docker-compose.yml bundles its own ANIS container (confirmed
via grep — only the dev-only docker-compose.local-sandbox.yml does, and
it already sets ANIS_URL explicitly, so it's unaffected by this change),
so a fresh install using either client-facing compose file previously got
ANIS_ENABLED=false and an empty/unreachable ANIS_URL with no working
threat intelligence out of the box.

An empty license key already grants the "community" tier server-side
(confirmed against ANIS's own RegisterInstance handler in a prior
grounding pass) — no signup or key needed, so defaulting
enabled=true/url=<public hub>/key=empty is a genuine zero-friction
default, not a placeholder pointing at something that doesn't work.
ANIS_ENABLED flipped from :-false to :-true in both compose files'
inline fallback (not just the .env.example docs) since a compose-level
explicit "false" string takes precedence over the Go binary's own
compiled default and previously masked it.

Updated distribution/.env.example and configs/env.example to match.

Live-verified against a genuinely fresh sandbox install (temporarily
unset the sandbox compose's own ANIS_URL override to actually exercise
the new default, reverted before committing — confirmed clean via `git
diff`): anis_settings bootstrapped to
enabled=true/url=https://anis.weboria.eu/license_key=''/bootstrapped=true
on first boot. Re-verified the sandbox's own explicit local override
(http://anis:8090, for its bundled ANIS container) still wins unaffected
after reverting.
2026-07-25 15:20:10 +00:00
913615903b fix(installer): align installer/onboarding with current codebase (Phase 1 audit)
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>
2026-07-25 13:46:34 +00:00
14 changed files with 222 additions and 408 deletions
+67
View File
@@ -0,0 +1,67 @@
# ARGUS — Environment Configuration
# Copy this file to .env and modify as needed. install.sh does this for you
# automatically, including generating a secure DB_PASSWORD.
# ===========================================
# Required Settings
# ===========================================
# Database password — install.sh generates this for you.
# Manual value: openssl rand -base64 24
DB_PASSWORD=change-me-in-production
# ===========================================
# Optional Settings
# ===========================================
TZ=UTC
DB_USER=postgres
DB_NAME=argus
# ===========================================
# ANIS — Threat Intelligence Integration
# ===========================================
# ANIS is a separate product, deployed independently (self-hosted or via a
# community instance). These vars configure how THIS ARGUS instance talks to
# an already-running ANIS service — they do not start one.
#
# On by default against the public Community Edition hub — an empty license
# key already grants the community (free) tier, no signup required. Point
# ANIS_URL at your own self-hosted ANIS instead if you run one, or set
# ANIS_ENABLED=false to turn this off entirely.
ANIS_ENABLED=true
ANIS_URL=https://anis.weboria.eu
# License key from ANIS dashboard -> Licenses -> Create License.
# Leave blank to use the community (free) tier.
ANIS_LICENSE_KEY=
ANIS_SHARE_ATTACKERS=false
# ===========================================
# Docker Compatibility (Synology DSM, etc.)
# ===========================================
# Leave empty for auto-detection. Only set if auto-detection fails.
# Synology DSM typically needs: 1.41 or 1.43
# DOCKER_API_VERSION=1.41
# ===========================================
# Network & Port Settings
# ===========================================
# Admin panel port (default: 81)
# UI_PORT=81
# Nginx listen ports — change if 80/443 are already in use
# (e.g. Synology Web Station)
# NGINX_HTTP_PORT=8080
# NGINX_HTTPS_PORT=8443
# API host port — exposed for nginx-to-API communication.
# MUST NOT conflict with NGINX_HTTP_PORT.
# API_HOST_PORT=9080
# DNS Security Engine listen address — host-only (127.0.0.1) by default.
# Set to an internal interface IP to route real client DNS traffic through
# it. Never 0.0.0.0 unless this host is on a fully trusted network.
# DNS_LISTEN_HOST=127.0.0.1
+2 -8
View File
@@ -27,11 +27,5 @@ Versioning follows [Semantic Versioning](https://semver.org/).
## [3.26.0] and earlier
Earlier release history predates this distribution's changelog.
---
**Note (2026-07-25):** this file is not currently kept in sync with every release — the most
recent entry above predates the current shipped version. Updating this changelog needs to
become part of the standard release process going forward, not backfilled retroactively with
invented descriptions of past changes.
Earlier release history predates this distribution's changelog. See the GitHub Releases
page for this repository going forward — every release from here on is documented here.
+7 -8
View File
@@ -1,18 +1,17 @@
ARGUS Enterprise Web Security Platform — Commercial License
Copyright (c) 2025-2026 Weboria. All rights reserved.
ARGUS Secure — Proprietary Software License
Copyright (c) 2025-2026 AI4SEC / lmelo. All rights reserved.
** PLACEHOLDER — NOT A FINAL LICENSE **
This repository contains proprietary, commercial software developed by Weboria. A complete
commercial license agreement has not yet been finalized and this file is a placeholder pending
legal review — this is a real, open item, not boilerplate.
This repository contains proprietary, commercial software. A complete commercial license
agreement has not yet been finalized and this file is a placeholder pending legal review.
Until a final license is adopted, no rights are granted to use, copy, modify, merge, publish,
distribute, sublicense, or sell copies of this software, in whole or in part, except as
separately agreed in writing with Weboria.
separately agreed in writing with the copyright holder.
This software incorporates third-party open-source components under their own licenses;
see THIRD_PARTY_LICENSES.md and NOTICE for details. Nothing in this placeholder alters the
terms of those third-party components.
see THIRD_PARTY_LICENSES and NOTICE for details. Nothing in this placeholder alters the terms
of those third-party components.
TODO before release: replace this file with final commercial/enterprise license text.
+9 -16
View File
@@ -1,25 +1,18 @@
ARGUS Enterprise Web Security Platform
ARGUS Secure
Copyright (c) 2025-2026 AI4SEC / lmelo
Copyright © 2025-2026 Weboria
ARGUS contains third-party open-source software.
The licenses and notices for these components are available in:
THIRD_PARTY_LICENSES.md
This product includes software developed by third parties under their own open-source
licenses. Full license texts and attributions are listed in THIRD_PARTY_LICENSES.
Notable components:
- nginx (BSD-2-Clause) — Copyright (C) 2002-2024 Igor Sysoev, (C) 2011-2024 Nginx, Inc.
- ModSecurity (Apache-2.0) — Copyright (C) 2002-2024 Trustwave Holdings, Inc.
- OWASP Core Rule Set (Apache-2.0) — Copyright (C) 2006-2024 Trustwave Holdings, Inc.,
OWASP Core Rule Set contributors
- TimescaleDB (Timescale License / Apache 2.0 depending on component) — distributed as an
embedded time-series storage component as part of the ARGUS Enterprise Appliance, not
offered as a standalone database service. See THIRD_PARTY_LICENSES.md for detail.
- TimescaleDB Community Edition (Timescale License) — see THIRD_PARTY_LICENSES for
redistribution terms
- MaxMind GeoLite2 (GeoLite2 EULA) — "This product includes GeoLite2 data created by
MaxMind, available from https://www.maxmind.com"
- Valkey (BSD-3-Clause)
- PostgreSQL (PostgreSQL License), Alpine Linux, BusyBox, Go runtime, Node.js (build-time
only), OpenSSL, curl — see THIRD_PARTY_LICENSES.md
The following ARGUS components are proprietary software developed by Weboria and are not
covered by the third-party licenses above: ARGUS Core Platform, ARGUS Management Interface,
ARGUS Security Automation Engine, ARGUS API Layer, ARGUS Threat Analysis Components, ARGUS
Licensing System, ARGUS Enterprise Features, and Weboria Integrations. These are distributed
under the ARGUS Commercial License — see LICENSE.
This repository's own source code is proprietary; see LICENSE.
+64 -119
View File
@@ -1,11 +1,11 @@
<div align="center">
# ARGUS Enterprise Web Security Platform
# ARGUS
### A real-time security operations platform for the modern web edge
### Enterprise Web Security Platform
[![License](https://img.shields.io/badge/License-Commercial-lightgrey?style=for-the-badge)](LICENSE)
[![Platform](https://img.shields.io/badge/Platform-Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white)]()
[![License](https://img.shields.io/badge/License-Proprietary-lightgrey?style=for-the-badge)](LICENSE)
[![Docker](https://img.shields.io/badge/Docker-ready-2496ED?style=for-the-badge&logo=docker&logoColor=white)](https://github.com/alleyviper/argus/pkgs/container/argus-secure-api)
[![Nginx](https://img.shields.io/badge/Nginx-1.30-009639?style=for-the-badge&logo=nginx&logoColor=white)](https://nginx.org/)
[![ModSecurity](https://img.shields.io/badge/ModSecurity-v3-red?style=for-the-badge)](https://modsecurity.org/)
@@ -13,18 +13,16 @@
[![HTTP/3](https://img.shields.io/badge/HTTP/3-QUIC-blue?style=for-the-badge)]()
<p align="center">
<strong>Enterprise-grade protection for the modern web edge — in the same league as Fortinet,
Palo Alto, and F5, purpose-built for how applications are actually attacked today.</strong><br/>
<strong>Reverse proxy. Web Application Firewall. Bot and AI-crawler defense. DNS security.
Real-time threat intelligence. Live attack visualization. Incident investigation. One
appliance, one dashboard, zero blind spots.</strong>
<strong>A real-time security operations platform for the modern web edge.<br/>
Reverse proxy, Web Application Firewall, bot defense, DNS protection, and live threat
investigation — in one appliance.</strong>
</p>
<p align="center">
<a href="#-key-features">✨ Features</a> •
<a href="#-installation">🚀 Installation</a> •
<a href="#-operations">🛠 Operations</a> •
<a href="#-licensing--support">📄 Licensing & Support</a>
<a href="#-api">📚 API</a>
</p>
---
@@ -34,89 +32,52 @@
## ✨ Key Features
### 🛡️ Web Application Firewall
ModSecurity v3 running the full OWASP Core Rule Set, tunable across paranoia levels 14 per
site — start permissive on a new application, tighten as you learn its traffic. Detection-only
or blocking mode per host, per-rule exceptions for known false positives, and a Rule Health
view that tracks which rules are actually earning their keep versus generating noise, so tuning
is based on evidence, not guesswork.
### 🧠 ANIS Threat Intelligence
ARGUS ships connected by default to **ANIS (Argus Network Intelligence Server)**, Weboria's
community-powered reputation network: every ARGUS deployment that opts in contributes
confirmed-attacker IPs and receives the aggregated blocklist back in return, so your appliance
gets smarter from day one using signal from every other protected site — no license key
required for the free Community tier. Every dashboard, investigation view, and auto-ban
decision is enriched with live ANIS reputation scoring. A license key upgrades the tier —
manage it entirely from Threat Intel → ANIS Connection in the dashboard, or turn the
integration off entirely from the same page.
ModSecurity v3 with the OWASP Core Rule Set. Paranoia levels 14, per-host rule exceptions,
detection-only or blocking modes.
### 🌐 Attack Origin Visualization
A live global map of inbound attacks — real-time arcs from source to your infrastructure,
color-coded by severity, with a running feed of top attacking countries and IPs. Pause, rewind,
and replay historical traffic, or click straight through to any single event's full detail.
severity-coded, with instant drill-down into any event's full detail.
### 🔎 Incident Investigation
Pivot from any IP, log line, or dashboard event straight into that entity's complete history —
every affected host it touched, every rule it triggered, its geography and ASN, and its live
ANIS reputation score — all in one place, without losing your position in whatever you were
looking at.
affected hosts, triggered rules, geography, and live threat-intelligence reputation — without
losing your place.
### 🤖 Bot & AI-Crawler Defense
Automatically blocks known-bad bots and scrapers, with a maintained allowlist so legitimate
search engines are never caught in the net. Purpose-built detection for AI crawlers (GPTBot,
ClaudeBot, and similar) lets you choose exactly which ones are welcome. Escalating challenge
modes — silent browser verification, proof-of-work, visual CAPTCHA — apply exactly as much
friction as suspicious traffic actually warrants, backed by a live risk-scoring engine so the
decision is never a coin flip.
Blocks known-bad bots and AI scrapers automatically, with a search-engine allowlist so legitimate
crawlers are never affected. Escalating challenge modes (browser check, proof-of-work, visual
CAPTCHA) for suspicious traffic.
### 🧬 DNS Security Engine
Passive DNS intelligence starts working the moment your first site is protected — no network
reconfiguration required — scoring every domain your traffic touches for DGA patterns,
fast-flux infrastructure, and other red flags, and cross-referencing that against real WAF
activity for a much stronger signal than either check alone. An optional embedded resolver adds
network-wide DNS tunneling detection, NXDOMAIN-flood protection, and automatic sinkholing for
sites that want DNS-layer coverage too.
An embedded forwarding DNS resolver with real-time threat detection — DGA domains, DNS
tunneling, fast-flux infrastructure, cache-poisoning attempts — and automatic mitigation via
sinkholing.
### 🌍 GeoIP & Cloud-Provider Access Control
Allow or block traffic by country or hosting provider, with live visual feedback as you tune
the policy — see exactly what would have been blocked before you commit to it.
Allow or block traffic by country or hosting provider, with live visual feedback.
### 🔒 Automated SSL
Let's Encrypt with automatic renewal, including wildcard certificates via DNS-01 challenge
across major DNS providers (Cloudflare, DuckDNS, Dynu, and more) — certificates that never
expire on your watch.
(Cloudflare, DuckDNS, Dynu, and more).
### ⚡ Rate Limiting & Auto-Ban
Configurable per-IP/per-URI rate limits, automatic banning on repeated WAF violations, and
community-intelligence-driven blocking via ANIS — layered defenses that reinforce each other
rather than working in isolation.
optional community threat-intelligence-driven blocking.
### 👥 Enterprise User Management
Role-based access control, per-user session management, forced password resets, account
lock/unlock as a reversible incident-response tool, mandatory MFA for administrators, and a
complete audit trail of every login and admin action — everything a security team needs to
administer access with confidence.
### 👥 Full User Management
Role-based access, per-user session control, forced password resets, account lock/unlock, MFA,
and a complete login history — everything a security team needs to administer access safely.
### 📊 Real-Time Operations Dashboard
Live traffic, security events, and system health updated continuously — a true operations
console, not a page you have to remember to refresh. Guided, role-based dashboard profiles (SOC
Analyst, Security Administrator, Network Administrator, Executive Overview) put the right view
in front of the right person automatically.
### 🎯 Guided Security Policy Center
Every protection module — WAF, DNS, GeoIP, Bot Protection, Rate Limiting, SSL/TLS, and more —
comes with one-click policy tiers from Home to Maximum Protection, a plain-language impact
preview before you apply anything, and an honest posture score that tells you exactly what's
configured, what's missing, and why it matters. No security expertise required to deploy with
confidence.
Live traffic, security events, and system health, updated continuously — no manual refresh.
### 🔀 Load Balancing & Stream Proxying
Multiple backend servers with active health checks, plus TCP/UDP stream proxying with optional
SNI routing for non-HTTP services.
Multiple backend servers with health checks, plus TCP/UDP stream proxying with optional SNI
routing.
### 🔮 Modern Protocol Support
HTTP/3 (QUIC) and post-quantum-ready TLS (ML-KEM hybrid key exchange) — ready for where the web
is headed, not just where it's been.
HTTP/3 (QUIC) and post-quantum-ready TLS (ML-KEM hybrid key exchange).
---
@@ -124,20 +85,18 @@ is headed, not just where it's been.
### Requirements
- A Linux host with Docker Engine 24.0+ and the Docker Compose plugin (`docker compose`)
- 2 vCPU / 4 GB RAM minimum for evaluation; see production sizing guidance in `docs/` for
real traffic volumes
- A Linux host with Docker 24.0+ and the Docker Compose plugin (`docker compose`)
- Ports 80/443 available for the reverse proxy, and 81 for the admin panel (all configurable)
### One-line install
```bash
curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/install.sh | bash
```
This downloads the deployment files, generates secure database/application secrets, creates the
This downloads the deployment files, generates a secure database password, creates the
required Docker network, pulls the production images, starts ARGUS, and prints your admin
login at the end. Installs to `/opt/argus` by default — set `ARGUS_INSTALL_DIR` first to change
login at the end. Installs to `~/argus` by default — set `ARGUS_INSTALL_DIR` first to change
that.
### Manual install
@@ -145,13 +104,13 @@ that.
If you'd rather see every step:
```bash
mkdir -p /opt/argus/docker-socket-proxy && cd /opt/argus
curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/docker-compose.yml -o docker-compose.yml
curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/env.example -o .env
curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/docker-socket-proxy/haproxy.cfg.template -o docker-socket-proxy/haproxy.cfg.template
mkdir -p ~/argus/docker-socket-proxy && cd ~/argus
curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/docker-compose.yml -o docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/.env.example -o .env
curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/docker-socket-proxy/haproxy.cfg.template -o docker-socket-proxy/haproxy.cfg.template
# Generate a secure database password
sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=$(openssl rand -hex 32)/" .env
sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=$(openssl rand -base64 24)/" .env
# ARGUS expects this network to already exist
docker network create argus-network
@@ -160,30 +119,19 @@ docker compose pull
docker compose up -d
```
Then log in at `https://<your-server-address>:81` with `admin` / `admin` and change the password
Then log in at `https://localhost:81` with `admin` / `admin` and change the password
immediately — the one-line installer does this rotation for you automatically.
**Do not expose the admin panel (port 81) to the internet.** Keep it on your LAN/VPN, or put
it behind its own proxy host with access lists and 2FA enabled.
### Next steps after install
1. Open the administration panel at the access URL printed at the end of install.
2. Complete the first-run setup wizard — regional settings and a guided review of every
protection module.
3. Confirm your administrator password was rotated (the installer does this automatically).
4. Configure domains and reverse proxy hosts under **Proxy Hosts**.
5. Review the ANIS threat intelligence connection under **Threat Intel** — on by default
against the public Community Edition hub.
6. Review security policies in the **Security Policy Center**.
---
## 🛠 Operations
All lifecycle management is Docker-based — five scripts cover day-to-day operation, downloaded
once alongside `docker-compose.yml` (the one-line installer already does this for you), then run
from `/opt/argus` (or wherever you installed):
Five scripts cover day-to-day operation download them once alongside `docker-compose.yml`
(the one-line installer already does this for you), then run from `~/argus` (or wherever you
installed):
| Script | Purpose |
|--------|---------|
@@ -193,24 +141,21 @@ from `/opt/argus` (or wherever you installed):
| `./restore.sh <archive>` | Restore a backup onto a fresh installation |
| `./uninstall.sh [--remove-data]` | Stop ARGUS; data is kept unless you explicitly opt in to removing it |
You never manually download application files or modify containers directly — every update is
delivered as a new published image version.
### Upgrading
```bash
cd /opt/argus
docker compose pull
docker compose up -d
cd ~/argus
./update.sh
```
(`./update.sh` wraps the same two commands with a before/after version check.) This is the only
supported upgrade path; there is no separate migration step to run.
New versions are published to GHCR as soon as they're released — `update.sh` always pulls the
current stable release. This is the only supported upgrade path; there is no separate migration
step to run.
### Backups
```bash
cd /opt/argus
cd ~/argus
./backup.sh # writes argus-backup-<timestamp>.tar.gz to the current directory
./restore.sh <archive> # onto a fresh installation only — see the script's own header
```
@@ -225,13 +170,12 @@ Add `--username <name>` to target a specific account, or `--password '...'` to s
value instead of generating one. See `docker compose exec api ./server reset-password --help`
for the rest of the options (clearing 2FA, etc.).
### Threat intelligence integration
### Threat intelligence integration (optional)
ARGUS connects to **ANIS**, Weboria's threat-intelligence hub, to share confirmed attacker IPs
and receive a community blocklist in return. Enabled by default against the public Community
Edition hub — no license key required. Set `ANIS_ENABLED=false` in `.env` to turn this off
entirely. A license key upgrades the tier — set it from Threat Intel → ANIS Connection in the
dashboard, not from `.env`.
ARGUS can connect to **ANIS**, a separately-deployed threat-intelligence hub, to share confirmed
attacker IPs and receive a community blocklist in return. It's off by default — set
`ANIS_ENABLED=true` and `ANIS_URL` in `.env` to turn it on. See the comments in `.env.example`
for the full set of options.
---
@@ -240,7 +184,7 @@ dashboard, not from `.env`.
ARGUS exposes a full REST API for automation. Authenticate with a JWT (`POST
/api/v1/auth/login`) for interactive use, or an API token (`Authorization: Bearer ng_<token>`,
created from the admin panel) for CI/CD and scripted access. Interactive API documentation is
served at `https://<your-server-address>:81/api/docs` once ARGUS is running.
served at `https://localhost:81/api/docs` once ARGUS is running.
---
@@ -254,23 +198,24 @@ served at `https://<your-server-address>:81/api/docs` once ARGUS is running.
| `NGINX_HTTP_PORT` / `NGINX_HTTPS_PORT` | Reverse-proxy listen ports | `80` / `443` |
| `API_HOST_PORT` | Internal API port exposed to the host | `9080` |
| `DNS_LISTEN_HOST` | DNS Security Engine bind address | `127.0.0.1` |
| `ANIS_ENABLED` | Threat-intel hub integration | `true` |
| `ANIS_ENABLED` / `ANIS_URL` | Optional threat-intel hub integration | `false` / *(empty)* |
Full list with descriptions in `env.example`. ANIS's URL is fixed (`https://anis.weboria.eu`,
not configurable) and its license key is dashboard-only — neither is an env var.
Full list with descriptions in `.env.example`.
---
## 📄 Licensing & Support
## 📄 License
ARGUS is commercial software licensed by Weboria — see [LICENSE](LICENSE). Third-party
open-source components retain their own licenses — see
[THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md) and [NOTICE](NOTICE).
This is proprietary, commercial software — see [LICENSE](LICENSE). Third-party open-source
components retain their own licenses — see [THIRD_PARTY_LICENSES](THIRD_PARTY_LICENSES) and
[NOTICE](NOTICE).
For licensing questions or support, contact the **Weboria Support Portal**.
## 💬 Support
[GitHub Issues](https://github.com/alleyviper/argus/issues) — bug reports and feature requests.
---
<div align="center">
<sub>© 2025-2026 Weboria. ARGUS Enterprise Web Security Platform.</sub>
<sub>© 2025-2026 ARGUS — AI4SEC.</sub>
</div>
@@ -1,26 +1,16 @@
# Third-Party Licenses
ARGUS uses the following third-party software.
ARGUS Secure uses the following third-party software:
## Core Components
### TimescaleDB
- **License**: Timescale License (TSL) / Apache 2.0 depending on component
- **Website**: https://www.timescale.com/
ARGUS uses TimescaleDB as an embedded time-series storage component for security events,
telemetry, and operational metrics.
TimescaleDB is distributed as part of the ARGUS Enterprise Appliance and is not offered as a
standalone database service. Customers receive ARGUS as a complete security appliance;
TimescaleDB remains subject to its original license terms.
### PostgreSQL
- **License**: PostgreSQL License (permissive, BSD/MIT-style)
- **Website**: https://www.postgresql.org/
TimescaleDB is distributed as a PostgreSQL extension; PostgreSQL itself is the underlying
database engine.
- **License**: Timescale License (TSL)
- **Website**: https://github.com/timescale/timescaledb
- **License URL**: https://github.com/timescale/timescaledb/blob/main/tsl/LICENSE-TIMESCALE
- **Note**: TimescaleDB Community Edition is used for time-series data storage and compression.
The Timescale License carries redistribution conditions beyond plain open source — reviewed
before bundling with a commercial, proprietary product; see legal review note below.
### Nginx
- **License**: BSD-2-Clause
@@ -37,46 +27,17 @@ database engine.
- **Website**: https://coreruleset.org/
- **Copyright**: (C) 2006-2024 Trustwave Holdings, Inc., OWASP Core Rule Set contributors
### MaxMind GeoIP2 / GeoLite2
- **License**: GeoLite2 End User License Agreement
- **Website**: https://www.maxmind.com/
- **Attribution**: This product includes GeoLite2 data created by MaxMind, available from
https://www.maxmind.com. Redistribution terms are stricter than plain open source — reviewed
before bundling; see legal review note below.
### Valkey
- **License**: BSD-3-Clause
- **Website**: https://valkey.io/
### Alpine Linux
- **License**: Various (base OS, mostly MIT/BSD-style per-package licenses)
- **Website**: https://alpinelinux.org/
Alpine Linux is the base image for the ARGUS API, UI build, and proxy container images.
### BusyBox
- **License**: GPL-2.0
- **Website**: https://busybox.net/
Bundled as part of the Alpine Linux base images above.
### Go Runtime
- **License**: BSD-3-Clause
- **Website**: https://go.dev/
The ARGUS API is built with Go; the compiled binary statically includes the Go runtime.
### Node.js (build-time only)
- **License**: MIT (Node.js core) plus per-package licenses of the npm dependencies below
- **Website**: https://nodejs.org/
Used to build the ARGUS web UI; not present in the running API/proxy containers.
### OpenSSL / TLS libraries
- **License**: Apache License 2.0 (OpenSSL 3.x) / various
- **Website**: https://www.openssl.org/
Used by the nginx proxy image for TLS termination.
### curl
- **License**: MIT/X derivate (curl license)
- **Website**: https://curl.se/
Used in container healthchecks and installer scripts.
## Backend (Go) Dependencies
| Package | License | Website |
@@ -86,6 +47,7 @@ Used in container healthchecks and installer scripts.
| github.com/lib/pq | MIT | https://github.com/lib/pq |
| github.com/google/uuid | BSD-3-Clause | https://github.com/google/uuid |
| github.com/redis/go-redis/v9 | BSD-2-Clause | https://github.com/redis/go-redis |
| github.com/oschwald/geoip2-golang | ISC | https://github.com/oschwald/geoip2-golang |
| github.com/cloudflare/cloudflare-go | BSD-3-Clause | https://github.com/cloudflare/cloudflare-go |
| golang.org/x/crypto | BSD-3-Clause | https://golang.org/x/crypto |
@@ -134,25 +96,17 @@ limitations under the License.
---
Third-party components have been reviewed for inclusion in ARGUS Enterprise deployments.
Each component remains subject to its original license terms.
## GeoLite2 End User License Agreement
This product includes GeoLite2 data created by MaxMind, available from
https://www.maxmind.com. GeoLite2 databases are offered under the
GeoLite2 End User License Agreement. For the full license text, see:
https://www.maxmind.com/en/geolite2/eula
---
# Weboria Proprietary Components
## Pending legal review before commercial distribution
The following ARGUS components are proprietary software developed by Weboria:
- ARGUS Core Platform
- ARGUS Management Interface
- ARGUS Security Automation Engine
- ARGUS API Layer
- ARGUS Threat Analysis Components
- ARGUS Licensing System
- ARGUS Enterprise Features
- Weboria Integrations
These components are distributed under the ARGUS Commercial License.
Unauthorized copying, modification, redistribution, reverse engineering, or resale is
prohibited.
TimescaleDB (Community Edition, TSL) and MaxMind GeoLite2 (EULA) both carry redistribution
conditions beyond plain MIT/BSD/Apache terms. Confirm these terms are compatible with the
proprietary commercial license in `LICENSE` before shipping a release build.
+3 -3
View File
@@ -3,11 +3,11 @@
# ARGUS backup — dumps the database and application data (certificates,
# uploaded config) into a single, timestamped archive.
#
# cd /opt/argus && ./backup.sh [output-directory]
# cd ~/argus && ./backup.sh [output-directory]
#
set -euo pipefail
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
OUT_DIR="${1:-$PWD}"
STAMP="$(date +%Y%m%d-%H%M%S)"
ARCHIVE="${OUT_DIR}/argus-backup-${STAMP}.tar.gz"
@@ -24,7 +24,7 @@ bold "Backing up ARGUS..."
WORKDIR="$(mktemp -d)"
trap 'rm -rf "$WORKDIR"' EXIT
docker compose exec -T db pg_dump -U postgres argus | gzip > "$WORKDIR/db.sql.gz"
docker compose exec -T db pg_dump -U "${DB_USER:-postgres}" "${DB_NAME:-argus}" | gzip > "$WORKDIR/db.sql.gz"
ok "Database dumped"
docker run --rm -v argus_api_data:/data -v "$WORKDIR":/backup alpine \
+14 -30
View File
@@ -11,18 +11,14 @@ services:
max-file: "3"
environment:
TZ: ${TZ:-UTC}
# Internal database credentials, not customer-configurable — nothing
# outside this compose stack ever connects to Postgres directly, so
# there's no real reason to let these vary. Only the password (below)
# needs to be a real secret; the username/db name are just labels.
POSTGRES_USER: postgres
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
POSTGRES_DB: argus
POSTGRES_DB: ${DB_NAME:-argus}
command: postgres -c timezone=${TZ:-UTC} -c log_timezone=${TZ:-UTC} -c shared_preload_libraries=timescaledb -c timescaledb.telemetry_level=off -c max_locks_per_transaction=512
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"]
interval: 10s
timeout: 5s
retries: 10
@@ -84,7 +80,7 @@ services:
# Go API Server
api:
image: git-cloud.weboria.eu/weboria/argus-api:latest
image: ghcr.io/alleyviper/argus-secure-api:latest
container_name: argus-api
restart: unless-stopped
# Container hardening: no-new-privileges blocks setuid privilege
@@ -108,14 +104,7 @@ services:
environment:
TZ: ${TZ:-UTC}
PORT: "8080"
# DATABASE_URL is not set here — the API builds it internally from
# DB_PASSWORD using net/url (proper percent-encoding), instead of this
# file naively interpolating the password into a raw connection
# string. A raw '${DB_PASSWORD}@...' interpolation breaks outright if
# the password ever contains '@', ':', '/', or similar (confirmed
# live: an openssl-rand-base64-generated password containing '/'
# produced an unparseable URL and the API never became healthy).
DB_PASSWORD: ${DB_PASSWORD:-postgres}
DATABASE_URL: postgres://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@db:5432/${DB_NAME:-argus}?sslmode=disable
REDIS_URL: redis://valkey:6379/0
ENVIRONMENT: ${ENVIRONMENT:-production}
NGINX_CONTAINER: argus-proxy
@@ -130,19 +119,13 @@ services:
API_HOST_PORT: ${API_HOST_PORT:-9080}
API_HOST: ${API_HOST:-}
# ANIS community intelligence — on by default against the public
# Community Edition hub (community tier, no signup required). There is
# no self-hosted-ANIS deployment model: the URL is fixed, not
# customer-configurable. A license key upgrades the tier, but is only
# ever set from Threat Intel -> ANIS Connection in the dashboard
# (write-only there — never round-trips back to the client), not from
# this file, so it's seeded empty (community tier) here.
# (No ANIS_ADMIN_KEY or ANIS_SHARE_ATTACKERS here: both confirmed dead
# via grep, zero references anywhere in internal/config.go or the ANIS
# client. A prior version of this file carried ANIS_ADMIN_KEY and
# falsely claimed ARGUS "fails closed at startup" without it.)
# Community Edition hub (empty license key = community tier, no signup
# required). Set ANIS_URL to your own self-hosted ANIS instead if you
# run one, or ANIS_ENABLED=false to turn this off entirely.
ANIS_ENABLED: ${ANIS_ENABLED:-true}
ANIS_URL: https://anis.weboria.eu
ANIS_LICENSE_KEY: ""
ANIS_URL: ${ANIS_URL:-https://anis.weboria.eu}
ANIS_LICENSE_KEY: ${ANIS_LICENSE_KEY:-}
ANIS_SHARE_ATTACKERS: ${ANIS_SHARE_ATTACKERS:-false}
DNS_SECURITY_LISTEN_ADDR: ":53"
ports:
- "127.0.0.1:${API_HOST_PORT:-9080}:8080"
@@ -172,7 +155,7 @@ services:
# React UI (Admin Panel), served over HTTPS
ui:
image: git-cloud.weboria.eu/weboria/argus-ui:latest
image: ghcr.io/alleyviper/argus-secure-ui:latest
container_name: argus-ui
restart: unless-stopped
security_opt:
@@ -198,7 +181,7 @@ services:
# Nginx reverse proxy — host network mode, so real client IPs are visible
# directly without needing PROXY protocol.
nginx:
image: git-cloud.weboria.eu/weboria/argus-proxy:latest
image: ghcr.io/alleyviper/argus-secure-nginx:latest
container_name: argus-proxy
restart: always
network_mode: host
@@ -214,6 +197,7 @@ services:
max-file: "5"
environment:
TZ: ${TZ:-UTC}
UI_PORT: ${UI_PORT:-81}
ulimits:
nofile:
soft: 65535
-64
View File
@@ -1,64 +0,0 @@
# ARGUS Enterprise Web Security Platform — Installation Configuration
#
# install.sh generates this file for you automatically, including a secure
# database password. Most installs need nothing beyond the defaults below.
#
# Everything else — WAF policy, DNS security, threat intelligence tuning,
# proxy hosts, users, security policies — is configured from the ARGUS
# dashboard after your first login, not from this file.
# ===========================================
# Database (do not edit)
# ===========================================
# install.sh replaces this with a securely generated value on first install
# and never touches it again. There's nothing to fill in here yourself.
DB_PASSWORD=change-me-in-production
# ===========================================
# Timezone
# ===========================================
# Should match the timezone you select in the dashboard's first-run setup
# wizard (Regional Settings) — the wizard checks for a mismatch and will
# warn you if this file and your dashboard selection disagree.
TZ=UTC
# ===========================================
# Threat Intelligence (ANIS)
# ===========================================
# ARGUS connects to ANIS, Weboria's threat-intelligence network, by default
# — no license key needed for the free Community tier. There is no
# self-hosted-ANIS deployment model, so there's no URL to configure here.
# A license key upgrades the tier, but is only ever set from
# Threat Intel -> ANIS Connection in the dashboard — never from this file.
ANIS_ENABLED=true
# ===========================================
# Network Ports
# ===========================================
# Only change these if the defaults conflict with something else already
# running on this host.
# Admin panel port (default: 81)
# UI_PORT=81
# Reverse-proxy listen ports — change if 80/443 are already in use
# NGINX_HTTP_PORT=8080
# NGINX_HTTPS_PORT=8443
# Internal port used for nginx<->API communication.
# MUST NOT conflict with NGINX_HTTP_PORT.
# API_HOST_PORT=9080
# DNS Security Engine listen address — host-only (127.0.0.1) by default.
# Set to an internal interface IP only if you intend to route real client
# DNS traffic through ARGUS. Never 0.0.0.0 unless this host is on a fully
# trusted network — an open forwarding resolver is exactly the profile
# abused for DNS amplification attacks against third parties.
# DNS_LISTEN_HOST=127.0.0.1
# ===========================================
# Advanced / Troubleshooting
# ===========================================
# Only needed on some NAS platforms (e.g. Synology DSM) where Docker's API
# version needs to be pinned manually. Leave commented out otherwise.
# DOCKER_API_VERSION=1.41
+2 -2
View File
@@ -2,11 +2,11 @@
#
# ARGUS health check — reports the status of every component.
#
# cd /opt/argus && ./healthcheck.sh
# cd ~/argus && ./healthcheck.sh
#
set -euo pipefail
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
bold() { printf '\033[1m%s\033[0m\n' "$1"; }
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
+19 -76
View File
@@ -1,20 +1,15 @@
#!/usr/bin/env bash
#
# ARGUS Enterprise Web Security Platform — installer. Fetches the production
# compose stack, generates secrets, starts the platform, and prints your
# admin credentials.
# ARGUS installer — fetches the production compose stack, generates secrets,
# starts the platform, and prints your admin credentials.
#
# curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/install.sh | bash
# curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/install.sh | bash
#
set -euo pipefail
REPO_RAW_BASE="https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
REPO_RAW_BASE="https://raw.githubusercontent.com/alleyviper/argus/main"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
NETWORK_NAME="argus-network"
# Production images are pulled from Weboria's own registry, built into
# git-cloud.weboria.eu (Gitea's container registry) — docker-compose.yml's
# image: lines reference git-cloud.weboria.eu/weboria/argus-{api,ui,proxy}
# directly. Anonymous docker pull works with no login required.
# ── Output helpers ────────────────────────────────────────────────────────────
bold() { printf '\033[1m%s\033[0m\n' "$1"; }
@@ -54,29 +49,16 @@ for script in update.sh uninstall.sh healthcheck.sh backup.sh restore.sh; do
fetch "$script" "$script"
chmod +x "$script"
done
# The repo stores this as env.example (no leading dot) rather than .env.example
# -- Weboria's own WAF blocks any request path matching .env* as a standard
# credential-harvesting-probe rule, which also caught this legitimate static
# file when served from Gitea. Renaming sidesteps it without needing a WAF
# exception. Saved locally as .env either way.
if [ ! -f .env ]; then
fetch "env.example" ".env"
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) ──
# hex, not base64: base64 can produce '/', '+', '=', any of which breaks the
# raw postgres://user:PASSWORD@host connection string if it ever ends up
# interpolated unescaped (confirmed live on the first real production
# install — see config.go's buildDatabaseURL for the second, independent
# defensive layer this pairs with). Hex output is always [0-9a-f], which
# can never produce that class of bug, at 4 bits/char vs base64's ~6 —
# 32 hex chars (128 bits) is used in place of 24 base64 chars (~144 bits)
# to keep entropy comparable rather than matching digit-count cosmetically.
if grep -q '^DB_PASSWORD=change-me-in-production' .env 2>/dev/null; then
DB_PASSWORD="$(openssl rand -hex 32)"
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
@@ -115,63 +97,24 @@ if [ "$READY" != "true" ]; then
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 ─────────────────────────────────────────────────────────────────
# ── 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 Enterprise Web Security Platform has been successfully installed."
bold "ARGUS is installed and running."
echo
info "Access URL: https://$(hostname -I 2>/dev/null | awk '{print $1}' || echo 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
bold "Next steps:"
info "1. Open the administration panel at the Access URL above."
if [ "$CREDS_ROTATED" != "true" ]; then
info "2. Complete the first-run setup wizard (regional settings, guided protection checklist)."
info "3. Change the initial administrator password if you haven't already."
else
info "2. Complete the first-run setup wizard — regional settings and a guided review of every"
info " protection module (your admin password was already rotated above)."
fi
info "4. Configure domains and reverse proxy hosts under Proxy Hosts."
info "5. Review the ANIS threat intelligence connection under Threat Intel — enabled by"
info " default against the public Community Edition hub, no license key required."
info "6. Review security policies in the Security Policy Center."
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 "Backup: cd ${INSTALL_DIR} && ./backup.sh"
info "Docs/support: see README.md in this directory"
info "Backups: see https://github.com/alleyviper/argus#backups"
echo
+3 -3
View File
@@ -5,11 +5,11 @@
# that already has data on it, uninstall.sh --remove-data && install.sh
# first, then run this.
#
# cd /opt/argus && ./restore.sh argus-backup-20260719-120000.tar.gz
# cd ~/argus && ./restore.sh argus-backup-20260719-120000.tar.gz
#
set -euo pipefail
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
ARCHIVE="${1:-}"
bold() { printf '\033[1m%s\033[0m\n' "$1"; }
@@ -38,7 +38,7 @@ bold "Stopping the API (keeping the database up)..."
docker compose stop api ui nginx >/dev/null
bold "Restoring database..."
gunzip -c "$WORKDIR/db.sql.gz" | docker compose exec -T db psql -U postgres argus >/dev/null
gunzip -c "$WORKDIR/db.sql.gz" | docker compose exec -T db psql -U "${DB_USER:-postgres}" "${DB_NAME:-argus}" >/dev/null
ok "Database restored"
bold "Restoring application data..."
+2 -2
View File
@@ -6,13 +6,13 @@
# it only stops and removes containers, so a plain re-install (install.sh)
# picks up right where you left off.
#
# cd /opt/argus && ./uninstall.sh # containers only, data kept
# cd ~/argus && ./uninstall.sh # containers only, data kept
# ./uninstall.sh --remove-data # also destroys all data (asks to confirm)
# ./uninstall.sh --remove-data --yes # non-interactive, for scripted use
#
set -euo pipefail
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
REMOVE_DATA=false
ASSUME_YES=false
+4 -5
View File
@@ -1,15 +1,14 @@
#!/usr/bin/env bash
#
# ARGUS Enterprise Web Security Platform — updater. Pulls the latest
# published images and restarts the stack.
# ARGUS updater — pulls the latest published images and restarts the stack.
#
# cd /opt/argus && ./update.sh
# cd ~/argus && ./update.sh
# (or, if you don't have it locally yet)
# curl -fsSL https://git-cloud.weboria.eu/weboria/argus-installer/raw/branch/main/update.sh | bash
# curl -fsSL https://raw.githubusercontent.com/alleyviper/argus/main/update.sh | bash
#
set -euo pipefail
INSTALL_DIR="${ARGUS_INSTALL_DIR:-/opt/argus}"
INSTALL_DIR="${ARGUS_INSTALL_DIR:-$HOME/argus}"
bold() { printf '\033[1m%s\033[0m\n' "$1"; }
info() { printf ' %s\n' "$1"; }