Session-bridge architecture
How gemini-chrome runs a persistent browser session inside an Azure VM behind Caddy and Cloudflare.
Azure VM — Sweden Central
A single Standard D2s v3 instance hosts the entire runtime. The region was chosen for low-latency peering with Cloudflare’s Stockholm edge. The VM runs Windows Server 2022 with Hyper-V disabled and RDP locked to a bastion-only subnet.
Headed Chromium
Chromium launches with --headless=new but keeps a virtual display via the Windows Desktop Session. A persistent user-data directory survives reboots, so cookies, localStorage, and service-worker registrations are retained across restarts.
Persistent profile
The profile directory is backed by the VM’s temporary disk (D:\). On startup a scheduled task snapshots the profile to Azure Blob cool tier every 15 minutes. If the VM is reprovisioned, the latest snapshot is restored before Chromium starts.
Caddy + TLS
Caddy terminates TLS with a Let’s Encrypt certificate for the internal hostname. It reverse-proxies the Chrome DevTools Protocol WebSocket on /cdp and serves a static health-check page on /. Mutual TLS is enforced for all non-health endpoints.
Cloudflare
Cloudflare sits in front of the Caddy listener. The origin is exposed only via a Cloudflare Tunnel (cloudflared), so no inbound ports are open on the Azure NSG. WAF rules block non-Meridian User-Agent strings and rate-limit WebSocket upgrade attempts to 5/s per IP.
Session lifecycle
A session is created when Meridian’s API calls the bridge’s POST /sessions endpoint. The bridge spawns a new browser context (not a full profile) so multiple users share one Chromium process safely. Idle contexts are evicted after 10 minutes. The bridge reports metrics to Meridian every 30 seconds via a dedicated telemetry pipe.