/
Admin Reference
v2.2 User guide → ← Dashboard
// QUICK REFERENCE
Start / Stop / Restart
sudo systemctl start|stop|restart guarddex
Service status
sudo systemctl status guarddex
Tail live logs
sudo journalctl -u guarddex -f
Last 100 log lines
sudo journalctl -u guarddex -n 100
Health check
curl http://localhost:8088/health
Run verify script
bash /opt/Guarddex0/verify.sh
Edit config
sudo nano /opt/Guarddex0/.env
DB connect (Docker)
docker exec -it data-postgres psql -U guarddex_user -d guarddex_db
DB connect (native)
psql -U guarddex_user -d guarddex_db
DB backup
pg_dump guarddex_db > guarddex_$(date +%Y%m%d).sql
Build APK
bash /opt/Guarddex0/build-apk.sh
Build extension
bash /opt/Guarddex0/extension/scripts/build.sh
Cockpit (browser)
http://<SERVER_IP>:9090
Post-install setup
bash /opt/Guarddex0/hpt430-master-setup.sh

Port Map 192.168.50.138

PortServiceUnit
8088GuardDex API + Dashboardguarddex.service
8089Attack Studioguarddex-attackstudio.service
9090TestBench (mothership) / Cockpit (battleship)guarddex-testbench.service / cockpit.service
5433PostgreSQL (Docker: data-postgres)data-postgres container
5432PostgreSQL (native battleship / gaming-postgres)postgresql.service
6379Redisdata-redis container / redis.service
11434Ollama (mothership only)ollama.service
3001BeEF Frameworkmanual
8000TTS Studio backend (reserved)Docker

Requirements

ItemMinimumNotes
RAM4 GBinstall.sh hard-stops at <2 GB, warns at <3.5 GB
Disk10 GB free20 GB+ recommended if running Ollama
OSUbuntu 22.04/24.04, Debian 12/1364-bit only. Debian 13 (Trixie) minimal server recommended for new battleship installs.
Python3.11+installed by install.sh
Node.js22 (LTS)needed for APK builds only
Java21needed for APK builds only — JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
NetworkStatic LAN IPclients must reliably reach the server

Supported hardware: Lenovo ThinkPad T430, Dell Wyse 5070, Raspberry Pi 4/5 (4 GB+). Not supported: Pi 3B/3B+ (insufficient RAM).

Installation

Battleship package (recommended)

# On this machine — build the deployment tarball
bash /opt/Guarddex0/make-battleship-package.sh
# Copies to: guarddex-battleship-YYYYMMDD.tar.gz (~4 MB)

# SCP to target node
scp guarddex-battleship-*.tar.gz user@TARGET_IP:~

# On target node
tar -xzf guarddex-battleship-*.tar.gz && cd guarddex-battleship-*/
sudo bash install.sh

What install.sh prompts for (v1.2)

  1. Server name + Public URL (auto-detected from hostname -I)
  2. Admin email, password (with confirmation re-type), and optional admin settings PIN (with confirmation)
  3. ntfy server URL, username, password (push notifications)
  4. HIBP (HaveIBeenPwned) API key — optional, enables breach monitor
  5. VirusTotal API key — optional, improves URL threat scoring
  6. NextDNS API key + profile ID — optional, auto-adds blocked domains to DNS denylist
  7. SMTP credentials for email alerts (optional)
  8. Anthropic API key — write-only (not displayed), required for AI on battleships without Ollama
Key presets (battleship package) When using make-battleship-package.sh, shareable API keys (Anthropic, VT, HIBP, OTX, GreyNoise, Shodan, etc.) are bundled in a keys-preset.env file inside the tarball. install.sh loads them automatically and shows [preset] at each prompt — just press Enter to accept. The preset file is deleted after .env is written.

What install.sh does (in order)

  1. RAM check — aborts if <2 GB, warns if <4 GB
  2. Loads keys-preset.env if present (battleship package)
  3. apt install: python3, pip, postgresql, redis, nmap (no Node.js on battleship)
  4. Creates Python venv at /opt/guarddex/venv, pip install -r requirements.txt
  5. Creates .env from prompts + presets
  6. Creates PostgreSQL user + database; grants schema privileges (PG15+ compatible)
  7. Runs python3 backend/init_db.py — creates all tables including LAN scanner + breach tables
  8. Creates admin user + NotificationPrefs row via API bootstrap script
  9. Writes and enables guarddex.service systemd unit with ExecStartPre that auto-updates PUBLIC_URL in .env from current LAN IP on every boot
  10. Waits up to 24 seconds for service to start (retry loop), then tails first 20 log lines
  11. Deletes keys-preset.env if present
Password characters PostgreSQL connection URL does not support @, #, or $ in the password field — they break URL parsing. Use alphanumeric + -_!. only.

Post-install Configuration

First login

http://<SERVER_IP>:8088/dashboard/login.html

Log in as the admin account you created during install. Go to Profile to confirm notification preferences are saved.

