API Reference¶
The Control Center exposes a REST API on port 8089. All endpoints are prefixed with /api.
Status¶
GET /api/status¶
Returns the complete system status.
Response:
{
"vm": {
"ip": "192.168.10.10",
"reachable": true,
"ssh_up": true
},
"firewall": {
"enabled": true,
"killswitch": false,
"chain_ok": true,
"active_rules": 2,
"total_rules": 2
},
"vpn": {
"total_tunnels": 3,
"connected_tunnels": 2,
"error": null
},
"dns": {
"available": true,
"stats": { ... }
},
"routes": {
"count": 0
},
"domain": "clsxx.de"
}
Fields:
| Field | Description |
|---|---|
vm.reachable |
ICMP ping to VM succeeds |
vm.ssh_up |
TCP connect to VM port 22 succeeds |
firewall.chain_ok |
VM_EGRESS chain exists and FORWARD rule is in place |
vpn.connected_tunnels |
Tunnels with handshake < 180 seconds |
Firewall Rules¶
GET /api/rules¶
Returns all firewall rules and their state.
Response:
{
"enabled": true,
"killswitch": false,
"rules": [
{
"id": 1,
"description": "DNS to gateway (UDP)",
"protocol": "udp",
"port": 53,
"destination": "192.168.10.1",
"enabled": true,
"locked": true
}
]
}
POST /api/rules¶
Add a new firewall rule.
Request Body:
| Field | Type | Required | Default |
|---|---|---|---|
description |
string | ✅ | — |
protocol |
string | — | "tcp" |
port |
int | — | null (any) |
destination |
string | — | null (any) |
PATCH /api/rules/{rule_id}¶
Update a rule's enabled state or description.
Request Body:
DELETE /api/rules/{rule_id}¶
Delete a non-locked rule. Returns 403 for locked rules.
Firewall Controls¶
POST /api/killswitch¶
Toggle the emergency killswitch. When active, ALL VM traffic is dropped and logged.
Response:
POST /api/firewall/toggle¶
Toggle the firewall on/off. When off, all traffic is accepted.
Response:
POST /api/apply¶
Force re-apply all firewall rules from the saved configuration.
Profiles¶
GET /api/profiles¶
List available firewall profiles.
Response:
{
"locked": {
"name": "Locked Down",
"description": "Maximum lockdown — DNS to gateway only",
"icon": "lock",
"color": "#f44336"
},
"minimal": { ... },
"development": { ... },
"unrestricted": { ... }
}
POST /api/profile/{name}¶
Apply a profile. Replaces all rules with the profile's preset.
Path Parameters:
| Parameter | Values |
|---|---|
name |
locked, minimal, development, unrestricted |
DNS (Pi-hole)¶
GET /api/dns/summary¶
Pi-hole statistics summary.
GET /api/dns/queries?limit=100¶
Recent DNS lookup history.
GET /api/dns/top-domains¶
Top 15 most queried domains.
GET /api/dns/top-blocked¶
Top 15 blocked domains.
POST /api/dns/toggle¶
Toggle Pi-hole ad-blocking on/off.
VPN¶
GET /api/vpn/status¶
Real-time WireGuard tunnel status.
Response:
{
"error": null,
"tunnels": {
"strato-host": {
"name": "Admin VPN",
"description": "Laptop → Host admin access + DNS",
"subnet": "10.0.0.0/24",
"purpose": "admin",
"listen_port": 51820,
"status": "connected",
"peer_count": 1,
"peers": [
{
"endpoint": "91.7.98.176:54682",
"allowed_ips": "10.0.0.2/32",
"connected": true,
"handshake_ago": 50,
"transfer_rx": 1300976,
"transfer_tx": 4061948
}
]
}
}
}
Peer fields:
| Field | Description |
|---|---|
connected |
Handshake within last 180 seconds |
handshake_ago |
Seconds since last handshake |
transfer_rx |
Bytes received |
transfer_tx |
Bytes transmitted |
Audit Log¶
GET /api/audit/events?limit=200&severity=¶
Retrieve structured audit events.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
int | 200 | Max events to return |
severity |
string | — | Filter: info, warning, critical |
Response:
{
"events": [
{
"ts": "2026-04-01T14:33:43.839686+00:00",
"event": "system.started",
"severity": "info",
"details": {
"firewall_enabled": true,
"killswitch": false,
"rules_count": 2
}
}
]
}
Event types:
| Event | Severity | Trigger |
|---|---|---|
system.started |
info | Container startup |
firewall.rule_added |
info | New rule created |
firewall.rule_deleted |
info | Rule removed |
firewall.rule_updated |
info | Rule toggled/edited |
firewall.killswitch |
critical/warning | Killswitch toggled |
firewall.toggled |
warning/info | Firewall on/off |
firewall.profile_applied |
info/warning | Profile applied |
firewall.force_applied |
info | Rules force re-applied |
dns.blocking_toggled |
info | Pi-hole toggled |
routes.added |
info | Web service added |
routes.removed |
info | Web service removed |
host_route.updated |
info | Host route VPN/auth toggled |
Web Services (Routes)¶
GET /api/routes¶
List configured Traefik routes for VM services.
POST /api/routes¶
Add a new web service route.
Request Body:
PATCH /api/routes/{route_id}¶
Update a route's VPN-only or auth settings.
Request Body (all fields optional):
DELETE /api/routes/{route_id}¶
Remove a web service route.
Host Infrastructure Routes¶
Manage VPN-only access for infrastructure services defined in host-services.yml (Control Center, root redirect).
GET /api/routes/host¶
List all host infrastructure routes with current VPN status.
Response:
{
"routes": [
{
"id": "firewall",
"subdomain": "firewall.clsxx.de",
"url": "http://172.20.10.1:8089",
"service": "firewall-svc",
"vpn_only": true,
"auth_required": true,
"tls": true
}
]
}
PATCH /api/routes/host/{route_id}¶
Toggle VPN-only or auth settings on a host infrastructure route.
Request Body (all fields optional):
Note
This modifies host-services.yml directly. Docker-label routes (Traefik dashboard, Pi-hole, Fail2ban, Docs) are not managed by this endpoint.
Secrets¶
GET /api/secrets¶
List all applications and secrets with masked values.
POST /api/secrets/apps¶
Create a new application group. Body: {"name": "myapp", "description": "..."}
DELETE /api/secrets/apps/{name}¶
Delete an application and all its secrets.
POST /api/secrets/apps/{app}/secrets/{key}¶
Add a secret. Body: {"key": "API_KEY", "value": "...", "description": "..."}
PUT /api/secrets/apps/{app}/secrets/{key}¶
Update a secret's value or description. Body: {"value": "...", "description": "..."}
DELETE /api/secrets/apps/{app}/secrets/{key}¶
Delete a single secret.
POST /api/secrets/deploy¶
Deploy all secrets as per-app .env files to the Strato VM via SSH.
Debug¶
GET /api/iptables¶
Raw iptables dump (filter and nat tables).
Response:
GET /api/blocked?limit=100¶
Parsed blocked traffic entries from kernel log.
Response: