Skip to content

Server API Reference

The Bifrost server exposes a REST API for management, monitoring, and configuration.

Default Address: http://localhost:7082

Check if the server is healthy and operational.

GET /api/v1/health

Response:

{
"status": "healthy",
"time": "2024-01-15T10:00:00Z"
}
FieldTypeDescription
statusstringhealthy or degraded
timestringISO 8601 timestamp

Get server version information.

GET /api/v1/version

Response:

{
"version": "1.0.0",
"git_commit": "abc123",
"build_time": "2024-01-15T10:00:00Z",
"go_version": "go1.22.0",
"platform": "linux/amd64"
}

Get server running status.

GET /api/v1/status

Response:

{
"status": "running",
"time": "2024-01-15T10:00:00Z",
"version": "1.0.0",
"backends": 3
}

Get aggregated server statistics.

GET /api/v1/stats

Response:

{
"total_connections": 5000,
"active_connections": 25,
"bytes_sent": 104857600,
"bytes_received": 209715200,
"backends": {
"total": 3,
"healthy": 3
},
"time": "2024-01-15T10:00:00Z"
}

Get all configured backends with their status and statistics.

GET /api/v1/backends

Response:

[
{
"name": "direct",
"type": "direct",
"healthy": true,
"stats": {
"active_connections": 5,
"total_connections": 100,
"bytes_sent": 1024000,
"bytes_received": 2048000
}
},
{
"name": "wireguard-us",
"type": "wireguard",
"healthy": true,
"stats": {
"active_connections": 10,
"total_connections": 500,
"bytes_sent": 5120000,
"bytes_received": 10240000
}
}
]

Get a specific backend by name.

GET /api/v1/backends/{name}

Path Parameters:

ParameterTypeDescription
namestringBackend name

Response:

{
"name": "wireguard-us",
"type": "wireguard",
"healthy": true,
"stats": {
"active_connections": 10,
"total_connections": 500,
"bytes_sent": 5120000,
"bytes_received": 10240000
}
}

Add a new backend to the proxy server.

POST /api/v1/backends

Request Body:

{
"name": "my-proxy",
"type": "httpproxy",
"enabled": true,
"httpproxy": {
"address": "proxy.example.com:8080",
"username": "user",
"password": "pass"
}
}

Supported Backend Types:

  • direct - Direct internet connection
  • wireguard - WireGuard VPN tunnel
  • openvpn - OpenVPN tunnel
  • httpproxy - HTTP/HTTPS proxy
  • socks5 - SOCKS5 proxy

Response (201 Created):

{
"status": "created",
"backend": "my-proxy",
"type": "httpproxy"
}

Remove a backend from the proxy server.

DELETE /api/v1/backends/{name}

Response:

{
"status": "removed",
"backend": "my-proxy"
}

Get detailed statistics for a specific backend.

GET /api/v1/backends/{name}/stats

Response:

{
"active_connections": 10,
"total_connections": 500,
"bytes_sent": 5120000,
"bytes_received": 10240000,
"errors": 0,
"latency_ms": 45
}

Test connectivity through a specific backend.

POST /api/v1/backends/{name}/test

Request Body (optional):

{
"target": "google.com:443",
"timeout": "10s"
}

Response:

{
"status": "success",
"backend": "wireguard-us",
"target": "google.com:443",
"duration": "45ms",
"healthy": true
}

Get the current configuration with sensitive values redacted.

GET /api/v1/config

Response: Sanitized ServerConfig object with passwords, keys, and tokens masked.


Get the complete configuration for editing (use with caution).

GET /api/v1/config/full

Response: Full ServerConfig object including sensitive values.


Get metadata about configuration sections, including hot-reload capabilities.

GET /api/v1/config/meta

Response:

[
{
"section": "routes",
"hot_reloadable": true,
"description": "Routing rules can be changed without restart"
},
{
"section": "rate_limit",
"hot_reloadable": true,
"description": "Rate limiting settings can be changed without restart"
},
{
"section": "server",
"hot_reloadable": false,
"description": "Server listener changes require restart"
},
{
"section": "backends",
"hot_reloadable": false,
"description": "Backend changes require restart"
}
]

Save configuration changes.

PUT /api/v1/config

Request Body:

{
"config": {
"server": { ... },
"backends": [ ... ],
"routes": [ ... ]
},
"create_backup": true
}

Response:

{
"success": true,
"message": "Configuration saved",
"requires_restart": false,
"changed_sections": ["routes"]
}

Validate configuration without saving.

POST /api/v1/config/validate

Request Body: ServerConfig object

Response:

{
"valid": true,
"errors": [],
"warnings": ["Backend 'old-vpn' is enabled but not configured"]
}

Reload configuration from file (hot-reload for supported sections).