ntfy provisioning QR

Visit /dashboard/provision.html — this generates a QR code family members scan to subscribe their ntfy app automatically. Share this page URL or take a screenshot of the QR.

Verify the admin account is flagged as admin

SELECT email, is_admin FROM users;
-- If is_admin = false for admin account:
UPDATE users SET is_admin = true WHERE email = '[email protected]';

Cockpit — browser-based system monitor

Cockpit provides CPU, RAM, disk, network, logs, and a browser terminal. Available at http://<SERVER_IP>:9090. A shortcut is in the Admin Settings page Quick Links bar. Log in with your OS user credentials.

sudo apt install cockpit -y && sudo systemctl enable --now cockpit.socket

Dynamic MOTD (login message)

If hpt430-master-setup.sh was run before install.sh, the server displays a GuardDex status banner after every SSH login showing CPU, RAM, disk, service states, and fail2ban ban counts.

Verify Installation

bash /opt/Guarddex0/verify.sh

Runs 11 checks: RAM, systemd service, PostgreSQL (native or Docker), Redis (native or Docker), nmap, /health, register, login, notification prefs, URL scan, AI status. All should show [PASS]. A 3 GB machine will show 1 warning (RAM) — expected.

Mothership vs battleship verify.sh auto-detects Docker vs native PostgreSQL/Redis. On the mothership it checks data-postgres and data-redis containers; on battleships it checks native systemd services.

Service Management systemd

sudo systemctl start   guarddex      # start
sudo systemctl stop    guarddex      # stop
sudo systemctl restart guarddex      # restart (after .env changes)
sudo systemctl reload  guarddex      # reload config without full restart (if supported)
sudo systemctl status  guarddex      # current state + last few log lines
sudo systemctl enable  guarddex      # auto-start on boot
sudo systemctl disable guarddex      # remove from boot

Unit file location

/etc/systemd/system/guarddex.service

After editing the unit file: sudo systemctl daemon-reload && sudo systemctl restart guarddex

Other services

sudo systemctl restart guarddex-attackstudio   # Attack Studio :8089
sudo systemctl restart guarddex-testbench      # TestBench :9090
sudo systemctl restart postgresql              # native PostgreSQL (battleship)
sudo systemctl restart redis                   # native Redis (battleship)
docker restart data-postgres                   # Docker PostgreSQL (mothership)
docker restart data-redis                      # Docker Redis (mothership)

Logs & Monitoring

Live log tail

sudo journalctl -u guarddex -f

Time-scoped

sudo journalctl -u guarddex --since "1 hour ago"
sudo journalctl -u guarddex --since "2026-05-02 08:00" --until "2026-05-02 10:00"

Filter by severity

sudo journalctl -u guarddex -p err -n 50    # errors only
sudo journalctl -u guarddex -p warning -f   # warnings + errors, live

JSON scan stats

cat /opt/Guarddex0/guarddex_stats.json | python3 -m json.tool

AI status

curl -s http://localhost:8088/api/v1/analytics/ai-status | python3 -m json.tool

Recent scans (database)

SELECT url, verdict, created_at FROM url_scans ORDER BY created_at DESC LIMIT 20;

Recent alerts (database)

SELECT alert_type, severity, description, created_at FROM alerts ORDER BY created_at DESC LIMIT 20;

Upgrading

Standard upgrade (same node)

cd /opt/Guarddex0
sudo systemctl stop guarddex

# Pull latest source (if using git)
git pull origin main

# Or SCP a new battleship package and extract over the existing directory
# (only replaces backend/ and dashboard/ — .env is preserved)

# Upgrade Python dependencies
venv/bin/pip install -r backend/requirements.txt --quiet

# Run DB migrations if any (check CHANGES file first)
PYTHONPATH=backend venv/bin/python3 backend/init_db.py

sudo systemctl start guarddex
sudo journalctl -u guarddex -n 30   # verify clean startup
Always check the changelog first Some upgrades require .env changes (new variables) or manual DB steps. Read docs/CHANGES_*.md before upgrading.

Rebuild blocklist rules after updating gd_blocklist.txt

python3 /opt/Guarddex0/extension/scripts/generate_rules.py
# Then rebuild extension zip
bash /opt/Guarddex0/extension/scripts/build.sh

Backup & Restore

Full backup script (run as cron or manually)

BACKUP_DIR="/opt/backups/guarddex/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Database dump
pg_dump -U guarddex_user guarddex_db > "$BACKUP_DIR/guarddex_db.sql"
# Or via Docker:
docker exec data-postgres pg_dump -U guarddex_user guarddex_db > "$BACKUP_DIR/guarddex_db.sql"

# Config and stats
cp /opt/Guarddex0/.env              "$BACKUP_DIR/env.bak"
cp /opt/Guarddex0/guarddex_stats.json "$BACKUP_DIR/"
cp /opt/Guarddex0/guarddex_alerts.json "$BACKUP_DIR/"

