Appearance
System Architecture
Purpose of the platform
The Cyber Range gives BSIT Network & Cybersecurity students on-demand, isolated, hands-on labs in the browser, scores their progress automatically, and gives instructors and admins the tools to monitor, review and operate it. It runs on a single Oracle Cloud (OCI) Ampere virtual machine.
High-level architecture
Major components
| Component | What it does | Runs where | Listens on | Source |
|---|---|---|---|---|
| Portal | All web pages; edge middleware for login and role redirects; server-side BFF routes that proxy to the API; DVWA reverse proxy that also detects Scenario 2 attacks | Host, systemd user unit cyberrange-portal | 10.115.77.1:3000 | cyberrange/portal/ |
| Provisioning API | Lab lifecycle (create, status, destroy), scoring, progress, reviews, instructor and admin endpoints, background reaper and score poller | Host, user unit cyberrange-provision-api | 10.115.77.1:5000 | cyberrange/src/provisioning/ |
| Terminal bridge | WebSocket server that authenticates the user and streams an lxc exec shell (inside tmux) to xterm.js | Host, user unit cyberrange-ssh-bridge | 10.115.77.1:8765 | cyberrange/bridge-src/bridge.py |
| SQLite database | Labs, scores, reviews, audit log, lab sessions, alert snapshots, evidence image metadata | Host file ~/cyberrange-data/pod_mgmt.db (default path) | n/a | cyberrange/src/provisioning/db.py, schema/ |
| LXD + OVN | Creates and deletes containers and per-lab networks | Host (snap) | Unix socket | cyberrange/src/provisioning/provision.py, pod_net.py |
| Gateway nginx | Single public origin: routes portal, Keycloak and terminal traffic | guacamole LXD container | 10.115.77.12:80 | cyberrange/deploy/guacamole/nginx-ampere.conf |
| Keycloak | Identity provider: accounts, passwords, realm roles, OIDC tokens, introspection, admin REST API | guacamole container, system unit | 127.0.0.1:8083 under /auth | cyberrange/deploy/keycloak/keycloak.service |
| Wazuh manager | SIEM: receives agent events from the lab targets, writes alerts.json | wazuh-manager container on mon-net | 10.0.40.10:1514/1515; API bound to 127.0.0.1:55000 inside the container (harden_wazuh_api.sh), proxied to host loopback | manual/02-gateway-and-wazuh.md, deploy/host/harden_wazuh_api.sh |
| Lab containers | kali (attacker box), meta (vulnerable server), dvwa (vulnerable web app) | One set per lab on pod-<id>-net, behind the lab's egress ACL | .10, .20, .30 | cyberrange/src/provisioning/provision.py, pod_net.py |
| cloudflared | Outbound tunnel publishing the gateway on the public hostname | Host, system unit | outbound only | cyberrange/deploy/systemd/cloudflared.service |
| Release puller | Every 5 minutes, applies a new GitHub release ampere-live with health checks, a Wazuh certificate check and rollback | Host, user timer | n/a | cyberrange/deploy/host/pull_release.sh |
| Booking page backend | Records test-session bookings in a Google Sheet and emails confirmations and organizer notices; it does not create Cyber Range accounts (domain owners create them in Admin → Users) | Google Apps Script, outside the host | n/a | cyberrange/booking/Code.gs, docs/BOOKING-ACCOUNT-PROVISIONING.md |
Technology stack
| Layer | Technologies |
|---|---|
| Frontend | Next.js 15.5 (App Router), React 19, TypeScript 5, Tailwind CSS 3, NextAuth 4, xterm.js 6, react-markdown with rehype-sanitize, zustand |
| Backend | Python 3, FastAPI, Pydantic, uvicorn, pylxd, requests, Pillow |
| Terminal | Python websockets 12, lxc exec, tmux |
| Identity | Keycloak (realm cyber-range, client portal) |
| Data | SQLite (WAL mode), Keycloak's own database (see Database) |
| Infrastructure | OCI Ampere A1, Ubuntu 24.04, LXD (snap), OVN, nginx, Cloudflare Tunnel, systemd |
| Security monitoring | Wazuh 4.7.5 manager and agents |
| Delivery | GitHub Actions (release build, pull-request type check), GitHub Releases, host-side pull script |
How the components communicate
| From | To | Protocol | Authentication | Source |
|---|---|---|---|---|
| Browser | Cloudflare | HTTPS | none at this layer | manual/appendix-network-map.md |
| cloudflared | Gateway nginx | HTTP over the private bridge | tunnel token (host side) | cyberrange/deploy/systemd/cloudflared.service |
| Browser | Portal pages and /api/* | HTTP via nginx | NextAuth session cookie | cyberrange/portal/src/middleware.ts, lib/apiProxy.ts |
| Browser | Keycloak /auth/... | HTTP via nginx | Keycloak login form | cyberrange/portal/src/lib/auth.ts |
| Portal server | Keycloak token endpoint | HTTP | confidential client ID and secret | cyberrange/portal/src/lib/auth.ts |
| Portal server | Provisioning API | HTTP to 10.115.77.1:5000 | Authorization: Bearer user access token | cyberrange/portal/src/lib/apiProxy.ts |
| Portal server (DVWA proxy) | API /internal/browser-score | HTTP | X-Browser-Score-Secret shared secret | cyberrange/portal/src/app/lab/dvwa/[[...path]]/route.ts |
| API and bridge | Keycloak introspection endpoint | HTTP | API's client credentials | cyberrange/src/provisioning/auth.py |
| Browser | Terminal bridge | WebSocket via nginx | access token in the token query parameter | cyberrange/portal/src/components/terminal/XtermView.tsx |
| Bridge | Provisioning API | HTTP | user's bearer token (ownership check) | cyberrange/bridge-src/bridge.py |
| API | LXD | pylxd over the local Unix socket, plus lxc CLI | host user in the lxd group | cyberrange/src/provisioning/provision.py, pod_net.py |
| API | Wazuh manager | LXD file API (read alerts.json); HTTPS to localhost:55000 for agent lookup, status and cleanup, verified against the pinned certificate or the internal CA; lxc exec to install the return route to each lab subnet | LXD control plane; Wazuh API users WAZUH_SCORING_USER (read-only) and WAZUH_PROVISION_USER (agent read and delete) | cyberrange/src/provisioning/alerts_reader.py, wazuh_client.py, pod_net.py |
| Lab agents | Wazuh manager | Wazuh agent protocol, TCP 1514/1515, the only traffic the lab's egress ACL lets out of the lab | agent keys after passwordless enrollment | manual/06-scoring.md, pod_net.py |
Where to go next
- Components: every module and what it is responsible for.
- Request & Data Flows: the main end-to-end flows.
- Deployment: how this runs on the host.
- Lab Infrastructure: containers and networks in detail.
Sources
manual/appendix-network-map.md, manual/02-gateway-and-wazuh.md, manual/06-scoring.md, cyberrange/deploy/systemd/*.service, cyberrange/deploy/host/harden_wazuh_api.sh, cyberrange/src/provisioning/pod_net.py, cyberrange/booking/Code.gs, docs/BOOKING-ACCOUNT-PROVISIONING.md, .github/workflows/*.yml, cyberrange/deploy/guacamole/nginx-ampere.conf, cyberrange/src/provisioning/provision_api_fastapi.py, cyberrange/src/provisioning/config.py, cyberrange/portal/package.json, cyberrange/bridge-src/requirements.txt.