Exposed ports#
An agent that serves a chat UI, a dashboard, or an HTTP API needs a way for people to reach it. An exposed port publishes one container port at a stable URL derived from the sandbox's slug.
curl -fsS -X POST \
-H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
-H "Content-Type: application/json" \
https://agents.example.com/v1/projects/$PROJECT_ID/sandboxes \
-d '{
"image": "ghcr.io/acme/agent:1.2",
"command": "./start.sh",
"cpu": "500m", "memory": "2Gi",
"exposedPorts": [{"name": "web", "port": 8080, "auth": "private"}]
}'
Create a sandbox in production from ghcr.io/acme/agent:1.2 running
"./start.sh" with 500m CPU and 2Gi memory. Publish port 8080 as
"web" with private auth, and give me the URL.
nexusctl sandbox create --project production \
--image ghcr.io/acme/agent:1.2 \
--command "./start.sh" \
--cpu 500m --memory 2Gi \
--port name=web,port=8080,auth=private
Or in a spec file:
exposedPorts:
- name: web
port: 8080
auth: private
A sandbox supports one exposed port today. The field is a list so multiple ports can be added without a breaking change.
The URL#
The platform publishes the port at:
https://<sandbox-slug>.<sandboxIngress.host>
The slug is assigned at creation and never changes, so the URL is stable across restarts, image upgrades, and rollbacks.
Read it back from the sandbox:
curl -fsS -H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
https://agents.example.com/v1/projects/$PROJECT_ID/sandboxes/$SANDBOX_ID \
| jq -r '.exposedPorts[].url'
What URL is the nightly-refactor sandbox in production serving on?
nexusctl sandbox get nightly-refactor --project production -o json \
| jq -r '.exposedPorts[].url'
The URL is null without sandboxIngress.host
If the install was deployed without sandboxIngress.host, exposed ports still exist but resolve to no URL. Set the value and make sure *.<host> resolves to your ingress. See Install on Kubernetes.
Fields#
| Field | Rules |
|---|---|
name |
Lowercase DNS label fragment, ^[a-z][a-z0-9-]{0,30}$. Identifies the port within the sandbox. |
port |
TCP port 1–65535. The supervisor dials it on 127.0.0.1 inside the container. |
auth |
private or public. |
The agent binds the port on loopback inside its own container. Nothing else about the sandbox's network is opened by exposing a port — outbound traffic is still governed by policy, and no other port becomes reachable.
Authentication modes#
private#
Requests must carry a valid platform session. Anyone without one is sent to sign in, and access is checked against the project the sandbox belongs to.
This is the default and the right choice for anything beyond a demo.
public#
The URL opens with no platform session at all. Anyone who has the URL can reach the service.
Use public for a local trial, a demo, or a service that does its own authentication. Treat the URL as a secret, and remember that the agent behind it is running with real credentials and real access.
Health checks pair with exposed ports#
A sandbox that serves HTTP is usually worth probing. Point an HTTP health check at the same port so the platform can tell "running" from "running and answering":
exposedPorts:
- name: web
port: 8080
auth: private
healthCheck:
type: http
http:
path: /healthz
port: 8080
Related#
- Sandbox spec — declaring ports in a file
- Storage and health — probes, revisions, and rollback
- Install on Kubernetes — wildcard ingress for
*.<sandboxIngress.host> - Sandbox isolation — what an exposed port does not open up