echo "Backup complete → $BACKUP_DIR"

Restore from backup

# Restore .env first, then DB
sudo systemctl stop guarddex
cp /opt/backups/guarddex/20260502/env.bak /opt/Guarddex0/.env

# Native PostgreSQL
psql -U guarddex_user -d guarddex_db < /opt/backups/guarddex/20260502/guarddex_db.sql

# Docker PostgreSQL
docker exec -i data-postgres psql -U guarddex_user -d guarddex_db \
  < /opt/backups/guarddex/20260502/guarddex_db.sql

sudo systemctl start guarddex

User Management database

List all users

SELECT id, email, full_name, is_admin, created_at FROM users ORDER BY created_at;

Grant admin

UPDATE users SET is_admin = true WHERE email = '[email protected]';

Reset a user's password

# Generate bcrypt hash
python3 -c "from passlib.context import CryptContext; \
  print(CryptContext(schemes=['bcrypt']).hash('NewPassword123!'))"

# Apply it
UPDATE users SET hashed_password = '<hash_output>' WHERE email = '[email protected]';

Delete a user and their data

BEGIN;
DELETE FROM notification_prefs WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]');
DELETE FROM url_scans           WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]');
DELETE FROM alerts              WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]');
DELETE FROM users WHERE email = '[email protected]';
COMMIT;

View a user's scan history

SELECT url, verdict, confidence, created_at
FROM url_scans
WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]')
ORDER BY created_at DESC LIMIT 50;

Check notification preferences

SELECT u.email, n.ntfy_enabled, n.ntfy_topic, n.email_enabled, n.sms_enabled
FROM notification_prefs n JOIN users u ON u.id = n.user_id;

Battleship Node Deployment new in v2.1

A battleship is a lean GuardDex node for a family member or remote office. It runs the API and dashboard but not Ollama or Attack Studio. AI falls back to Claude Haiku.

Build package on mothership

bash /opt/Guarddex0/make-battleship-package.sh
# Output: guarddex-battleship-YYYYMMDD.tar.gz (~4 MB)
# Contains: backend/ dashboard/ install.sh verify.sh APK guarddex.apk
# Also bundles keys-preset.env (chmod 600) — shareable API keys auto-loaded by install.sh
# Keys bundled: Anthropic, VT, HIBP, OTX, GreyNoise, Shodan, AbuseIPDB, URLScan, etc.
# Keys NOT bundled: NextDNS, SMTP, Twilio, DB/JWT secrets (per-node only)

Deploy

scp guarddex-battleship-*.tar.gz [email protected]:~
ssh [email protected]
tar -xzf guarddex-battleship-*.tar.gz && cd guarddex-battleship-*/
sudo bash install.sh

Key battleship .env settings

ENABLE_OLLAMA=false              # no local GPU — use Haiku
ANTHROPIC_API_KEY=sk-ant-...     # required for AI on battleship
DATABASE_URL=postgresql://guarddex_user:PASSWORD@localhost:5432/guarddex_db
# Note: native PostgreSQL uses port 5432 (not 5433 like Docker on mothership)

Provision Android app on a battleship

  1. Install the APK on the user's phone: adb install guarddex-v2.2-release.apk — or download from /dashboard/guarddex.apk in a browser
  2. On the battleship server, open /dashboard/provision.html
  3. Show the user the QR code — phone camera scan → GuardDex app opens → server URL saved automatically
  4. Guide user through enabling Notification Access (Settings → Apps → Special app access → Notification access → GuardDex → On)
  5. Set GuardDex as default browser (Settings → Apps → Default apps → Browser)

Appliance Setup hpt430-master-setup.sh

Run this script before install.sh on a fresh OS install to harden the machine and prepare it for operation as a GuardDex appliance. Designed for HP t430 thin clients and similar low-power hardware.

sudo bash /opt/Guarddex0/hpt430-master-setup.sh

Key variables at the top of the script

VariableDefaultDescription
INSTALL_DOCKER0Set 1 to install Docker (not needed for GuardDex native)
ENABLE_FAIL2BAN1SSH jail: 3 failed attempts = 24-hour ban
ENABLE_ZRAM1Compressed RAM swap (lz4, 50% of physical RAM). Helps 3 GB machines.
SWAP_SIZE_GB2Fallback swap file size in GB (written to /swapfile)
ENABLE_VNC0Set 1 to install TigerVNC + noVNC browser desktop on port 6080
VNC_PASSWORDguarddogVNC session password
INSTALL_GUARDDEX0Set 1 to chain directly into install.sh after setup completes
STATIC_IP""Set to e.g. 192.168.1.246 to configure a static LAN IP. Leave blank to skip.
STATIC_GW""Gateway for static IP, e.g. 192.168.1.1
STATIC_DNS"1.1.1.1 9.9.9.9"DNS servers for static IP config

What it configures (in order)

  1. Static IP via Netplan (Ubuntu) or /etc/network/interfaces (Debian) if STATIC_IP is set
  2. Base packages: curl, wget, git, htop, net-tools, fail2ban, unzip, tmux, rsync, nmap
  3. Tailscale (auto-installs and displays auth URL for one-time setup)
  4. Docker opt-in (disabled by default)
  5. fail2ban SSH jail: 3 failures = 24-hour ban
  6. zram compressed RAM (lz4, 50% of physical RAM) + swap file + sysctl swappiness=10
  7. Dynamic MOTD at /etc/update-motd.d/10-guarddex — shows GuardDex banner, CPU/RAM/disk stats, service states, and fail2ban counts on every SSH login
  8. TigerVNC + noVNC browser desktop on port 6080 (opt-in)
  9. Chains into install.sh (opt-in)

Browser-based desktop (VNC over noVNC)

When ENABLE_VNC=1, the desktop accessible via HDMI can also be viewed in a browser at http://<SERVER_IP>:6080. Useful for diagnosing UI issues or running graphical apps remotely without needing an HDMI monitor attached.

# Start/stop the noVNC session manually
sudo systemctl start  guarddex-vnc
sudo systemctl stop   guarddex-vnc
sudo systemctl status guarddex-vnc

User Profile Features new in v2.2

Each logged-in user can access these features from their Profile page (/dashboard/profile.html).

Data Export

Downloads a full JSON file of the user's account data: profile, scan history, alerts, notification preferences, breach check history.

GET /api/v2/auth/export-data    # Auth: JWT  →  returns JSON download

Delete Account

Permanently removes the user and all their data across 6 database tables. Requires current password + the exact phrase DELETE MY ACCOUNT.

DELETE /api/v2/auth/account
# Body: {"password": "...", "confirmation": "DELETE MY ACCOUNT"}

Security Report

Generates a printable HTML security summary covering the past N days: URL scans, alert breakdown, breach status, notification history.

GET /api/v2/auth/security-report?days=30    # Auth: JWT  →  returns HTML

Two-Factor Authentication (TOTP)

TOTP-based 2FA using any authenticator app (Google Authenticator, Authy, Bitwarden, etc.).

  1. Go to Profile → Two-Factor Authentication → Set Up 2FA
  2. A QR code appears — scan it with your authenticator app
  3. Enter the 6-digit code from the app to confirm setup
  4. On future logins, the login page will prompt for the 6-digit code after your password
Note: QR code generation requires the qrcode[pil] Python package (Pillow). This is included in requirements.txt as of v2.2. If scanning the QR gives "no usable data," re-run venv/bin/pip install qrcode[pil] Pillow and restart the service.

Build APK

# Prerequisites (mothership only)
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
# Node.js 22 must be installed (via NodeSource)

# Debug build (default)
bash /opt/Guarddex0/build-apk.sh

# Release build (requires keystore)
bash /opt/Guarddex0/build-apk.sh release

Output: /opt/Guarddex0/guarddex-v2.2-release.apk (~3.1 MB signed). Also copied to dashboard/guarddex.apk — downloadable from /dashboard/guarddex.apk.

Source: /opt/Guarddex0/mobile/ — Capacitor 8 + Android SDK API 34

Key source files

FilePurpose
mobile/android/app/src/main/java/…/BrowserActivity.javaSecurity gateway browser (6 privacy extensions)
mobile/android/app/src/main/java/…/GuardDexNotificationListener.javaPre-click phishing scan on all notifications
mobile/android/app/src/main/java/…/ServerConfigPlugin.javaSharedPreferences bridge for server URL
mobile/android/app/src/main/java/…/DeviceSecurityPlugin.javaNative telemetry for Security Center
mobile/android/app/src/main/assets/gd_blocklist.txt132-domain ad/tracker blocklist
mobile/www/setup.htmlFirst-launch server URL config (QR + manual)

Build Browser Extension new in v2.1

bash /opt/Guarddex0/extension/scripts/build.sh
# Regenerates rules, icons, zips to guarddex-extension.zip (15 KB)

Rebuild blocklist rules (after updating gd_blocklist.txt)

python3 /opt/Guarddex0/extension/scripts/generate_rules.py
# Reads mobile/android/app/src/main/assets/gd_blocklist.txt
# Writes extension/rules/blocklist_rules.json (132 rules)

Install in Chrome (development)

# chrome://extensions → Developer mode → Load unpacked
# Point to: /opt/Guarddex0/extension/

Install in Firefox (temporary)

# about:debugging → Load Temporary Add-on
# Select: /opt/Guarddex0/guarddex-extension.zip

Requires Chrome 111+ / Firefox 128+ for world: "MAIN" fingerprint guard support.

Environment Variables /opt/Guarddex0/.env

