Outbound is a HTTP tunneling system that exposes local services through a public edge server using a long-lived gRPC stream.
[HTTP client] ── HTTPS ──▶ [edge :443 via proxy] ── gRPC ──▶ [agent] ── HTTP ──▶ [local service]
- The edge runs on a public server. It accepts HTTP requests and dispatches them over gRPC to the appropriate agent.
- The agent runs on your local machine. It connects to the edge, registers named services, and proxies inbound requests to local ports.
- Routing is header-based — callers include
X-Outbound-AgentandX-Outbound-Serviceon every request.
go build -o outbound-edge ./cmd/edge
go build -o outbound-agent ./cmd/agent./outbound-edge --http-addr :8080 --grpc-addr :8081 --auth-secret mysecretExpose a local service running on port 3000 as the service named web:
./outbound-agent \
--id my-machine \
--service web=3000 \
--token mysecret \
--edge edge.example.com:443Pass --insecure for local development when the edge has no TLS:
./outbound-agent --id my-machine --service web=3000 --token mysecret --edge localhost:8081 --insecurecurl \
-H "X-Outbound-Agent: my-machine" \
-H "X-Outbound-Service: web" \
https://edge.example.com/./outbound-agent \
--id my-machine \
--service web=3000 \
--service api=8000 \
--service metrics=9090 \
--edge edge.example.com:443curl -H "X-Outbound-Agent: my-machine" -H "X-Outbound-Service: api" https://edge.example.com/v1/users
curl -H "X-Outbound-Agent: my-machine" -H "X-Outbound-Service: metrics" https://edge.example.com/metricsTLS is not handled inside the edge binary. Put Caddy (or any reverse proxy) in front of the edge and terminate TLS there. The proxy forwards HTTP traffic to :8080 and gRPC traffic to :8081.
[HTTP client] ─── HTTPS (443) ───┐
[Caddy] ─── plain HTTP ──▶ edge :8080
[agent] ─── gRPC+TLS (443) ───┘ ─── plain gRPC ──▶ edge :8081
edge.example.com {
@grpc {
header Content-Type application/grpc*
}
reverse_proxy @grpc h2c://127.0.0.1:8081
reverse_proxy 127.0.0.1:8080
}Keep both ports bound to 127.0.0.1 so only the proxy can reach them.
| Flag | Default | Description |
|---|---|---|
--http-addr |
:8080 |
Address for the public HTTP listener |
--grpc-addr |
:8081 |
Address for the agent gRPC listener |
--auth-secret |
(none) | Shared secret required for agent registration; if unset all connections are accepted |
--request-timeout |
30s |
Timeout for proxied HTTP requests |
--keepalive-interval |
15s |
Interval between keepalive pings sent to agents |
--keepalive-timeout |
5s |
Time to wait for a pong before dropping the session |
--shutdown-timeout |
30s |
Graceful shutdown timeout |
| Flag | Default | Description |
|---|---|---|
--id |
(auto-generated) | Agent identifier |
--edge |
localhost:8081 |
Edge address (host:port) |
--token |
(none) | Shared auth token for edge registration |
--service |
(required, repeatable) | Service mapping name=port |
--insecure |
false |
Disable TLS on the gRPC connection (local dev only) |