POST /api/v1/config/reload

Response:

{
"message": "Config reloaded successfully",
"time": "2024-01-15T10:00:00Z"
}

Get all configured routing rules.

GET /api/v1/routes

Response:

[
{
"name": "internal",
"domains": ["*.internal.company.com", "intranet.*"],
"backend": "wireguard-corp",
"enabled": true,
"priority": 100
},
{
"name": "streaming",
"domains": ["*.netflix.com", "*.youtube.com"],
"backends": ["direct", "wireguard-us"],
"enabled": true,
"priority": 50
}
]

Add a new routing rule.

POST /api/v1/routes

Request Body:

{
"name": "social-media",
"domains": ["*.twitter.com", "*.facebook.com", "*.instagram.com"],
"backend": "direct",
"enabled": true,
"priority": 75
}

Response (201 Created):

{
"status": "created",
"route": "social-media",
"domains": ["*.twitter.com", "*.facebook.com", "*.instagram.com"],
"backend": "direct"
}

Remove a routing rule.

DELETE /api/v1/routes/{name}

Response:

{
"status": "removed",
"route": "social-media"
}

Get recent request log entries (requires enable_request_log: true in config).

GET /api/v1/requests
GET /api/v1/requests?limit=50
GET /api/v1/requests?since=123
GET /api/v1/requests?offset=100

Query Parameters:

ParameterTypeDefaultDescription
limitint100Maximum entries to return
sinceint-Get entries since this ID
offsetint0Skip this many entries

Response:

{
"enabled": true,
"requests": [
{
"id": 1,
"timestamp": "2024-01-15T10:00:00Z",
"method": "GET",
"host": "api.example.com",
"path": "/v1/users",
"url": "https://api.example.com/v1/users",
"user_agent": "Mozilla/5.0...",
"client_ip": "192.168.1.100",
"username": "admin",
"backend": "direct",
"status_code": 200,
"bytes_sent": 1024,
"bytes_recv": 2048,
"duration_ms": 150,
"protocol": "HTTP"
}
]
}

Get request log statistics.

GET /api/v1/requests/stats

Response:

{
"enabled": true,
"count": 1500,
"max_size": 10000
}

Clear all request log entries.

DELETE /api/v1/requests

Response:

{
"message": "Request log cleared"
}

Get all currently active connections.

GET /api/v1/connections

Response:

{
"connections": [
{
"id": "20240115100000-1",
"client_ip": "192.168.1.100",
"client_port": "54321",
"host": "api.example.com:443",
"backend": "direct",
"protocol": "CONNECT",
"start_time": "2024-01-15T10:00:00Z",
"bytes_sent": 1024,
"bytes_recv": 2048
}
],
"count": 1,
"time": "2024-01-15T10:00:05Z"
}

Get unique clients with aggregated statistics.

GET /api/v1/connections/clients

Response:

{
"clients": [
{
"client_ip": "192.168.1.100",
"connections": 5,
"bytes_sent": 10240,
"bytes_recv": 20480,
"first_seen": "2024-01-15T09:00:00Z"
}
],
"count": 1,
"time": "2024-01-15T10:00:05Z"
}

Get cache statistics.

GET /api/v1/cache/stats

Response:

{
"enabled": true,
"hit_rate": 0.85,
"total_requests": 12450,
"cache_hits": 10582,
"cache_misses": 1868,
"storage_type": "tiered",
"rules_count": 5,
"memory": {
"entries": 4521,
"size_bytes": 1073741824,
"max_size_bytes": 2147483648
},
"disk": {
"entries": 892,
"size_bytes": 107374182400,
"max_size_bytes": 536870912000
}
}

Get cached entries with optional filtering.

GET /api/v1/cache/entries
GET /api/v1/cache/entries?domain=*.steamcontent.com
GET /api/v1/cache/entries?limit=10&offset=0

Query Parameters:

ParameterTypeDefaultDescription
domainstring-Filter by domain pattern
limitint100Maximum entries (max 1000)
offsetint0Skip entries for pagination

Response:

{
"entries": [
{
"key": "ab12cd34...",
"url": "http://cdn.steamcontent.com/depot/123/chunk/abc",
"host": "cdn.steamcontent.com",
"size": 1048576,
"content_type": "application/octet-stream",
"created_at": "2024-01-15T10:30:00Z",
"expires_at": "2025-01-15T10:30:00Z"
}
],
"total": 892,
"offset": 0,
"limit": 10
}

Get metadata for a specific cache entry.

GET /api/v1/cache/entries/{key}

Delete a specific cache entry.

DELETE /api/v1/cache/entries/{key}

Response:

{
"message": "Cache entry deleted",
"key": "ab12cd34..."
}