VariableDefaultNotes
SECRET_KEY reqJWT signing secret. Generate: openssl rand -hex 32
DATABASE_URL reqFull PostgreSQL URL. Mothership: port 5433. Battleship: port 5432.
REDIS_URLredis://localhost:6379/0Rate limiter + cache. Mothership: 6379. Battleship: same.
ENABLE_OLLAMAtrueSet false on battleships without GPU
ANTHROPIC_API_KEY optClaude Haiku fallback. Required on battleships with ENABLE_OLLAMA=false
ENABLE_AItrueMaster AI on/off switch (both Ollama + Haiku)
ACCESS_TOKEN_EXPIRE_MINUTES60JWT lifetime. Inactivity timeout in frontend auth.js is separate.
NTFY_SERVER opthttps://ntfy.shntfy server base URL
NTFY_USERNAMEntfy auth username (self-hosted)
NTFY_PASSWORDntfy auth password
SMTP_HOST optGmail: smtp.gmail.com
SMTP_PORT587STARTTLS
SMTP_USERNAMEGmail address
SMTP_PASSWORDGmail app password (not account password)
TWILIO_ACCOUNT_SID optTwilio SID
TWILIO_AUTH_TOKENTwilio auth token
TWILIO_FROM_NUMBERE.164 format: +15555550100
NEXTDNS_API_KEY optNextDNS API key
NEXTDNS_PROFILE_IDe.g. 4344ac
POSTGRES_PASSWORDUsed by install.sh to create DB user (may differ from URL)

Key API Endpoints

MethodPathAuthNotes
GET/healthService health check
POST/api/v1/scan/urloptional{"url":"https://..."} → verdict + signals
POST/api/v2/auth/register{"email","password","full_name","phone"}
POST/api/v2/auth/loginReturns {"access_token","token_type","user"}
GET/api/v2/auth/meJWTCurrent user profile
GET/PUT/api/v2/notifications/preferencesJWTNotification prefs
POST/api/v2/notifications/testJWT{"type":"test"} — sends test notification
GET/api/v2/my/scansJWTPer-user scan history
POST/api/v1/security/assistant/chatJWTSSE streaming AI chat. Body: {"message":"..."}
GET/api/v1/analytics/ai-statusAI backend + model info (includes haiku_available)
GET/api/v1/security/attack-lab/statusAttack lab tool availability
GET/api/v2/auth/export-dataJWTFull JSON export of user data (profile, scans, alerts, breach history)
DELETE/api/v2/auth/accountJWTDelete account + all data. Body: {"password":"...","confirmation":"DELETE MY ACCOUNT"}
GET/api/v2/auth/security-report?days=30JWTPrintable HTML security report
GET/api/v2/auth/2fa/setupJWTReturns TOTP secret + QR code as base64 PNG
POST/api/v2/auth/2fa/enableJWTConfirms + activates 2FA. Body: {"secret":"...","code":"123456"}
GET/api/v2/notifications/historyJWTNotification send history. Query: days, channel, severity, limit, offset
GET/api/v2/dns/autoblockJWTGet DNS auto-block state
POST/api/v2/dns/autoblockJWTSet auto-block state. Body: {"enabled":true}

Scan response shape

{
  "verdict":       "safe" | "challenge" | "block",
  "is_blocked":     false,
  "is_challenged":  false,
  "matched_brand":  "Bank of America" | null,
  "confidence":     0.0 – 1.0,
  "signals":        ["typosquatting", "fresh domain"],
  "reason":         "string explanation"
}

AI Configuration

ConditionAI BackendModel
ENABLE_OLLAMA=true + Ollama reachable + model availableOllama (local)nous-hermes2:10.7b (assistant), phi3:mini (URL analyzer)
ENABLE_OLLAMA=false + ANTHROPIC_API_KEY setHaiku (cloud)claude-haiku-4-5-20251001
Ollama unreachable + ANTHROPIC_API_KEY setHaiku (fallback)claude-haiku-4-5-20251001
Neither availableNone — 503

Install Ollama (mothership)

curl -fsSL https://ollama.com/install.sh | sh
ollama pull nous-hermes2:10.7b   # security assistant
ollama pull phi3:mini            # URL analyzer
ollama pull dolphin-mistral:7b   # Attack Studio red team AI

Check AI status

curl -s http://localhost:8088/api/v1/analytics/ai-status | python3 -m json.tool

NextDNS Integration

When configured, scan verdicts of block auto-add the domain to the NextDNS denylist, protecting all devices on your network at the DNS level.

NEXTDNS_API_KEY=your_api_key
NEXTDNS_PROFILE_ID=4344ac   # "Dave's" profile
denylist POST behavior NextDNS returns 204 on success and 200+JSON on duplicate (already blocked). Both are treated as success — no duplicate alerts.

Manually check denylist count

curl -H "X-Api-Key: YOUR_KEY" \
  "https://api.nextdns.io/profiles/4344ac/denylist" | python3 -m json.tool | grep -c domain

