Skip to content

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:

{
  "description": "HTTPS outbound",
  "protocol": "tcp",
  "port": 443,
  "destination": null
}
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:

{
  "enabled": false
}

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:

{
  "killswitch": true
}

POST /api/firewall/toggle

Toggle the firewall on/off. When off, all traffic is accepted.

Response:

{
  "enabled": false
}

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:

{
  "subdomain": "myapp",
  "vm_port": 8080,
  "auth_required": true,
  "vpn_only": true
}

PATCH /api/routes/{route_id}

Update a route's VPN-only or auth settings.

Request Body (all fields optional):

{
  "vpn_only": false,
  "auth_required": true
}

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):

{
  "vpn_only": false,
  "auth_required": true
}

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:

{
  "filter": "...",
  "nat": "..."
}

GET /api/blocked?limit=100

Parsed blocked traffic entries from kernel log.

Response:

{
  "entries": [
    {
      "type": "blocked",
      "src": "192.168.10.10",
      "dst": "8.8.8.8",
      "proto": "TCP",
      "src_port": 45123,
      "dst_port": 443,
      "timestamp": "14:30:22"
    }
  ]
}