- HTTP/WebSocket reverse proxy that routes to sandbox instances.
- Watches sandbox CRs (BatchSandbox or AgentSandbox, chosen by
--provider-type) in a target Namespace:- BatchSandbox: reads endpoints from
sandbox.opensandbox.io/endpointsannotation. - AgentSandbox: reads
status.serviceFQDN.
- BatchSandbox: reads endpoints from
- Exposes
/status.okhealth check; prints build metadata (version, commit, time, Go/platform) at startup.
go run main.go \
--namespace <target-namespace> \
--provider-type <batchsandbox|agent-sandbox> \
--mode <header|uri> \
--port 28888 \
--log-level infoEndpoints: / (proxy), /status.ok (health).
The ingress supports two routing modes for discovering sandbox instances:
Routes requests based on the OpenSandbox-Ingress-To header or the Host header.
Format:
- Header:
OpenSandbox-Ingress-To: <sandbox-id>-<port> - Host:
<sandbox-id>-<port>.<domain>
Example:
# Using OpenSandbox-Ingress-To header
curl -H "OpenSandbox-Ingress-To: my-sandbox-8080" https://ingress.opensandbox.io/api/users
# Using Host header
curl -H "Host: my-sandbox-8080.example.com" https://ingress.opensandbox.io/api/usersParsing logic:
- Extracts sandbox ID and port from the format
<sandbox-id>-<port> - The last segment after the last
-is treated as the port - Everything before the last
-is treated as the sandbox ID
Routes requests based on the URI path structure.
Format:
/<sandbox-id>/<sandbox-port>/<path-to-request>
Example:
# Request to sandbox "my-sandbox" on port 8080, forwarding to /api/users
curl https://ingress.opensandbox.io/my-sandbox/8080/api/users
# WebSocket example
wss://ingress.opensandbox.io/my-sandbox/8080/wsParsing logic:
- First path segment: sandbox ID
- Second path segment: sandbox port
- Remaining path: forwarded to the target sandbox as the request URI
- If no remaining path is provided, defaults to
/
Use cases:
- When you cannot modify HTTP headers
- When you need path-based routing
- For simpler client configuration without custom headers
When enabled, the ingress publishes renew-intent events to a Redis list on each proxied request (after resolving the sandbox). The OpenSandbox server consumes these events and may extend sandbox expiration for sandboxes that opted in at creation time. See OSEP-0009 for the full design.
Requirements: The server must have renew_intent (and Redis consumer for ingress mode) enabled; the sandbox must opt in via extensions["access.renew.extend.seconds"] (decimal integer string between 300 and 86400 seconds, see OSEP-0009). This feature is best-effort and disabled by default.
| Flag | Default | Description |
|---|---|---|
--renew-intent-enabled |
false |
Enable publishing renew-intent events to Redis |
--renew-intent-redis-dsn |
redis://127.0.0.1:6379/0 |
Redis DSN (may include user:password@) |
--renew-intent-queue-key |
opensandbox:renew:intent |
Redis List key for intent payloads |
--renew-intent-queue-max-len |
0 |
Max list length (0 = no cap); LTRIM applied when > 0 |
--renew-intent-min-interval |
60 |
Min seconds between intents per sandbox (client-side throttle) |
Example (with Redis):
go run main.go \
--namespace opensandbox \
--renew-intent-enabled \
--renew-intent-redis-dsn "redis://user:pass@redis:6379/0" \
--renew-intent-min-interval 120cd components/ingress
make build
# override build metadata if needed
VERSION=1.2.3 GIT_COMMIT=$(git rev-parse HEAD) BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") make buildDockerfile already wires ldflags via build args:
docker build \
--build-arg VERSION=$(git describe --tags --always --dirty) \
--build-arg GIT_COMMIT=$(git rev-parse HEAD) \
--build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-t opensandbox/ingress:local .build.sh uses buildx to build/push linux/amd64 and linux/arm64:
cd components/ingress
TAG=local VERSION=1.2.3 GIT_COMMIT=abc BUILD_TIME=2025-01-01T00:00:00Z bash build.sh- Access to Kubernetes API (in-cluster or via KUBECONFIG).
- If
--provider-type=batchsandbox: BatchSandbox CRs in the specified Namespace withsandbox.opensandbox.io/endpointsannotation containing Pod IPs. - If
--provider-type=agent-sandbox: AgentSandbox CRs withstatus.serviceFQDNpopulated.
- Routing key priority:
OpenSandbox-Ingress-Toheader first, otherwise Host parsing<sandbox-name>-<port>.*. - Sandbox name extracted from request is used to query the sandbox CR (BatchSandbox or AgentSandbox) via informer cache:
- BatchSandbox → endpoints annotation.
- AgentSandbox →
status.serviceFQDN.
- The original request path is preserved and forwarded to the target sandbox.
- Routing information is extracted from the URI path:
/<sandbox-id>/<sandbox-port>/<path-to-request>. - The sandbox ID and port are extracted from the first two path segments.
- The remaining path (
/<path-to-request>) is forwarded to the target sandbox as the request URI. - If no remaining path is provided, the request URI defaults to
/.
- Error handling:
ErrSandboxNotFound(sandbox resource not exists) → HTTP 404ErrSandboxNotReady(not enough replicas, missing endpoints, invalid config) → HTTP 503- Other errors (K8s API errors, etc.) → HTTP 502
- WebSocket path forwards essential headers and X-Forwarded-*; HTTP path strips
OpenSandbox-Ingress-Tobefore proxying (header mode only).
cd components/ingress
go test ./...Key code:
main.go: entrypoint and handlers.pkg/proxy/: HTTP/WebSocket proxy logic, sandbox endpoint resolution.pkg/sandbox/: Sandbox provider abstraction and BatchSandbox implementation.version/: build metadata output (populated via ldflags).