Architecture

  Android / Browser Extension
        │  HTTPS :8088
        ▼
  ┌────────────────────────────────────────┐
  │  FastAPI  (backend/main.py)            │
  │  ─────────────────────────────────     │
  │  /api/v1/   challenge_api.py           │  scan, brands, analytics
  │             security_api.py           │  15 detectors, AI assistant
  │  /api/v2/   auth_api.py               │  JWT register/login/me
  │             notification_api.py       │  prefs, test, dispatch
  │  ─────────────────────────────────     │
  │  services/  url_scanner.py            │  threat intel aggregator
  │             notification_service.py   │  ntfy / email / SMS
  │  security/  phishing_detector.py      │  44-brand + heuristics
  │             ai_analyzer.py            │  Ollama or Haiku
  └──────────┬─────────────────────────────┘
             │
    ┌────────┴──────────┐
    │                   │
  PostgreSQL           Redis          Ollama
  :5433 (Docker)       :6379          :11434
  :5432 (native)       rate limit     models
  users, scans         cache          (mothership)
  alerts, prefs

Troubleshooting — Service / Boot

Service fails to start

sudo journalctl -u guarddex -n 50 --no-pager

Common causes and fixes:

Error in logsFix
ModuleNotFoundErrorVenv not built: python3 -m venv venv && venv/bin/pip install -r backend/requirements.txt
could not connect to server (PostgreSQL)DB not running — start it, then restart guarddex
No such file or directory: .envRun install.sh or create .env manually
Address already in use :8088sudo lsof -i :8088 — kill conflicting process
PYTHONPATH error / ImportErrorCheck unit file: ExecStart must include PYTHONPATH=/opt/Guarddex0/backend

Troubleshooting — Database

Test connectivity

# Native
psql -U guarddex_user -d guarddex_db -c "SELECT 1"

# Docker (mothership)
docker exec data-postgres psql -U guarddex_user -d guarddex_db -c "SELECT 1"

Recreate all tables (dev only — destroys data)

PYTHONPATH=backend venv/bin/python3 backend/init_db.py

Check tables exist

\dt     -- inside psql: should list users, url_scans, alerts, notification_prefs

API returns 500 on every request

Almost always a database connection issue. Check DATABASE_URL in .env — watch for @, #, $ in password (must be URL-encoded or avoided). Mothership uses port 5433; battleship uses 5432.

Troubleshooting — Auth / JWT

Login returns 401 for valid credentials

Check SECRET_KEY in .env is set and hasn't changed since the token was issued. Changed SECRET_KEY invalidates all existing tokens — users must log in again.

Admin account shows is_admin = false

UPDATE users SET is_admin = true WHERE email = '[email protected]';

Forgot admin password

python3 -c "from passlib.context import CryptContext; \
  print(CryptContext(schemes=['bcrypt']).hash('NewPassword!'))"
UPDATE users SET hashed_password = '<hash>' WHERE email = '[email protected]';

Troubleshooting — Notifications

Notifications not arriving

CheckHow
ntfy topic matchesProfile ntfy_topic must match phone subscription topic exactly
Throttle window activephishing_block: 1/hr, security_alert: 1/4hr, dns_critical: 1/hr. Wait or restart service to reset.
NotificationPrefs row existsSELECT * FROM notification_prefs WHERE user_id = (SELECT id FROM users WHERE email='...');
Send testcurl -X POST http://localhost:8088/api/v2/notifications/test -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" -d '{"type":"test"}'
ntfy server reachablecurl -d "test" "$NTFY_SERVER/guarddex-test-topic"
Throttle key names The _THROTTLE dict uses: phishing_block, login_challenge, security_alert, dns_critical, dns_scan_batch. Mismatched keys = silent throttle bypass (fixed in v2.1).

Troubleshooting — Android App

SymptomCause / Fix
App shows "Cannot reach server"Phone not on same LAN as server. Check Wi-Fi network. Or VPN required for remote access.
QR code scan does nothingIntent filter for guarddex:// missing — rebuild APK or reinstall. Camera app must support deep links.
Notification scanning not workingNotification Access not granted. Settings → Apps → Special app access → Notification access → GuardDex → On.
Browser shows scan error on every pageServer URL not configured or server down. Go to app settings and re-enter server URL.
Pages blocked that should be safeCheck scan API response: curl -X POST http://SERVER:8088/api/v1/scan/url -d '{"url":"https://..."}'. Adjust brand DB or heuristics if needed.
Dark mode not workingSome sites block CSS injection via strict CSP headers. Not a bug — expected limitation.
Bitwarden autofill not appearingCheck Bitwarden is set as autofill provider in Android settings. Our code sets IMPORTANT_FOR_AUTOFILL_YES on the WebView.

Troubleshooting — Browser Extension

SymptomFix
"Scan error" badge on every pageServer URL wrong in popup, or server down, or CF Access blocking API. Check popup → server URL. Add CF Access bypass for your domain.
Fingerprint guard not workingRequires Chrome 111+ or Firefox 128+ for world:MAIN content scripts.
Ad blocking not workingVerify declarativeNetRequest rulesets enabled: open chrome://extensions → GuardDex → Details → check rule counts.
Dark mode flickers on page loadExpected — CSS injects after document_start. Content-Security-Policy on some sites may block the style tag.
Extension removed after Firefox restartTemporary install. Use about:addons → Install Add-on From File for permanent install.

