Port Map 192.168.50.138
| Port | Service | Unit |
|---|---|---|
| 8088 | GuardDex API + Dashboard | guarddex.service |
| 8089 | Attack Studio | guarddex-attackstudio.service |
| 9090 | TestBench (mothership) / Cockpit (battleship) | guarddex-testbench.service / cockpit.service |
| 5433 | PostgreSQL (Docker: data-postgres) | data-postgres container |
| 5432 | PostgreSQL (native battleship / gaming-postgres) | postgresql.service |
| 6379 | Redis | data-redis container / redis.service |
| 11434 | Ollama (mothership only) | ollama.service |
| 3001 | BeEF Framework | manual |
| 8000 | TTS Studio backend (reserved) | Docker |
Requirements
| Item | Minimum | Notes |
|---|---|---|
| RAM | 4 GB | install.sh hard-stops at <2 GB, warns at <3.5 GB |
| Disk | 10 GB free | 20 GB+ recommended if running Ollama |
| OS | Ubuntu 22.04/24.04, Debian 12/13 | 64-bit only. Debian 13 (Trixie) minimal server recommended for new battleship installs. |
| Python | 3.11+ | installed by install.sh |
| Node.js | 22 (LTS) | needed for APK builds only |
| Java | 21 | needed for APK builds only — JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 |
| Network | Static LAN IP | clients 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)
- Server name + Public URL (auto-detected from
hostname -I) - Admin email, password (with confirmation re-type), and optional admin settings PIN (with confirmation)
- ntfy server URL, username, password (push notifications)
- HIBP (HaveIBeenPwned) API key — optional, enables breach monitor
- VirusTotal API key — optional, improves URL threat scoring
- NextDNS API key + profile ID — optional, auto-adds blocked domains to DNS denylist
- SMTP credentials for email alerts (optional)
- Anthropic API key — write-only (not displayed), required for AI on battleships without Ollama
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)
- RAM check — aborts if <2 GB, warns if <4 GB
- Loads
keys-preset.envif present (battleship package) - apt install: python3, pip, postgresql, redis, nmap (no Node.js on battleship)
- Creates Python venv at
/opt/guarddex/venv, pip install -r requirements.txt - Creates
.envfrom prompts + presets - Creates PostgreSQL user + database; grants schema privileges (PG15+ compatible)
- Runs
python3 backend/init_db.py— creates all tables including LAN scanner + breach tables - Creates admin user + NotificationPrefs row via API bootstrap script
- Writes and enables
guarddex.servicesystemd unit withExecStartPrethat auto-updatesPUBLIC_URLin .env from current LAN IP on every boot - Waits up to 24 seconds for service to start (retry loop), then tails first 20 log lines
- Deletes
keys-preset.envif present
@, #, 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.
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
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
- Install the APK on the user's phone:
adb install guarddex-v2.2-release.apk— or download from/dashboard/guarddex.apkin a browser - On the battleship server, open
/dashboard/provision.html - Show the user the QR code — phone camera scan → GuardDex app opens → server URL saved automatically
- Guide user through enabling Notification Access (Settings → Apps → Special app access → Notification access → GuardDex → On)
- 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
| Variable | Default | Description |
|---|---|---|
| INSTALL_DOCKER | 0 | Set 1 to install Docker (not needed for GuardDex native) |
| ENABLE_FAIL2BAN | 1 | SSH jail: 3 failed attempts = 24-hour ban |
| ENABLE_ZRAM | 1 | Compressed RAM swap (lz4, 50% of physical RAM). Helps 3 GB machines. |
| SWAP_SIZE_GB | 2 | Fallback swap file size in GB (written to /swapfile) |
| ENABLE_VNC | 0 | Set 1 to install TigerVNC + noVNC browser desktop on port 6080 |
| VNC_PASSWORD | guarddog | VNC session password |
| INSTALL_GUARDDEX | 0 | Set 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)
- Static IP via Netplan (Ubuntu) or
/etc/network/interfaces(Debian) ifSTATIC_IPis set - Base packages: curl, wget, git, htop, net-tools, fail2ban, unzip, tmux, rsync, nmap
- Tailscale (auto-installs and displays auth URL for one-time setup)
- Docker opt-in (disabled by default)
- fail2ban SSH jail: 3 failures = 24-hour ban
- zram compressed RAM (lz4, 50% of physical RAM) + swap file + sysctl swappiness=10
- 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 - TigerVNC + noVNC browser desktop on port 6080 (opt-in)
- 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.).
- Go to Profile → Two-Factor Authentication → Set Up 2FA
- A QR code appears — scan it with your authenticator app
- Enter the 6-digit code from the app to confirm setup
- On future logins, the login page will prompt for the 6-digit code after your password
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
| File | Purpose |
|---|---|
| mobile/android/app/src/main/java/…/BrowserActivity.java | Security gateway browser (6 privacy extensions) |
| mobile/android/app/src/main/java/…/GuardDexNotificationListener.java | Pre-click phishing scan on all notifications |
| mobile/android/app/src/main/java/…/ServerConfigPlugin.java | SharedPreferences bridge for server URL |
| mobile/android/app/src/main/java/…/DeviceSecurityPlugin.java | Native telemetry for Security Center |
| mobile/android/app/src/main/assets/gd_blocklist.txt | 132-domain ad/tracker blocklist |
| mobile/www/setup.html | First-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
| Variable | Default | Notes |
|---|---|---|
| SECRET_KEY req | — | JWT signing secret. Generate: openssl rand -hex 32 |
| DATABASE_URL req | — | Full PostgreSQL URL. Mothership: port 5433. Battleship: port 5432. |
| REDIS_URL | redis://localhost:6379/0 | Rate limiter + cache. Mothership: 6379. Battleship: same. |
| ENABLE_OLLAMA | true | Set false on battleships without GPU |
| ANTHROPIC_API_KEY opt | — | Claude Haiku fallback. Required on battleships with ENABLE_OLLAMA=false |
| ENABLE_AI | true | Master AI on/off switch (both Ollama + Haiku) |
| ACCESS_TOKEN_EXPIRE_MINUTES | 60 | JWT lifetime. Inactivity timeout in frontend auth.js is separate. |
| NTFY_SERVER opt | https://ntfy.sh | ntfy server base URL |
| NTFY_USERNAME | — | ntfy auth username (self-hosted) |
| NTFY_PASSWORD | — | ntfy auth password |
| SMTP_HOST opt | — | Gmail: smtp.gmail.com |
| SMTP_PORT | 587 | STARTTLS |
| SMTP_USERNAME | — | Gmail address |
| SMTP_PASSWORD | — | Gmail app password (not account password) |
| TWILIO_ACCOUNT_SID opt | — | Twilio SID |
| TWILIO_AUTH_TOKEN | — | Twilio auth token |
| TWILIO_FROM_NUMBER | — | E.164 format: +15555550100 |
| NEXTDNS_API_KEY opt | — | NextDNS API key |
| NEXTDNS_PROFILE_ID | — | e.g. 4344ac |
| POSTGRES_PASSWORD | — | Used by install.sh to create DB user (may differ from URL) |
Key API Endpoints
| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | /health | — | Service health check |
| POST | /api/v1/scan/url | optional | {"url":"https://..."} → verdict + signals |
| POST | /api/v2/auth/register | — | {"email","password","full_name","phone"} |
| POST | /api/v2/auth/login | — | Returns {"access_token","token_type","user"} |
| GET | /api/v2/auth/me | JWT | Current user profile |
| GET/PUT | /api/v2/notifications/preferences | JWT | Notification prefs |
| POST | /api/v2/notifications/test | JWT | {"type":"test"} — sends test notification |
| GET | /api/v2/my/scans | JWT | Per-user scan history |
| POST | /api/v1/security/assistant/chat | JWT | SSE streaming AI chat. Body: {"message":"..."} |
| GET | /api/v1/analytics/ai-status | — | AI backend + model info (includes haiku_available) |
| GET | /api/v1/security/attack-lab/status | — | Attack lab tool availability |
| GET | /api/v2/auth/export-data | JWT | Full JSON export of user data (profile, scans, alerts, breach history) |
| DELETE | /api/v2/auth/account | JWT | Delete account + all data. Body: {"password":"...","confirmation":"DELETE MY ACCOUNT"} |
| GET | /api/v2/auth/security-report?days=30 | JWT | Printable HTML security report |
| GET | /api/v2/auth/2fa/setup | JWT | Returns TOTP secret + QR code as base64 PNG |
| POST | /api/v2/auth/2fa/enable | JWT | Confirms + activates 2FA. Body: {"secret":"...","code":"123456"} |
| GET | /api/v2/notifications/history | JWT | Notification send history. Query: days, channel, severity, limit, offset |
| GET | /api/v2/dns/autoblock | JWT | Get DNS auto-block state |
| POST | /api/v2/dns/autoblock | JWT | Set 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
| Condition | AI Backend | Model |
|---|---|---|
| ENABLE_OLLAMA=true + Ollama reachable + model available | Ollama (local) | nous-hermes2:10.7b (assistant), phi3:mini (URL analyzer) |
| ENABLE_OLLAMA=false + ANTHROPIC_API_KEY set | Haiku (cloud) | claude-haiku-4-5-20251001 |
| Ollama unreachable + ANTHROPIC_API_KEY set | Haiku (fallback) | claude-haiku-4-5-20251001 |
| Neither available | None — 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
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 logs | Fix |
|---|---|
| ModuleNotFoundError | Venv 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: .env | Run install.sh or create .env manually |
| Address already in use :8088 | sudo lsof -i :8088 — kill conflicting process |
| PYTHONPATH error / ImportError | Check 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
| Check | How |
|---|---|
| ntfy topic matches | Profile ntfy_topic must match phone subscription topic exactly |
| Throttle window active | phishing_block: 1/hr, security_alert: 1/4hr, dns_critical: 1/hr. Wait or restart service to reset. |
| NotificationPrefs row exists | SELECT * FROM notification_prefs WHERE user_id = (SELECT id FROM users WHERE email='...'); |
| Send test | curl -X POST http://localhost:8088/api/v2/notifications/test -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" -d '{"type":"test"}' |
| ntfy server reachable | curl -d "test" "$NTFY_SERVER/guarddex-test-topic" |
phishing_block, login_challenge, security_alert, dns_critical, dns_scan_batch. Mismatched keys = silent throttle bypass (fixed in v2.1).
Troubleshooting — Android App
| Symptom | Cause / 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 nothing | Intent filter for guarddex:// missing — rebuild APK or reinstall. Camera app must support deep links. |
| Notification scanning not working | Notification Access not granted. Settings → Apps → Special app access → Notification access → GuardDex → On. |
| Browser shows scan error on every page | Server URL not configured or server down. Go to app settings and re-enter server URL. |
| Pages blocked that should be safe | Check 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 working | Some sites block CSS injection via strict CSP headers. Not a bug — expected limitation. |
| Bitwarden autofill not appearing | Check Bitwarden is set as autofill provider in Android settings. Our code sets IMPORTANT_FOR_AUTOFILL_YES on the WebView. |
Troubleshooting — Browser Extension
| Symptom | Fix |
|---|---|
| "Scan error" badge on every page | Server 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 working | Requires Chrome 111+ or Firefox 128+ for world:MAIN content scripts. |
| Ad blocking not working | Verify declarativeNetRequest rulesets enabled: open chrome://extensions → GuardDex → Details → check rule counts. |
| Dark mode flickers on page load | Expected — CSS injects after document_start. Content-Security-Policy on some sites may block the style tag. |
| Extension removed after Firefox restart | Temporary 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-...
| Step | Detail |
|---|---|
| Sign up | console.anthropic.com → Create account |
| Get key | API Keys → Create Key → copy the sk-ant-... value |
| Add credit | Billing → Add payment method. No subscription needed — pay per use. |
| Free tier | None, but Haiku costs ~$0.25/M tokens. Typical GuardDex usage: under $1/month. |
| Model used | claude-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
| Step | Detail |
|---|---|
| Sign up | virustotal.com/gui/join-us → free account |
| Get key | Profile icon (top right) → API Key → copy |
| Free tier | 500 requests/day, 4 requests/min. More than enough for personal/family use. |
| Paid tier | VirusTotal 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
| Step | Detail |
|---|---|
| Sign up | account.shodan.io → Create a free account |
| Get key | account.shodan.io/api_info → copy API Key |
| Free tier | Limited 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
| Step | Detail |
|---|---|
| Sign up | abuseipdb.com → Sign Up (free) |
| Get key | Account → API → Create Key |
| Free tier | 1,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
| Step | Detail |
|---|---|
| Sign up | phishtank.org → Register |
| Get key | phishtank.org/api_info.php → Register your application → copy app key |
| Free tier | 100 requests/day without key, 900/day with a free developer key |
| Note | PhishTank 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
| Step | Detail |
|---|---|
| Sign up | nextdns.io → Create a free account |
| Get key | nextdns.io/account → API section → copy key |
| Profile ID | nextdns.io → your profile → copy the 6-char ID from the URL (e.g. 4344ac) |
| Free tier | 300,000 queries/month. Paid plan $1.99/mo for unlimited. |
| Router setup | Set 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
| Step | Detail |
|---|---|
| Sign up | twilio.com/try-twilio → free trial account |
| Account SID & Token | twilio.com/console → shown on the main dashboard |
| Phone number | Console → 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 restriction | Free 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
| Option | Detail |
|---|---|
| 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 app | Android: Play Store or F-Droid. iOS: App Store. Scan QR from /dashboard/provision.html to subscribe automatically. |
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
| Component | Change |
|---|---|
| Profile new | Data Export — GET /api/v2/auth/export-data — full JSON download of user's data |
| Profile new | Delete Account — DELETE /api/v2/auth/account — requires password + "DELETE MY ACCOUNT" phrase; cascades 6 tables |
| Profile new | Security Report — GET /api/v2/auth/security-report?days=30 — printable HTML report (URL scans, alerts, breach status, notifications) |
| Profile | 2FA QR fix — GET /api/v2/auth/2fa/setup now returns qr_data_url (base64 PNG); enable endpoint receives secret from frontend |
| Android | APK rebuilt as v2.2 release build (signed v2 scheme, 3.1 MB). dashboard/guarddex.apk serves it for provision page download. |
| Notifications | Device IP in critical DNS block alerts — admin can see which device triggered the block |
| Dashboard | Mobile sidebar — all 7 admin sidebar pages have hamburger nav (<768px) via dashboard/js/sidebar.js |
| Dashboard | Table overflow — DNS scanner and LAN scanner tables use overflow-x:auto for mobile |
| Dashboard | NextDNS service health chip added to admin dashboard health strip |
| Dashboard | Cockpit link added to Admin Settings Quick Links bar |
| DNS Scanner | Auto-block toggle fixed — URL double-path bug (/dns/dns/autoblock) corrected |
| install.sh v1.2 | breach/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.sh | Bundles keys-preset.env with shareable API keys (chmod 600), deleted after .env written |
| verify.sh | 11 checks (added LAN scanner, breach monitor, nmap) |
| hpt430-master-setup.sh | fail2ban SSH jail, zram (lz4, 50% RAM), swap file, dynamic MOTD, TigerVNC/noVNC browser desktop, static IP (Netplan/interfaces), Docker opt-in (default off) |
| Security | Passive network monitor (ARP + DNS hijacking checks every 30 min) in security_api.py |
| Breach Monitor new | Household member slots, HIBP + LeakCheck + Leak-Lookup + Shodan + Hunter.io, history, CSV export |
| Notification History new | Timeline of all push/email/SMS sends, filter by channel/severity/date, export CSV, clear all |
| Python | qrcode[pil] + Pillow added to requirements.txt (required for 2FA QR generation) |
v2.1 — 2026-05-02
| Component | Change |
|---|---|
| Android | BrowserActivity — security gateway browser with 6 privacy extensions (ad block, URL cleaner, HTTPS upgrade, fingerprint reduction, dark mode, credential watchdog) |
| Android | GuardDexNotificationListener — pre-click scanning on all app notifications |
| Android | ServerConfigPlugin — QR deep link server URL config (guarddex://configure) for battleship provisioning |
| Extension new | Chrome/Firefox MV3 WebExtension — URL scanning, 132-domain ad block, HTTPS upgrade, 28-param tracking cleaner, dark mode, fingerprint guard |
| Phase 2.2 | Ollama → Claude Haiku fallback in security_api.py and ai_analyzer.py. ENABLE_OLLAMA=false skips probe entirely. |
| install.sh | v1.1: RAM check (4 GB min), Redis install, ntfy prompts, race condition fix (init_db before service start), admin NotificationPrefs row |
| verify.sh new | 10-check post-install health script with native + Docker PostgreSQL/Redis fallback |
| Notifications | Fixed throttle key mismatch (5 event_type strings aligned to _THROTTLE dict keys) |
| Auth | register() now creates NotificationPrefs row — new users receive notifications immediately |
| Profile UI | ntfy_topic and ntfy_server fields added |
| Login UI | Phone 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.