Every service is a URL. The proxy is how.
One container exposes every Hoody Kit service at its own HTTPS URL, plus an http-PORT slug for anything you bind yourself. Ports, auth, TLS, and real client IPs all resolve at the URL layer.
Proxy runs on your bare metal. Hoody sees management API calls — container traffic never leaves your server.
*.containers.hoody.com — wildcard TLS · no Certificate Transparency log exposure
One grammar, many patterns
Every Kit service resolves through the same proxy, but the URL slug reveals what it is. Same grammar, different shape per service.
| Service | URL slug | Notes |
|---|---|---|
| Workspaces | workspace-N | Composition layer over other service URLs |
| Terminal | terminal-N | Per-instance shell; maps to display-N |
| Display | display-N | GUI / X11 desktop per instance |
| Browser | browser-N | Remote Chrome instance |
| Code | code-N | VS Code instance per index |
| Files | files | Singleton — no instance index |
| SQLite | sqlite-N | One slug per database service |
| Exec | exec-N | Scripts-as-APIs |
| Agent | agent-N | Per-agent LLM instance |
| cURL | curl-N | Outbound HTTP proxy |
| Daemon | hoody-daemon-N | Process manager |
| Cron | — (via cURL today) | Placeholder service; scheduling lives in cURL |
| Notifications | n-N · notification-server-N | Browser bridge + API |
| Pipe | — (via other services) | Placeholder service; streaming distributed across Files/Terminal/Exec |
Project 24-hex × container 24-hex = 2^192 pair combinations. Infeasible to brute-force.
Run a server on any port. It gets a URL.
http-PORT prefixes route the proxy to your container's internal port. No nginx server block. No ingress YAML.
# listening sockets
$ ss -ltnp
https://PROJECT_ID-CONTAINER_ID-http-4000.SERVER.containers.hoody.com
https://PROJECT_ID-CONTAINER_ID-http-5173.SERVER.containers.hoody.com
https://PROJECT_ID-CONTAINER_ID-http-7070.SERVER.containers.hoody.com
— Hoody-kit ports are reserved for the platform's own services; everything else is yours. App-side, bind on any port and expose it via http-PORT.
— Apps must bind to 0.0.0.0, not localhost — the socket has to be reachable from the proxy container.
— Proxies HTTP/1.1, HTTP/2, HTTP/3, and WebSocket end-to-end. Arbitrary user UDP is not routed — use a dedicated IPv4 if you need raw UDP.
Auth is a JSON policy, not application middleware.
The proxy validates JWT claims, password hashes, IP CIDR ranges, and bearer tokens before a request reaches your container. Your app stays vanilla.
{
"enable_proxy": true,
"default": "deny",
"groups": {
"dashboard": {
"type": "jwt",
"algorithm": "HS256",
"source": "header",
"key": "Authorization",
"secret": "<hmac-secret>",
"claims": { "role": ["admin", "viewer"] }
},
"office-only": {
"type": "ip",
"cidrs": ["203.0.113.0/24"]
}
},
"permissions": {
"dashboard": { "http": [4000, 5173] },
"office-only": { "ssh": true, "terminal": true }
}
}JWT
HS256 · RS256 · ES256 · header / cookie / query · claim validation
Password
HTTP Basic · SHA-256 + salt · URL-embeddable
IP
IPv4 CIDR match · real client IP at socket level
Bearer Token
Multiple tokens per group · API-friendly
Container-level permissions replace project-level permissions — they do not merge. Set both scopes explicitly if you rely on inheritance.
Memorable URLs on top of cryptographic URLs
One API call turns the crypto URL into api.mycompany.com. Let's Encrypt provisions in 30–60 seconds; renews every 90 days.
https://67e89abc…-890abcdef…-http-4000.node-us.containers.hoody.com
https://api.mycompany.com
Alias naming: 3–61 chars, lowercase alphanumeric plus hyphens, must start and end with a letter or number. Auto-generated aliases are 48-char hex.
What you would otherwise stitch together
The proxy replaces a stack most teams assemble from scratch: reverse proxy + cert manager + VPN or tunnel + per-app auth + audit log. The axioms the self-hosted column fails — URL-as-route, URL-as-auth-scope, URL-as-embeddable — are what the proxy supplies natively.
| Concern | Hoody Proxy | Self-hosted equivalent |
|---|---|---|
| Wildcard HTTPS | supported natively — Native | certbot + renewal cron + cert rotation |
| Routing to internal port | supported natively — Native | nginx server block per service |
| Real client IP | supported natively — Native | Parse X-Forwarded-For per app |
| JWT · Basic · IP · Token auth | supported natively — Native | Middleware per app + session libs |
| Custom domain + TLS | supported natively — Native | Cloudflare / DNS-01 / nginx reload |
| Centralized request audit | supported natively — Native | nginx logs + log shipper + index |
| Iframe-embeddable URLs | supported natively — Native | Manual CORS / CSP / TLS per app |
| Runs on your hardware | supported natively — Native | You run it yourself anyway |
If you're already on Kubernetes with an ingress controller, Cloudflare Tunnels for SSO to Okta, or Tailscale for L3 private access, those tools stay better for their specific niches. The proxy earns its place when you want URL-addressable container services as the primary abstraction.
Six workflows the URL-first model makes trivial
Drawn from patterns teams actually ship with the Hoody Proxy.
Ship an API with no reverse proxy
Bind to 0.0.0.0:4000. Get http-4000.SERVER.containers.hoody.com. Skip the nginx, cert, and DNS song.
Custom domain with auto TLS
POST /api/v1/proxy-aliases, set a CNAME, and the first request provisions Let's Encrypt in 30–60 seconds.
Blue/green via alias swap
Point api.company.com at container B, test, swap the alias back. No config reload, no downtime.
Give an AI agent a container to drive
Agent gets a JWT, proxy validates per-request, agent writes files, runs commands, queries sqlite over HTTPS.
Multi-tenant SaaS subdomains
One container per tenant; alias TENANT.yourapp.com. Tenant isolation enforced at the URL layer.
Instant revocation
One DELETE call to the Control Plane and the URL is dead within a second. No cache poisoning.
Your first URL is one API call away.
Create a project, create a container, and every service is already online. No infrastructure to stand up first.
See also — /platform/control-plane for proxy alias, permission, and log APIs.