Troubleshooting — AI / Ollama

# Check Ollama is running
curl http://localhost:11434/api/tags

# Check available models
ollama list

# Pull a missing model
ollama pull nous-hermes2:10.7b

# Check GuardDex AI status endpoint
curl -s http://localhost:8088/api/v1/analytics/ai-status | python3 -m json.tool

If haiku_available: false in the AI status response and ENABLE_OLLAMA=false, set ANTHROPIC_API_KEY in .env and restart the service.

If ollama_available: false and ENABLE_OLLAMA=true, check that ollama.service is running and a model from the SECURITY_MODELS list is installed.

Third-party API Keys optional integrations

GuardDex's core scanner works out of the box with no external accounts. These integrations are optional add-ons that improve detection coverage, add notification channels, or enable DNS-level blocking. Each key goes in /opt/Guarddex0/.env, then sudo systemctl restart guarddex.

Anthropic — Claude AI

Used for: AI assistant in Security Center, URL phishing confidence scoring. Required on battleship nodes where Ollama is not available (ENABLE_OLLAMA=false).

ANTHROPIC_API_KEY=sk-ant-api03-...
StepDetail
Sign upconsole.anthropic.com → Create account
Get keyAPI Keys → Create Key → copy the sk-ant-... value
Add creditBilling → Add payment method. No subscription needed — pay per use.
Free tierNone, but Haiku costs ~$0.25/M tokens. Typical GuardDex usage: under $1/month.
Model usedclaude-haiku-4-5-20251001 — fastest and cheapest Claude model

VirusTotal — URL & IP Threat Intelligence

Used for: Enriches URL scans with VirusTotal's multi-engine verdict (70+ AV engines). Adds signal confidence to the phishing scorer.

VIRUSTOTAL_API_KEY=64-char-hex-key
StepDetail
Sign upvirustotal.com/gui/join-us → free account
Get keyProfile icon (top right) → API Key → copy
Free tier500 requests/day, 4 requests/min. More than enough for personal/family use.
Paid tierVirusTotal Premium from $40/mo — not needed for GuardDex at family scale

Shodan — Network & Host Intelligence

Used for: DNS Scanner enrichment — looks up open ports, services, and known vulnerabilities on scanned IPs. Useful for IMSI catcher and C2 beacon detection context.

SHODAN_API_KEY=your-shodan-key
StepDetail
Sign upaccount.shodan.io → Create a free account
Get keyaccount.shodan.io/api_info → copy API Key
Free tierLimited to 1 query/sec, no scan credits. Read-only lookups work fine for GuardDex.
Membership$49 one-time "Lifetime Membership" unlocks full API — worth it if you use the DNS Scanner heavily

AbuseIPDB — IP Reputation

Used for: Flags IP addresses that have been reported for abuse, spam, or attacks. Adds a signal layer to network-based detectors.

ABUSEIPDB_API_KEY=your-key
StepDetail
Sign upabuseipdb.com → Sign Up (free)
Get keyAccount → API → Create Key
Free tier1,000 checks/day. More than adequate for family deployments.

PhishTank — Phishing URL Database

Used for: Cross-checks scanned URLs against a community-maintained database of verified phishing pages. Zero false positives since every entry is human-verified.

PHISHTANK_API_KEY=your-app-key
StepDetail
Sign upphishtank.org → Register
Get keyphishtank.org/api_info.php → Register your application → copy app key
Free tier100 requests/day without key, 900/day with a free developer key
NotePhishTank is owned by Cisco/OpenDNS. Database is community-sourced and freely available.

NextDNS — DNS-level Blocking

Used for: Auto-adds newly blocked domains to your NextDNS denylist, protecting every device on your network at the DNS level — not just those with the app.

NEXTDNS_API_KEY=your-api-key
NEXTDNS_PROFILE_ID=4344ac
StepDetail
Sign upnextdns.io → Create a free account
Get keynextdns.io/account → API section → copy key
Profile IDnextdns.io → your profile → copy the 6-char ID from the URL (e.g. 4344ac)
Free tier300,000 queries/month. Paid plan $1.99/mo for unlimited.
Router setupSet your router's DNS to NextDNS servers — all devices on the network are then protected

Twilio — SMS Alerts

Used for: Sends SMS text message notifications when a phishing block or security alert fires, as an alternative or backup to ntfy push notifications.

TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your-auth-token
TWILIO_FROM_NUMBER=+15555550100
StepDetail
Sign uptwilio.com/try-twilio → free trial account
Account SID & Tokentwilio.com/console → shown on the main dashboard
Phone numberConsole → Phone Numbers → Buy a Number (~$1/mo for a US number)
Free trial$15 trial credit. Each SMS costs ~$0.0079. Family use = a few cents/month.
Trial restrictionFree trial can only SMS verified numbers. Upgrade ($0) to remove this limit.

