Proxy Aliases
Section titled “Proxy Aliases”A container’s default service URLs embed its project and container IDs, so they work but nobody can remember or type them. A proxy alias gives the same service a second hostname that you choose: my-api.node-us.containers.hoody.com instead of the generated form.
This page covers how aliases are created, what they route to, how they handle paths and expiration, and how they interact with proxy permissions. It follows on from how the Hoody Proxy works.
API endpoints summary
Section titled “API endpoints summary”This page explains alias concepts and usage patterns. The endpoint reference carries the full request and response schemas.
Alias management:
- POST /api/v1/proxy/aliases - Create new alias
- GET /api/v1/proxy/aliases - List all aliases (with filters)
- GET /api/v1/proxy/aliases/{id} - Get alias details
- PATCH /api/v1/proxy/aliases/{id} - Update alias configuration
- PATCH /api/v1/proxy/aliases/{id}/state - Enable/disable alias
- DELETE /api/v1/proxy/aliases/{id} - Delete alias
Related:
- Proxy Permissions - Control who can access aliases
- Container Operations - Container lifecycle
Generated URLs and aliases
Section titled “Generated URLs and aliases”Default container URLs
Section titled “Default container URLs”Spawning a container produces service URLs automatically:
https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.comThose URLs have a fixed set of properties:
- Created automatically, with nothing to configure
- Unique per service, built from cryptographic IDs
- Effectively unguessable, so sharing the URL is what grants access
- Working for every program the container runs
- Impossible to type or remember
- Unsafe to leak: if one is shared accidentally before permissions are configured, anyone holding the URL can reach the service
- Not brandable, since you cannot put one on a business card
Alias URLs
Section titled “Alias URLs”Create an alias and the service gets a hostname you choose:
POST /api/v1/proxy/aliases{ "container_id": "890abcdef12345678901cdef", "alias": "my-api", "program": "http", "port": 3000}Result:
https://my-api.node-us.containers.hoody.comBoth hostnames reach the same container and the same service.
Aliases in production
Section titled “Aliases in production”A container running a web server or an API can be reached two ways.
The cryptographic URL
Section titled “The cryptographic URL”https://67e89abc123def456789abcd-890abcdef12345678901cdef-http-8080.node-us.containers.hoody.comProblems in production:
- Exposes project and container IDs (48 characters of sensitive data)
- Impossible to remember or type
- Unprofessional for customers and users
- Cannot go on business cards, marketing material, or documentation
The alias
Section titled “The alias”https://api.node-us.containers.hoody.comBenefits:
- Keeps internal IDs out of the URL you hand out — though some programs still return them in their responses
- Short enough to remember and type
- Suited to public APIs and web services
- Usable as a CNAME target for a custom domain
Then connect your domain:
api.mycompany.com CNAME api.node-us.containers.hoody.comhttps://api.mycompany.com then routes to your container, and no ID appears in the URL.
The http program
Section titled “The http program”For a web server or API inside a container, use program: "http" with port:
POST /api/v1/proxy/aliases{ "container_id": "890abcdef12345678901cdef", "alias": "my-api", "program": "http", // Routes to container's HTTP service "port": 3000 // Port your server listens on inside the container}That maps to the web server running on the port you named (3000, 8080, 5000, or whatever your process listens on). The proxy then routes https://my-api.node-us.containers.hoody.com to that HTTP service automatically.
Typical production workflow:
- Deploy your Node.js, Python, or Go API in a container
- Create an alias with
program: "http"and your server’sport - Point your domain at the alias
- Configure authentication with proxy permissions
How aliases work
Section titled “How aliases work”Alias structure
Section titled “Alias structure”Aliases follow this pattern:
https://{alias}.{serverName}.containers.hoody.com └──┬──┘ └────┬────┘ Your Your Server Choice (where container runs)Alias names are unique per physical server, across every tenant hosted on it, not merely within your own account. The {serverName} component reflects where the container runs, so a name taken on one server can still be created on a different server.
Example:
- Container on
node-us→ Alias becomesmy-app.node-us.containers.hoody.com - The name
my-appis now taken onnode-us(for every tenant on that server) and cannot be claimed again there
Alias targets
Section titled “Alias targets”An alias points at one program inside a container:
POST /api/v1/proxy/aliases{ "container_id": "890abcdef12345678901cdef", "alias": "my-api", "program": "http", // Which program (use "http"/"https" for web servers) "port": 3000, // Port your server listens on inside the container "target_path": "/api/v1", // Optional: base path "allow_path_override": true}Common programs: http, https, exec, ssh, terminal, display, code
http/https- HTTP/HTTPS servers (use withportto route to a server running inside the container)exec- Exec scripts as APIsssh- SSH accessterminal- Terminal interfacedisplay- Desktop environmentcode- Code editor interface
The program value must exist in your container’s container-programs.json.
A container can carry several aliases, pointing at different programs or at the same program with different configurations.
Alias creation
Section titled “Alias creation”A basic alias
Section titled “A basic alias”# Create a basic proxy alias for your containerhoody proxy create --container-id $CONTAINER_ID --alias my-app --program http --port 3000const alias = await client.api.proxyAliases.create({ container_id: CONTAINER_ID, alias: 'my-app', program: 'http', port: 3000});console.log(alias.data.url);// https://my-app.node-us.containers.hoody.comcurl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "container_id": "'$CONTAINER_ID'", "alias": "my-app", "program": "http", "port": 3000 }'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Creates a proxy alias for the container’s HTTP service, giving it a memorable hostname in place of the generated one.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"container_id":"CONTAINER_ID","alias":"my-app","program":"http","port":3000}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
The service is now reachable at:
https://my-app.node-us.containers.hoody.comAuto-generated names
Section titled “Auto-generated names”Omit the alias parameter and the API generates a name for you:
The response carries a 48-character hexadecimal alias, auto-generated and unique, for example a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3.
Naming rules
Section titled “Naming rules”Valid alias names:
- 3-61 characters
- Lowercase letters (a-z)
- Numbers (0-9)
- Hyphens (-)
- Must start with letter or number
- Must end with letter or number
- Pattern:
^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ - Reserved:
containers(exact label), plusegress/workspacesexactly or with anegress-/workspaces-prefix (a distinct label such asegressmyappis fine). Names starting with the internal{projectId}-{containerId}format are rejected too
Valid examples:
my-apistaging-frontendapp-v2prod
Invalid examples:
-myapp(starts with hyphen)my_api(underscore not allowed)MY-APP(uppercase not allowed)
Path routing
Section titled “Path routing”Target path
Section titled “Target path”Route requests to a specific base path in your container:
Routing behavior:
Incoming Request:https://my-api.node-us.containers.hoody.com/
Routed To Container:/api/v1
(a root request uses target_path; a non-root request path replaces it, so /users arrives as /users, whatever allow_path_override is set to)Incoming Request:https://my-api.node-us.containers.hoody.com/users
Routed To Container:/users
(pass-through, no modification)Path override
Section titled “Path override”allow_path_override is not an access-control boundary. The runtime preserves every non-root request path:
# All paths allowedhttps://my-api.node-us.containers.hoody.com/api/v1/users → /api/v1/users (forwarded)https://my-api.node-us.containers.hoody.com/admin → /admin (forwarded)https://my-api.node-us.containers.hoody.com/anything → /anything (forwarded)Use when: You want flexible routing
# Only the root request uses target_path; nothing is blockedhttps://my-api.node-us.containers.hoody.com/ → /api/v1 (target_path)https://my-api.node-us.containers.hoody.com/api/v1/users → /api/v1/users (forwarded)https://my-api.node-us.containers.hoody.com/admin → /admin (forwarded)https://my-api.node-us.containers.hoody.com/anything → /anything (forwarded)Use when: You want a bare root request to land on target_path
Example: land the bare alias root on your API base path (/api/v1) instead of /. An alias does not gate paths, so hiding routes such as /admin/* takes proxy permissions:
POST /api/v1/proxy/aliases{ "alias": "public-api", "program": "http", "port": 3000, "target_path": "/api/v1", "allow_path_override": false}Multi-service aliases
Section titled “Multi-service aliases”One container can carry several aliases, one per service:
Result:
https://my-api.node-us.containers.hoody.com → HTTP servicehttps://my-scripts.node-us.containers.hoody.com → Exec scriptshttps://my-terminal.node-us.containers.hoody.com → TerminalEach hostname reaches a different program in the same container.
Alias lifecycle
Section titled “Alias lifecycle”The alias list
Section titled “The alias list”# List all aliaseshoody proxy list
# Filter by projecthoody proxy list --project-id $PROJECT_ID
# Filter by containerhoody proxy list --container-id $CONTAINER_ID
# Find expired aliaseshoody proxy list --expired true// List all aliasesconst all = await client.api.proxyAliases.list();
// Filter by projectconst byProject = await client.api.proxyAliases.list({ project_id: PROJECT_ID });
// Filter by containerconst byContainer = await client.api.proxyAliases.list({ container_id: CONTAINER_ID });
// Find expired aliasesconst expired = await client.api.proxyAliases.list({ expired: 'true' });# List all aliasescurl "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN"
# Filter by projectcurl "https://api.hoody.com/api/v1/proxy/aliases?project_id=$PROJECT_ID" \ -H "Authorization: Bearer $TOKEN"
# Filter by containercurl "https://api.hoody.com/api/v1/proxy/aliases?container_id=$CONTAINER_ID" \ -H "Authorization: Bearer $TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Lists your aliases, optionally filtered to one project or one container.
# List all
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=GET&bearer_token=TOKEN&response=transparent
# By project
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases?project_id=PROJECT_ID&method=GET&bearer_token=TOKEN&response=transparent
# By container
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases?container_id=CONTAINER_ID&method=GET&bearer_token=TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Configuration updates
Section titled “Configuration updates”# Change alias target servicehoody proxy update $ALIAS_ID --program exec --index 2 --target-path /v2
# Update expirationhoody proxy update $ALIAS_ID --expires-at "2026-12-31T23:59:59Z"// Change alias target serviceawait client.api.proxyAliases.update(ALIAS_ID, { program: 'exec', index: 2, target_path: '/v2'});
// Update expirationawait client.api.proxyAliases.update(ALIAS_ID, { expires_at: '2026-12-31T23:59:59Z'});# Change alias target servicecurl -X PATCH "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"program": "exec", "index": 2, "target_path": "/v2"}'
# Update expirationcurl -X PATCH "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"expires_at": "2026-12-31T23:59:59Z"}'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Updates an existing alias’s target program or its expiration timestamp.
# Change target
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID&method=PATCH&bearer_token=TOKEN&json={"program":"exec","index":2,"target_path":"/v2"}&response=transparent
# Update expiration
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID&method=PATCH&bearer_token=TOKEN&json={"expires_at":"2026-12-31T23:59:59Z"}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Enabled state
Section titled “Enabled state”Disable an alias without deleting its configuration:
# Re-enable aliashoody proxy set-state $ALIAS_ID --enabled
# Disable alias# The CLI can only enable (--enabled is a bare flag; there is no --no-enabled).# Disable via the SDK or HTTP:# await client.api.proxyAliases.setState(ALIAS_ID, { enabled: false })// Disable aliasawait client.api.proxyAliases.setState(ALIAS_ID, { enabled: false });
// Re-enable aliasawait client.api.proxyAliases.setState(ALIAS_ID, { enabled: true });# Disable aliascurl -X PATCH "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID/state" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled": false}'
# Re-enable aliascurl -X PATCH "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID/state" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled": true}'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Toggles an alias’s routing on or off without deleting its configuration.
# Disable
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID/state&method=PATCH&bearer_token=TOKEN&json={"enabled":false}&response=transparent
# Re-enable
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID/state&method=PATCH&bearer_token=TOKEN&json={"enabled":true}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
This takes an API offline temporarily for maintenance, without losing the alias configuration.
Deletion
Section titled “Deletion”# Permanently remove aliashoody proxy delete $ALIAS_IDawait client.api.proxyAliases.delete(ALIAS_ID);curl -X DELETE "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID" \ -H "Authorization: Bearer $TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Permanently removes the alias; the name becomes available for reuse immediately.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID&method=DELETE&bearer_token=TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
The alias name becomes available for reuse immediately.
Expiration
Section titled “Expiration”An alias can expire on its own:
After expiration:
- Alias stops routing traffic automatically
- Returns 404 for all requests
- Configuration preserved (can re-enable by removing expiration)
Expiration formats:
On create (POST), expires_at must be an ISO 8601 string, or null for no expiration. On update (PATCH), the route schema also accepts a numeric Unix timestamp in seconds or milliseconds alongside the ISO string and null. Prefer ISO 8601 everywhere.
{ "expires_at": "2026-07-12T00:00:00.000Z" }{ "expires_at": "2026-12-31T23:59:59.000Z" }{ "expires_at": 1783987200 }{ "expires_at": null }Use cases:
- Demo environments - Auto-expire after customer trial
- Temporary access - Event-specific URLs
- Staged rollouts - Beta URLs that expire when moving to prod
Common patterns
Section titled “Common patterns”Production API alias
Section titled “Production API alias”A permanent alias for an API service:
Access:
https://prod-api.node-us.containers.hoody.com/→ Routes to container's /api/v1
https://prod-api.node-us.containers.hoody.com/users→ Routes to container's /usersOne container, several aliases
Section titled “One container, several aliases”Three aliases on one container, each pointing at a different program:
Result:
https://app.node-us.containers.hoody.com → Web servicehttps://app-terminal.node-us.containers.hoody.com → Terminalhttps://app-scripts.node-us.containers.hoody.com → Exec scriptsVersion aliases
Section titled “Version aliases”Aliases can carry API versions:
Clients can choose:
https://api-v1.node-us.containers.hoody.com → Old versionhttps://api-v2.node-us.containers.hoody.com → New versionhttps://api-beta.node-us.containers.hoody.com → Beta (same as v2)When ready: Delete api-v1, rename api-v2 → api-v1, or update client references.
Staging to production promotion
Section titled “Staging to production promotion”A typical deployment workflow:
# 1. Develop in container with cryptographic URLhttps://67e89abc...890abc-exec-1.node-us.containers.hoody.com
# 2. Create staging alias when ready for testingPOST /api/v1/proxy/aliases{ "alias": "staging-app", "container_id": "890abcdef...", "program": "http", "port": 3000 }# → https://staging-app.node-us.containers.hoody.com
# 3. Test with team, clients, QA
# 4. Snapshot tested containerPOST /api/v1/containers/890abcdef.../snapshots{ "alias": "pre-prod-2025-11-09" }
# 5. Create production aliasPOST /api/v1/proxy/aliases{ "alias": "prod-app", "container_id": "890abcdef...", "program": "http", "port": 3000 }# → https://prod-app.node-us.containers.hoody.com
# 6. If issues, instant rollback via snapshotPUT /api/v1/containers/890abcdef.../snapshots/pre-prod-2025-11-09Operations across many aliases
Section titled “Operations across many aliases”Filters and lookups
Section titled “Filters and lookups” Bulk updates
Section titled “Bulk updates”Update many aliases programmatically:
// Example: Update all staging aliases to a new base pathconst stagingAliases = await fetch( 'https://api.hoody.com/api/v1/proxy/aliases?project_id=staging-project').then(r => r.json());
for (const alias of stagingAliases.data.aliases) { await fetch(`https://api.hoody.com/api/v1/proxy/aliases/${alias.id}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ target_path: '/v2' }) });}Advanced routing
Section titled “Advanced routing”Subdomain routing for hoody-exec
Section titled “Subdomain routing for hoody-exec”The exec program routes on subdomains as well as paths.
When you create an alias for program: "exec", you can use subdomain-based routing to access specific scripts:
Scripts in the container:
/api/users.ts/api/posts.ts/webhooks/stripe.tsAccess via subdomains:
https://api.my-scripts.node-us.containers.hoody.com/users→ Executes /api/users.ts, route: /users
https://webhooks.my-scripts.node-us.containers.hoody.com/stripe→ Executes /webhooks/stripe.ts, route: /stripeThe subdomain maps to the directory and the path maps to the route.
See: Hoody Exec → for complete script routing documentation.
Multiple instances
Section titled “Multiple instances”Target different instances of the same program:
Result:
https://frontend.node-us.containers.hoody.com → HTTP service on port 3000https://backend.node-us.containers.hoody.com → HTTP service on port 8080Aliases as CNAME targets
Section titled “Aliases as CNAME targets”An alias is the CNAME target for a custom domain.
Step 1: Create alias
Step 2: Point your domain to the alias
# DNS configuration at your domain providerapi.mycompany.com CNAME myapp-prod.node-us.containers.hoody.comStep 3: Automatic SSL
Hoody provisions a Let’s Encrypt certificate for api.mycompany.com automatically. The custom domain serves HTTPS within minutes.
Result:
https://api.mycompany.com → CNAME →https://myapp-prod.node-us.containers.hoody.com → Routes to →Container's HTTP serviceSee: Connect a Domain → for complete custom domain setup.
Security considerations
Section titled “Security considerations”Alias uniqueness
Section titled “Alias uniqueness”Aliases must be unique per physical server, across every tenant hosted on it.
If anyone, including another tenant, has claimed my-app on the same physical server, you cannot use it there. The API returns a 422 validation error (Alias is already in use on this server). On a different server the name is available again.
Solution: Choose descriptive, unique aliases:
- Add your company name:
acme-api - Add identifier:
my-app-prod - Use generated names when uniqueness is uncertain
Cryptographic URLs vs aliases
Section titled “Cryptographic URLs vs aliases”Cryptographic URLs (Default)
https://67e89abc...890abc-exec-1. node-us.containers.hoody.comSecurity:
- Unguessable (2^96 combinations)
- Share URL = grant access
- Don’t share = private
- Suited to development and collaboration
Usability:
- Impossible to remember
- Can’t type manually
- Not brandable
Aliases (Production)
https://my-api.node-us. containers.hoody.comSecurity:
- Guessable (if known pattern)
- Discoverable (enumeration possible)
- IP whitelist recommended
- Add authentication via permissions
Usability:
- Memorable
- Typeable
- Brandable
- Professional
Best practice:
- Development: Use cryptographic URLs (secure by obscurity)
- Production: Use aliases + permissions (secure by authentication)
Permissions on aliases
Section titled “Permissions on aliases”Aliases work with proxy permissions:
Then configure permissions on a separate endpoint:
PUT /api/v1/containers/{id}/proxy/permissions{ "project": "67e89abc123def456789abcd", "container": "890abcdef12345678901cdef", "groups": { "authenticated": { "type": "jwt", "secret": "a-long-random-signing-key-with-32-plus-chars", "algorithm": "HS256", "sources": ["header:Authorization"] } }, "permissions": { "authenticated": { "http": [3000] } }, "default": "deny"}Both URLs now require authentication:
https://67e89abc...890abc-http-3000.node-us.containers.hoody.com → Requires JWThttps://public-api.node-us.containers.hoody.com → Requires JWTThe alias and the cryptographic URL apply the same permissions.
Worked example
Section titled “Worked example”A complete workflow from development to production.
1. Develop in container (use the cryptographic URL)
https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.com2. Create staging alias for team testing
Result: https://staging-myapp.node-us.containers.hoody.com
3. Configure staging with IP whitelist (office only)
# Read the current file_version via GET first, then pass it as If-Match (the server returns 428 if the header is omitted)curl -X PUT "https://api.hoody.com/api/v1/containers/890abcdef.../proxy/permissions" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "If-Match: file:v1" \ -H "Content-Type: application/json" \ -d '{ "project": "67e89abc123def456789abcd", "container": "890abcdef12345678901cdef", "groups": { "office": { "type": "ip", "range": "203.0.113.0/24" } }, "permissions": { "office": { "http": [3000] } }, "default": "deny" }'4. Team tests on staging-myapp.node-us.containers.hoody.com
5. Snapshot when ready
6. Create production alias
Result: https://myapp.node-us.containers.hoody.com
7. Point custom domain
DNS: api.mycompany.com CNAME myapp.node-us.containers.hoody.comResult: https://api.mycompany.com (automatic SSL)
8. Configure production permissions (JWT auth)
# Read the current file_version via GET first, then pass it as If-Match (the server returns 428 if the header is omitted)curl -X PUT "https://api.hoody.com/api/v1/containers/890abcdef.../proxy/permissions" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "If-Match: file:v1" \ -H "Content-Type: application/json" \ -d '{ "project": "67e89abc123def456789abcd", "container": "890abcdef12345678901cdef", "groups": { "customers": { "type": "jwt", "secret": "production-jwt-secret", "sources": ["header:Authorization"] } }, "permissions": { "customers": { "http": [3000] } }, "default": "deny" }'9. Production is live
Development: https://67e89abc...890abc-exec-1.node-us.containers.hoody.com (crypto URL)Staging: https://staging-myapp.node-us.containers.hoody.com (IP-restricted)Production: https://api.mycompany.com (JWT auth, custom domain)The same container is reachable at three hostnames, each under a different access policy.
Useful questions
Section titled “Useful questions”Can I use the same alias name on different servers?
Section titled “Can I use the same alias name on different servers?”Yes. Alias names are unique per physical server (across all tenants on it), so the same name can be created again for a container on a different server. On the same server a taken name fails with a 422 validation error; pick a variant like my-app-eu there.
What happens if I delete a container that has aliases?
Section titled “What happens if I delete a container that has aliases?”The aliases remain configured but return errors (container not found) until you delete them and recreate them for a different container (the target container is fixed at create time and cannot be reassigned). Best practice: delete aliases before deleting containers.
Can several aliases point to one service?
Section titled “Can several aliases point to one service?”Yes. Create several aliases with different names, all pointing to the same container_id and program. This is useful for versioning (api-v1 and api-v2 both pointing to the same container initially) or for multi-brand domains.
Do aliases work with proxy permissions?
Section titled “Do aliases work with proxy permissions?”Yes. When you configure proxy permissions for a container, they apply to both the cryptographic URL and every alias pointing to that container. One permission configuration covers all entry points.
Can I create an alias before the container is running?
Section titled “Can I create an alias before the container is running?”Yes. You can create aliases for stopped containers. The alias exists, but requests will fail until you start the container. Useful for pre-configuring production URLs before deployment.
How do target_path and allow_path_override differ?
Section titled “How do target_path and allow_path_override differ?”target_path supplies the destination for a root request (/); non-root request paths are forwarded unchanged. allow_path_override: false does not create a path allowlist or block other paths.
How do I prevent someone from guessing my alias names?
Section titled “How do I prevent someone from guessing my alias names?”Use long, specific aliases (acme-prod-api-v2-us-2025) instead of generic ones (api, app). Better still, combine the alias with proxy permissions for authentication, so that guessing the name does not grant access.
Can I have an alias without specifying program or index?
Section titled “Can I have an alias without specifying program or index?”The program is required. For built-in programs, index is optional and defaults to 1, so {"container_id": "…", "program": "terminal"} is a valid alias. For http/https, always supply port (which index is also read as) with the backend’s listening port; omitting it routes to port 1, not port 80 or 443. The program is mandatory because one container runs several services and the alias has to name the one it routes to.
Do aliases survive snapshot and restore?
Section titled “Do aliases survive snapshot and restore?”Aliases are stored separately, not in the container. If you snapshot container A with alias my-app, then restore to container B, the alias still points to container A. To route to container B, delete the alias and create a new one targeting container B’s ID (the target container cannot be changed on an existing alias).
Can I see which custom domains point to my aliases?
Section titled “Can I see which custom domains point to my aliases?”The GET /api/v1/proxy/aliases/{id} endpoint shows alias configuration, but not which custom domains CNAME to it (that’s in your DNS provider). Best practice: document your CNAME mappings externally (spreadsheet, wiki, infrastructure-as-code).
Troubleshooting
Section titled “Troubleshooting”Alias already exists
Section titled “Alias already exists”Error:
{ "statusCode": 422, "error": "Unprocessable Entity", "message": "Alias is already in use on this server"}Solutions:
- Choose a different alias name
- Use a suffix:
my-app-v2,my-app-prod - Check existing aliases:
GET /api/v1/proxy/aliases?project_id={id}
Alias not routing
Section titled “Alias not routing”Check:
- Enabled status:
GET /api/v1/proxy/aliases/{id}→ Checkenabled: true - Container running:
GET /api/v1/containers/{id}→ Checkstatus: "running" - Service running: Check container’s service is actually started
- Permissions: Verify you can access via cryptographic URL first
DNS propagation delay
Section titled “DNS propagation delay”For custom domains:
- CNAME changes take 5-60 minutes to propagate globally
- Test from multiple locations or wait before troubleshooting
- Use
dig api.mycompany.comto verify DNS points to alias
Coexistence with cryptographic URLs
Section titled “Coexistence with cryptographic URLs”When you create an alias, the original cryptographic URL still works:
Alias:https://my-api.node-us.containers.hoody.com
Original (still works):https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.comBoth route to the same container service, under the same permissions.
Use case:
- Share aliases publicly (clean URLs)
- Keep cryptographic URLs for internal tools (unguessable security)
What’s next
Section titled “What’s next”- Connect a Domain → - Point your custom domain to an alias
- Set Permissions → - Add authentication to protect aliases
Summary of this page:
- Aliases create short URLs of the form
my-app.{serverName}.containers.hoody.com - They map to specific container programs (http, exec, terminal, and the rest)
- They support path routing and access control
- They serve as CNAME targets for custom domains
- They can be temporary (expiration) or permanent