Clear the entire cache.

DELETE /api/v1/cache/entries?confirm=true

Response:

{
"message": "Cache cleared",
"time": "2024-01-15T10:00:00Z"
}

Purge all cache entries for a domain.

DELETE /api/v1/cache/domain/{domain}

Response:

{
"message": "Domain purged from cache",
"domain": "cdn.steamcontent.com",
"deleted": 150
}

Get all caching rules.

GET /api/v1/cache/rules

Response:

{
"rules": [
{
"name": "steam",
"domains": ["*.steamcontent.com", "content*.steampowered.com"],
"enabled": true,
"ttl": "8760h0m0s",
"priority": 100,
"preset": "steam"
}
],
"count": 5
}

Add a custom caching rule.

POST /api/v1/cache/rules

Request Body:

{
"name": "my-cdn",
"domains": ["cdn.example.com", "assets.example.com"],
"enabled": true,
"ttl": "168h",
"priority": 50
}

Response:

{
"message": "Cache rule created",
"rule": "my-cdn"
}

Update an existing cache rule.

PUT /api/v1/cache/rules/{name}

Request Body:

{
"enabled": false
}

Delete a cache rule.

DELETE /api/v1/cache/rules/{name}

Get available caching presets.

GET /api/v1/cache/presets

Response:

{
"presets": [
{
"name": "steam",
"description": "Steam game downloads and updates",
"domains": ["*.steamcontent.com", "content*.steampowered.com"],
"ttl": "8760h0m0s",
"priority": 100
},
{
"name": "epic-games",
"description": "Epic Games Store downloads",
"domains": ["*.epicgames.com", "download.epicgames.com"],
"ttl": "8760h0m0s",
"priority": 100
}
],
"count": 10
}

POST /api/v1/cache/presets/{name}/enable
POST /api/v1/cache/presets/{name}/disable

Response:

{
"message": "Preset enabled",
"preset": "steam"
}

Get all mesh networks.

GET /api/v1/mesh/networks

Response:

{
"networks": [
{
"id": "net-abc123",
"name": "Home Network",
"cidr": "10.100.0.0/24",
"peer_count": 5,
"created": "2024-01-01T00:00:00Z"
}
]
}

Create a new mesh network.

POST /api/v1/mesh/networks

Request Body:

{
"id": "net-xyz789",
"name": "Office Network",
"cidr": "10.200.0.0/24"
}

Response:

{
"id": "net-xyz789",
"name": "Office Network",
"cidr": "10.200.0.0/24",
"peer_count": 0,
"created": "2024-01-15T10:00:00Z"
}

Get details of a specific mesh network.

GET /api/v1/mesh/networks/{networkID}

Delete a mesh network.

DELETE /api/v1/mesh/networks/{networkID}

Register a peer to a mesh network.

POST /api/v1/mesh/networks/{networkID}/peers

Request Body:

{
"network_id": "net-abc123",
"peer": {
"id": "peer-xyz789",
"name": "laptop-work",
"public_key": "base64-encoded-key",
"endpoints": [
{
"address": "192.168.1.100",
"port": 51820,
"type": "lan",
"priority": 100
}
]
}
}

Response:

{
"success": true,
"virtual_ip": "10.100.0.5",
"peers": [
{
"id": "peer-abc123",
"name": "desktop-home",
"virtual_ip": "10.100.0.2",
"endpoints": [...]
}
]
}

Get all peers in a mesh network.

GET /api/v1/mesh/networks/{networkID}/peers

Get details of a specific peer.

GET /api/v1/mesh/networks/{networkID}/peers/{peerID}

Update peer information.

PATCH /api/v1/mesh/networks/{networkID}/peers/{peerID}

Request Body:

{
"endpoints": [...],
"metadata": {"location": "office"}
}

Remove a peer from the mesh network.

DELETE /api/v1/mesh/networks/{networkID}/peers/{peerID}

Update peer heartbeat (keep-alive).

POST /api/v1/mesh/networks/{networkID}/peers/{peerID}/heartbeat

Bifrost automatically generates PAC (Proxy Auto-Configuration) files based on routing rules.

GET /proxy.pac
GET /wpad.dat

Response (application/x-ns-proxy-autoconfig):

function FindProxyForURL(url, host) {
if (shExpMatch(host, "*.internal.company.com")) {
return "PROXY bifrost.example.com:7080; DIRECT";
}
return "DIRECT";
}

Browser Configuration:

  • macOS: System Preferences → Network → Advanced → Proxies → Automatic Proxy Configuration
  • Windows: Settings → Network → Proxy → Use setup script
  • Firefox: Settings → Network Settings → Automatic proxy configuration URL
  • Chrome: Uses system settings or Proxy SwitchyOmega extension