ntfy — Push Notifications

Used for: Real-time push alerts to phones. Preferred over SMS for instant delivery with no per-message cost.

NTFY_SERVER=https://ntfy.richeyda.com   # or https://ntfy.sh for the public server
NTFY_USERNAME=guarddex
NTFY_PASSWORD=your-ntfy-password
OptionDetail
Self-hosted (recommended)Run ntfy on any server or Pi. Docker: docker run -p 80:80 binwiederhier/ntfy serve. Free, private, no limits.
ntfy.sh (public)ntfy.sh → free hosted service. No account needed for public topics. Reserved topics require a paid account ($3/mo).
Phone appAndroid: Play Store or F-Droid. iOS: App Store. Scan QR from /dashboard/provision.html to subscribe automatically.
Tip — start with just Anthropic + ntfy For a battleship node, the two most impactful keys are ANTHROPIC_API_KEY (enables AI without Ollama) and ntfy (enables push notifications). Everything else is an enhancement you can add later.

Changelog

v2.2 — 2026-05-18

ComponentChange
Profile newData Export — GET /api/v2/auth/export-data — full JSON download of user's data
Profile newDelete Account — DELETE /api/v2/auth/account — requires password + "DELETE MY ACCOUNT" phrase; cascades 6 tables
Profile newSecurity Report — GET /api/v2/auth/security-report?days=30 — printable HTML report (URL scans, alerts, breach status, notifications)
Profile2FA QR fix — GET /api/v2/auth/2fa/setup now returns qr_data_url (base64 PNG); enable endpoint receives secret from frontend
AndroidAPK rebuilt as v2.2 release build (signed v2 scheme, 3.1 MB). dashboard/guarddex.apk serves it for provision page download.
NotificationsDevice IP in critical DNS block alerts — admin can see which device triggered the block
DashboardMobile sidebar — all 7 admin sidebar pages have hamburger nav (<768px) via dashboard/js/sidebar.js
DashboardTable overflow — DNS scanner and LAN scanner tables use overflow-x:auto for mobile
DashboardNextDNS service health chip added to admin dashboard health strip
DashboardCockpit link added to Admin Settings Quick Links bar
DNS ScannerAuto-block toggle fixed — URL double-path bug (/dns/dns/autoblock) corrected
install.sh v1.2breach/LAN tables in SQL block, nmap install, HIBP/VT prompts, password + PIN confirmation loops, ExecStartPre auto-IP on boot, keys-preset.env support, PG15+ schema GRANT fix, startup retry loop
make-battleship-package.shBundles keys-preset.env with shareable API keys (chmod 600), deleted after .env written
verify.sh11 checks (added LAN scanner, breach monitor, nmap)
hpt430-master-setup.shfail2ban SSH jail, zram (lz4, 50% RAM), swap file, dynamic MOTD, TigerVNC/noVNC browser desktop, static IP (Netplan/interfaces), Docker opt-in (default off)
SecurityPassive network monitor (ARP + DNS hijacking checks every 30 min) in security_api.py
Breach Monitor newHousehold member slots, HIBP + LeakCheck + Leak-Lookup + Shodan + Hunter.io, history, CSV export
Notification History newTimeline of all push/email/SMS sends, filter by channel/severity/date, export CSV, clear all
Pythonqrcode[pil] + Pillow added to requirements.txt (required for 2FA QR generation)

v2.1 — 2026-05-02

ComponentChange
AndroidBrowserActivity — security gateway browser with 6 privacy extensions (ad block, URL cleaner, HTTPS upgrade, fingerprint reduction, dark mode, credential watchdog)
AndroidGuardDexNotificationListener — pre-click scanning on all app notifications
AndroidServerConfigPlugin — QR deep link server URL config (guarddex://configure) for battleship provisioning
Extension newChrome/Firefox MV3 WebExtension — URL scanning, 132-domain ad block, HTTPS upgrade, 28-param tracking cleaner, dark mode, fingerprint guard
Phase 2.2Ollama → Claude Haiku fallback in security_api.py and ai_analyzer.py. ENABLE_OLLAMA=false skips probe entirely.
install.shv1.1: RAM check (4 GB min), Redis install, ntfy prompts, race condition fix (init_db before service start), admin NotificationPrefs row
verify.sh new10-check post-install health script with native + Docker PostgreSQL/Redis fallback
NotificationsFixed throttle key mismatch (5 event_type strings aligned to _THROTTLE dict keys)
Authregister() now creates NotificationPrefs row — new users receive notifications immediately
Profile UIntfy_topic and ntfy_server fields added
Login UIPhone field added to registration form
Archive~30 v1 root Python files + stale docs moved to archive/

v2.0.5 — 2026-02-25

JWT auth, PostgreSQL persistence, 44-brand phishing DB, 15 security detectors, Ollama AI assistant, notification system (ntfy/email/SMS), family dashboard, user profile, TestBench 10 suites.