# GracePress MeshPress Bridge Small local HTTP bridge between WordPress/MeshPress and MeshCentral. The bridge runs beside MeshCentral and uses MeshCentral's official `meshctrl` tool to read device groups and devices. WordPress talks to this bridge instead of trying to speak MeshCentral websocket protocol directly. ## Endpoints - `GET /api/health` - `GET /api/status` - `GET /api/self-test` - `GET /api/groups` - `GET /api/users` - `GET /api/events?limit=50` - `GET /api/serverinfo` - `GET /api/devices` - `GET /api/device/:nodeId` - `GET /api/fleet` - `POST /api/push-now` - `POST /api/cache/clear` - `GET /api/link/desktop/:nodeId` - `GET /api/link/terminal/:nodeId` - `GET /api/link/files/:nodeId` - `GET /api/link/:mode/:nodeId?link_mode=both` - `GET /api/agent-links/:groupId` - `POST /api/groups/create` - `POST /api/groups/edit` - `POST /api/groups/remove` - `POST /api/groups/add-user` - `POST /api/groups/remove-user` - `POST /api/invite-link` - `POST /api/device/message` - `POST /api/device/toast` - `POST /api/action` All endpoints require `Authorization: Bearer TOKEN`. If `MESHPRESS_BRIDGE_TOKEN` is empty, protected requests are rejected. `/api/action` is intentionally locked down for now. It returns a clear unsupported-command response until each broad remote-command workflow is whitelisted and tested. Provisioning and device-command endpoints require: ```bash MESHPRESS_ALLOW_COMMANDS="1" ``` Without that flag the bridge will read MeshCentral state but refuse provisioning actions. ## Install ```bash cd /storage/meshcentral-workspace/bridge/meshpress-bridge sudo ./install.sh sudo nano /etc/gracepress/meshpress-bridge.env pm2 restart gp-meshpress-bridge ``` ## Required Config ```bash MESHPRESS_BRIDGE_PORT="3099" MESHPRESS_BRIDGE_BIND="127.0.0.1" MESHPRESS_BRIDGE_TOKEN="generated-secret" MESHPRESS_ALLOWED_IPS="" MESHPRESS_AUTH_WINDOW_SECONDS="900" MESHPRESS_AUTH_MAX_FAILURES="30" MESHCTRL_URL="wss://127.0.0.1" PUBLIC_MESH_URL="https://mesh.yourdomain.com" MESHCTRL_USER="admin" MESHCTRL_PASS="" MESHCTRL_DOMAIN="" MESHCTRL_LOGIN_KEY_FILE="/etc/gracepress/meshcentral-login.key" MESHCTRL_PATH="" MESHCTRL_IGNORE_CERT="0" MESHPRESS_LINK_HIDE="" MESHPRESS_LINK_MODE="gotonode" MESHPRESS_ALLOW_COMMANDS="0" WP_DOMAIN="https://christp2p.com" WP_API_KEY="same-token-used-in-meshpress" MESHPRESS_PUSH_INTERVAL_SECONDS="3600" MESHPRESS_PUSH_EVENTS="1" ``` If auto-detection cannot find `meshctrl`, set `MESHCTRL_PATH` to the full path of `meshctrl.js`. When `WP_DOMAIN` and `WP_API_KEY` are set, the bridge pushes fleet snapshots to WordPress at startup and then every hour. When `MESHPRESS_PUSH_EVENTS` is enabled, selected bridge lifecycle events are posted to MeshPress so WordPress can record them through OmniLog. ## Public Exposure Hardening Do not expose port `3099` to the public internet without firewall/VPN controls. Preferred options: 1. Bind to localhost and proxy privately: ```bash MESHPRESS_BRIDGE_BIND="127.0.0.1" ``` 2. Bind to a Tailscale address only: ```bash MESHPRESS_BRIDGE_BIND="100.x.y.z" ``` 3. If the bridge must listen on all interfaces temporarily, restrict source IPs at both the firewall and app layer: ```bash MESHPRESS_BRIDGE_BIND="0.0.0.0" MESHPRESS_ALLOWED_IPS="WORDPRESS_SERVER_IP,YOUR_ADMIN_IP" ``` The app-layer allowlist only accepts exact IP addresses. It is a backstop, not a replacement for firewall rules. ## Diagnostics Use MeshPress > Diagnostics & Manual Actions first. It calls these bridge endpoints: ```bash curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/health curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/version curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/status curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/self-test curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/groups?refresh=1 curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/devices?refresh=1 ``` `/api/self-test` verifies the bridge can find `meshctrl`, has an auth method, has a public MeshCentral URL, and can list device groups and devices. For direct session links, test both URL styles: ```bash curl -H "Authorization: Bearer TOKEN" "http://127.0.0.1:3099/api/session-links/NODEID" curl -H "Authorization: Bearer TOKEN" "http://127.0.0.1:3099/api/link/console/NODEID?link_mode=all" ``` To trigger a catalog-managed bridge update from MeshPress admin or curl: ```bash curl -X POST -H "Authorization: Bearer TOKEN" http://127.0.0.1:3099/api/update-now ``` To test the first provisioning path, enable commands and create a temporary group: ```bash curl -X POST \ -H "Authorization: Bearer TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"MeshPress Test Group","description":"Manual bridge validation"}' \ http://127.0.0.1:3099/api/groups/create ``` ## MeshCentral Auth The bridge supports either a MeshCentral login key file or a dedicated integration username/password. For username/password auth, set: ```bash MESHCTRL_USER="your-generated-integration-user" MESHCTRL_PASS="your-generated-integration-password" ``` If `MESHCTRL_LOGIN_KEY_FILE` exists, the bridge will prefer it. If the file does not exist and `MESHCTRL_PASS` is set, it will use username/password auth. ## MeshCentral Login Key Option On the MeshCentral server: ```bash cd /opt/meshcentral sudo node node_modules/meshcentral --loginTokenKey > /etc/gracepress/meshcentral-login.key sudo chmod 600 /etc/gracepress/meshcentral-login.key ``` MeshCentral must have login tokens enabled in `meshcentral-data/config.json`: ```json { "settings": { "allowLoginToken": true } } ``` Restart MeshCentral after changing config.