Serve remote engines through a tunnel and a local proxy#
Status#
Accepted, 15 September 2026.
Context#
lllm2 can run llama-server on a remote GPU, starting with Modal. Bench, warm, harness wrappers, the panel and claude-sandbox all reach the engine at a loopback URL on the engine port, and bench depends on llama-server’s raw completion stream.
Modal offers two ways to reach a server in a container. A web endpoint gives a stable HTTPS URL but applies Modal’s request timeout limits, which a long prompt can exceed. A tunnel exposes a container port directly for as long as the function runs.
Another provider must be able to plug in without changes to consumers.
Decision#
The serve function opens a Modal tunnel to llama-server’s port and publishes the tunnel address. llama-server requires an API key that lllm2 generates for each launch.
lllm2 runs a streaming HTTP proxy on 127.0.0.1 at the usual engine port. It
forwards requests to the tunnel without buffering and adds the API key.
Engine.base stays a loopback URL for both local and remote engines.
The proxy and the engine lifecycle live in a provider-neutral RemoteEngine.
Each provider implements the RemoteProvider interface and registers a factory
and a GPU table.
Consequences#
Consumers need no changes, and clients keep sending placeholder tokens.
llama-server’s full native API is available, with no provider request timeout on long prompts.
Anyone who learns the tunnel address can reach llama-server’s endpoints that need no key:
/health,/v1/healthand the web UI files. Completions and the model list need the key.The local lllm2 process must stay running while the model serves. The proxy also sees every request, which drives the idle timer.
The tunnel address changes on every launch, so a client cannot connect to the remote server without lllm2.
A new provider needs only a
RemoteProviderimplementation and a GPU table.