Skip to content

Reverse Tunnels

An Axern tunnel is a reverse TCP tunnel: code inside a remote allocation calls a localhost port that Axern binds inside the allocation, and that traffic is forwarded back to a TCP target on your workstation. Use it when remote workloads need a development API server, a mock, or a local credential-holding proxy. It is the opposite of a port-forward; your machine does not use the tunnel to call the remote service.

Start the local target first, create a detached Run, and open a foreground tunnel for its allocation:

Terminal window
python3 -m http.server 8080 --bind 127.0.0.1
axern run --detach python:3.12-slim -- python -c 'import time; time.sleep(3600)'
axern tunnel open --allocation-id <allocation-id> --local 127.0.0.1:8080

The command targets the named Allocation, creates a tunnel session bound to that exact Allocation ID, waits for the allocation-local bind, and prints the session and bind addresses:

Tunnel session: tun-...
Local target: 127.0.0.1:8080
Remote bind: 127.0.0.1:42377
Press Ctrl-C to revoke the tunnel.

Inside the allocation, curl http://127.0.0.1:42377/ now reaches your local 127.0.0.1:8080. Keep the command running while the remote workload needs the local target; Ctrl-C revokes the session.

The Python SDK owns the connector and renews the tunnel TTL while the sandbox is active:

from axern_sdk import AxernClient, Sandbox
client = AxernClient.from_context("~/.config/axern/config.json")
with Sandbox(
client=client,
image="docker.io/library/python:3.12-slim",
upstream="127.0.0.1:8080",
remote_port=8786,
) as sandbox:
print(sandbox.bound_addr)
Terminal window
axern tunnel list --allocation-id <allocation-id>
axern tunnel inspect <session-id>
axern tunnel doctor --allocation-id <allocation-id> --local 127.0.0.1:8080
axern tunnel revoke <session-id> --reason manual-cleanup

Doctor checks control-plane state, gateway relay reachability, recent peer events, and the local upstream probe. Its JSON output intentionally excludes tunnel tokens. Relay connections use the gateway control edge mTLS path, so development and production contexts use the same public entry model. The local upstream is connector configuration on the caller and is never sent to or persisted by the control plane.

For the full session lifecycle and relay path, see the repository’s tunnel document.