## HTTP API Olm can be controlled with an embedded HTTP server when using `--enable-http`. This allows you to start it as a daemon and trigger it with the following endpoints. The API can listen on either a TCP address or a Unix socket/Windows named pipe. ### Socket vs TCP By default, when `--enable-http` is used, Olm listens on a TCP address (configured via `--http-addr`, default `:9452`). Alternatively, Olm can listen on a Unix socket (Linux/macOS) or Windows named pipe for local-only communication with better security. **Unix Socket (Linux/macOS):** - Socket path example: `/var/run/olm/olm.sock` - The directory is created automatically if it doesn't exist - Socket permissions are set to `0666` to allow access - Existing socket files are automatically removed on startup - Socket file is cleaned up when Olm stops **Windows Named Pipe:** - Pipe path example: `\\.\pipe\olm` - If the path doesn't start with `\`, it's automatically prefixed with `\\.\pipe\` - Security descriptor grants full access to Everyone and the current owner - Named pipes are automatically cleaned up by Windows **Connecting to the Socket:** ```bash # Linux/macOS - using curl with Unix socket curl --unix-socket /var/run/olm/olm.sock http://localhost/status --- ### POST /connect Initiates a new connection request to a Pangolin server. **Request Body:** ```json { "id": "string", "secret": "string", "endpoint": "string", "userToken": "string", "mtu": 1280, "dns": "8.8.8.8", "dnsProxyIP": "string", "upstreamDNS": ["8.8.8.8:53", "1.1.1.1:53"], "interfaceName": "olm", "holepunch": false, "tlsClientCert": "string", "pingInterval": "3s", "pingTimeout": "5s", "orgId": "string", "fingerprint": { "username": "string", "hostname": "string", "platform": "string", "osVersion": "string", "kernelVersion": "string", "arch": "string", "deviceModel": "string", "serialNumber": "string" }, "postures": {} } ``` **Required Fields:** - `id`: Olm ID generated by Pangolin - `secret`: Authentication secret for the Olm ID - `endpoint`: Target Pangolin endpoint URL **Optional Fields:** - `userToken`: User authentication token - `mtu`: MTU for the internal WireGuard interface (default: 1280) - `dns`: DNS server to use for resolving the endpoint - `dnsProxyIP`: DNS proxy IP address - `upstreamDNS`: Array of upstream DNS servers - `interfaceName`: Name of the WireGuard interface (default: olm) - `holepunch`: Enable NAT hole punching (default: false) - `tlsClientCert`: TLS client certificate - `pingInterval`: Interval for pinging the server (default: 3s) - `pingTimeout`: Timeout for each ping (default: 5s) - `orgId`: Organization ID to connect to - `fingerprint`: Device fingerprinting information (should be set before connecting) - `username`: Current username on the device - `hostname`: Device hostname - `platform`: Operating system platform (macos, windows, linux, ios, android, unknown) - `osVersion`: Operating system version - `kernelVersion`: Kernel version - `arch`: System architecture (e.g., amd64, arm64) - `deviceModel`: Device model identifier - `serialNumber`: Device serial number - `postures`: Device posture/security information **Response:** - **Status Code:** `202 Accepted` - **Content-Type:** `application/json` ```json { "status": "connection request accepted" } ``` **Error Responses:** - `405 Method Not Allowed` - Non-POST requests - `400 Bad Request` - Invalid JSON or missing required fields - `409 Conflict` - Already connected to a server (disconnect first) --- ### GET /status Returns the current connection status, registration state, and peer information. **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "connected": true, "registered": true, "terminated": false, "version": "1.0.0", "agent": "olm", "orgId": "org_123", "peers": { "10": { "siteId": 10, "name": "Site A", "connected": true, "rtt": 145338339, "lastSeen": "2025-08-13T14:39:17.208334428-07:00", "endpoint": "p.fosrl.io:21820", "isRelay": true, "peerAddress": "100.89.128.5", "holepunchConnected": false }, "8": { "siteId": 8, "name": "Site B", "connected": false, "rtt": 0, "lastSeen": "2025-08-13T14:39:19.663823645-07:00", "endpoint": "p.fosrl.io:21820", "isRelay": true, "peerAddress": "100.89.128.10", "holepunchConnected": false } }, "networkSettings": { "tunnelIP": "100.89.128.3/20" } } ``` **Fields:** - `connected`: Boolean indicating if connected to Pangolin - `registered`: Boolean indicating if registered with the server - `terminated`: Boolean indicating if the connection was terminated - `version`: Olm version string - `agent`: Agent identifier - `orgId`: Current organization ID - `peers`: Map of peer statuses by site ID - `siteId`: Peer site identifier - `name`: Site name - `connected`: Boolean peer connection state - `rtt`: Peer round-trip time (integer, nanoseconds) - `lastSeen`: Last time peer was seen (RFC3339 timestamp) - `endpoint`: Peer endpoint address - `isRelay`: Whether the peer is relayed (true) or direct (false) - `peerAddress`: Peer's IP address in the tunnel - `holepunchConnected`: Whether holepunch connection is established - `networkSettings`: Current network configuration including tunnel IP **Error Responses:** - `405 Method Not Allowed` - Non-GET requests --- ### POST /disconnect Disconnects from the current Pangolin server and tears down the WireGuard tunnel. **Request Body:** None required **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "status": "disconnect initiated" } ``` **Error Responses:** - `405 Method Not Allowed` - Non-POST requests - `409 Conflict` - Not currently connected to a server --- ### POST /switch-org Switches to a different organization while maintaining the connection. **Request Body:** ```json { "orgId": "string" } ``` **Required Fields:** - `orgId`: The organization ID to switch to **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "status": "org switch request accepted" } ``` **Error Responses:** - `405 Method Not Allowed` - Non-POST requests - `400 Bad Request` - Invalid JSON or missing orgId field - `500 Internal Server Error` - Org switch failed --- ### PUT /metadata Updates device fingerprinting and posture information. This endpoint can be called at any time to update metadata, but it's recommended to provide this information in the initial `/connect` request or immediately before connecting. **Request Body:** ```json { "fingerprint": { "username": "string", "hostname": "string", "platform": "string", "osVersion": "string", "kernelVersion": "string", "arch": "string", "deviceModel": "string", "serialNumber": "string" }, "postures": {} } ``` **Optional Fields:** - `fingerprint`: Device fingerprinting information - `username`: Current username on the device - `hostname`: Device hostname - `platform`: Operating system platform (macos, windows, linux, ios, android, unknown) - `osVersion`: Operating system version - `kernelVersion`: Kernel version - `arch`: System architecture (e.g., amd64, arm64) - `deviceModel`: Device model identifier - `serialNumber`: Device serial number - `postures`: Device posture/security information (object with arbitrary key-value pairs) **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "status": "metadata updated" } ``` **Error Responses:** - `405 Method Not Allowed` - Non-PUT requests - `400 Bad Request` - Invalid JSON **Note:** It's recommended to call this endpoint BEFORE `/connect` to ensure fingerprinting information is available during the initial connection handshake. --- ### POST /exit Initiates a graceful shutdown of the Olm process. **Request Body:** None required **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "status": "shutdown initiated" } ``` **Note:** The response is sent before shutdown begins. There is a 100ms delay before the actual shutdown to ensure the response is delivered. **Error Responses:** - `405 Method Not Allowed` - Non-POST requests --- ### GET /health Simple health check endpoint to verify the API server is running. **Response:** - **Status Code:** `200 OK` - **Content-Type:** `application/json` ```json { "status": "ok" } ``` **Error Responses:** - `405 Method Not Allowed` - Non-GET requests --- ## Usage Examples ### Update metadata before connecting (recommended) ```bash curl -X PUT http://localhost:9452/metadata \ -H "Content-Type: application/json" \ -d '{ "fingerprint": { "username": "john", "hostname": "johns-laptop", "platform": "macos", "osVersion": "14.2.1", "arch": "arm64", "deviceModel": "MacBookPro18,3" } }' ``` ### Connect to a peer ```bash curl -X POST http://localhost:9452/connect \ -H "Content-Type: application/json" \ -d '{ "id": "31frd0uzbjvp721", "secret": "h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6", "endpoint": "https://example.com" }' ``` ### Connect with additional options ```bash curl -X POST http://localhost:9452/connect \ -H "Content-Type: application/json" \ -d '{ "id": "31frd0uzbjvp721", "secret": "h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6", "endpoint": "https://example.com", "mtu": 1400, "holepunch": true, "pingInterval": "5s" }' ``` ### Check connection status ```bash curl http://localhost:9452/status ``` ### Switch organization ```bash curl -X POST http://localhost:9452/switch-org \ -H "Content-Type: application/json" \ -d '{"orgId": "org_456"}' ``` ### Disconnect from server ```bash curl -X POST http://localhost:9452/disconnect ``` ### Health check ```bash curl http://localhost:9452/health ``` ### Shutdown Olm ```bash curl -X POST http://localhost:9452/exit ``` ### Using Unix socket (Linux/macOS) ```bash curl --unix-socket /var/run/olm/olm.sock http://localhost/status curl --unix-socket /var/run/olm/olm.sock -X POST http://localhost/disconnect ```