Skip to content
Hoody.com

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.


This page explains alias concepts and usage patterns. The endpoint reference carries the full request and response schemas.

Alias management:

Related:


Spawning a container produces service URLs automatically:

https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.com

Those 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

Create an alias and the service gets a hostname you choose:

Terminal window
POST /api/v1/proxy/aliases
{
"container_id": "890abcdef12345678901cdef",
"alias": "my-api",
"program": "http",
"port": 3000
}

Result:

https://my-api.node-us.containers.hoody.com

Both hostnames reach the same container and the same service.


A container running a web server or an API can be reached two ways.

https://67e89abc123def456789abcd-890abcdef12345678901cdef-http-8080.node-us.containers.hoody.com

Problems 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
https://api.node-us.containers.hoody.com

Benefits:

  • 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.com

https://api.mycompany.com then routes to your container, and no ID appears in the URL.

For a web server or API inside a container, use program: "http" with port:

Terminal window
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:

  1. Deploy your Node.js, Python, or Go API in a container
  2. Create an alias with program: "http" and your server’s port
  3. Point your domain at the alias
  4. Configure authentication with proxy permissions

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 becomes my-app.node-us.containers.hoody.com
  • The name my-app is now taken on node-us (for every tenant on that server) and cannot be claimed again there

An alias points at one program inside a container:

Terminal window
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 with port to route to a server running inside the container)
  • exec - Exec scripts as APIs
  • ssh - SSH access
  • terminal - Terminal interface
  • display - Desktop environment
  • code - 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.


Terminal window
# Create a basic proxy alias for your container
hoody proxy create --container-id $CONTAINER_ID --alias my-app --program http --port 3000
POST Create a basic proxy alias for your container
/api/v1/proxy/aliases
Click "Run" to execute the request

The service is now reachable at:

https://my-app.node-us.containers.hoody.com

Omit the alias parameter and the API generates a name for you:

POST Create alias with auto-generated name (omit alias parameter)
/api/v1/proxy/aliases
Click "Run" to execute the request

The response carries a 48-character hexadecimal alias, auto-generated and unique, for example a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3.

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), plus egress / workspaces exactly or with an egress- / workspaces- prefix (a distinct label such as egressmyapp is fine). Names starting with the internal {projectId}-{containerId} format are rejected too

Valid examples:

  • my-api
  • staging-frontend
  • app-v2
  • prod

Invalid examples:

  • -myapp (starts with hyphen)
  • my_api (underscore not allowed)
  • MY-APP (uppercase not allowed)

Route requests to a specific base path in your container:

POST Create alias with target path routing to /api/v1
/api/v1/proxy/aliases
Click "Run" to execute the request

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)

allow_path_override is not an access-control boundary. The runtime preserves every non-root request path:

# All paths allowed
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 flexible routing

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:

Terminal window
POST /api/v1/proxy/aliases
{
"alias": "public-api",
"program": "http",
"port": 3000,
"target_path": "/api/v1",
"allow_path_override": false
}

One container can carry several aliases, one per service:

POST Create alias for HTTP service
/api/v1/proxy/aliases
Click "Run" to execute the request

Result:

https://my-api.node-us.containers.hoody.com → HTTP service
https://my-scripts.node-us.containers.hoody.com → Exec scripts
https://my-terminal.node-us.containers.hoody.com → Terminal

Each hostname reaches a different program in the same container.


Terminal window
# List all aliases
hoody proxy list
# Filter by project
hoody proxy list --project-id $PROJECT_ID
# Filter by container
hoody proxy list --container-id $CONTAINER_ID
# Find expired aliases
hoody proxy list --expired true
GET List all your aliases
/api/v1/proxy/aliases
Click "Run" to execute the request
Terminal window
# Change alias target service
hoody proxy update $ALIAS_ID --program exec --index 2 --target-path /v2
# Update expiration
hoody proxy update $ALIAS_ID --expires-at "2026-12-31T23:59:59Z"
PATCH Change alias target service (replace {id} with actual alias ID)
/api/v1/proxy/aliases/{id}
Click "Run" to execute the request

Disable an alias without deleting its configuration:

Terminal window
# Re-enable alias
hoody 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 })
PATCH Disable alias (stops routing, keeps configuration)
/api/v1/proxy/aliases/{id}/state
Click "Run" to execute the request

This takes an API offline temporarily for maintenance, without losing the alias configuration.

Terminal window
# Permanently remove alias
hoody proxy delete $ALIAS_ID
DELETE Permanently remove alias (replace {id} with actual alias ID)
/api/v1/proxy/aliases/{id}
Click "Run" to execute the request

The alias name becomes available for reuse immediately.


An alias can expire on its own:

POST Create alias with automatic expiration (ISO 8601 timestamp)
/api/v1/proxy/aliases
Click "Run" to execute the request

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" }

Use cases:

  • Demo environments - Auto-expire after customer trial
  • Temporary access - Event-specific URLs
  • Staged rollouts - Beta URLs that expire when moving to prod

A permanent alias for an API service:

POST Create permanent production API alias whose root request lands on /api/v1
/api/v1/proxy/aliases
Click "Run" to execute the request

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 /users

Three aliases on one container, each pointing at a different program:

POST Production HTTP service
/api/v1/proxy/aliases
Click "Run" to execute the request

Result:

https://app.node-us.containers.hoody.com → Web service
https://app-terminal.node-us.containers.hoody.com → Terminal
https://app-scripts.node-us.containers.hoody.com → Exec scripts

Aliases can carry API versions:

POST Current production version
/api/v1/proxy/aliases
Click "Run" to execute the request

Clients can choose:

https://api-v1.node-us.containers.hoody.com → Old version
https://api-v2.node-us.containers.hoody.com → New version
https://api-beta.node-us.containers.hoody.com → Beta (same as v2)

When ready: Delete api-v1, rename api-v2api-v1, or update client references.

A typical deployment workflow:

Terminal window
# 1. Develop in container with cryptographic URL
https://67e89abc...890abc-exec-1.node-us.containers.hoody.com
# 2. Create staging alias when ready for testing
POST /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 container
POST /api/v1/containers/890abcdef.../snapshots
{ "alias": "pre-prod-2025-11-09" }
# 5. Create production alias
POST /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 snapshot
PUT /api/v1/containers/890abcdef.../snapshots/pre-prod-2025-11-09

GET Find all aliases for a specific project (replace project_id)
/api/v1/proxy/aliases?project_id=67e89abc123def456789abcd
Click "Run" to execute the request

Update many aliases programmatically:

// Example: Update all staging aliases to a new base path
const 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'
})
});
}

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:

POST Create exec alias for subdomain-based script routing
/api/v1/proxy/aliases
Click "Run" to execute the request

Scripts in the container:

/api/users.ts
/api/posts.ts
/webhooks/stripe.ts

Access 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: /stripe

The subdomain maps to the directory and the path maps to the route.

See: Hoody Exec → for complete script routing documentation.

Target different instances of the same program:

POST Alias to first HTTP service instance
/api/v1/proxy/aliases
Click "Run" to execute the request

Result:

https://frontend.node-us.containers.hoody.com → HTTP service on port 3000
https://backend.node-us.containers.hoody.com → HTTP service on port 8080

An alias is the CNAME target for a custom domain.

Step 1: Create alias

POST Create alias for custom domain CNAME target
/api/v1/proxy/aliases
Click "Run" to execute the request

Step 2: Point your domain to the alias

# DNS configuration at your domain provider
api.mycompany.com CNAME myapp-prod.node-us.containers.hoody.com

Step 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 service

See: Connect a Domain → for complete custom domain setup.


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 (Default)

https://67e89abc...890abc-exec-1.
node-us.containers.hoody.com

Security:

  • 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.com

Security:

  • 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)

Aliases work with proxy permissions:

POST Create public API alias (then configure permissions separately)
/api/v1/proxy/aliases
Click "Run" to execute the request

Then configure permissions on a separate endpoint:

Terminal window
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 JWT
https://public-api.node-us.containers.hoody.com → Requires JWT

The alias and the cryptographic URL apply the same permissions.


A complete workflow from development to production.

1. Develop in container (use the cryptographic URL)

https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.com

2. Create staging alias for team testing

POST Create staging alias for team testing
/api/v1/proxy/aliases
Click "Run" to execute the request

Result: https://staging-myapp.node-us.containers.hoody.com

3. Configure staging with IP whitelist (office only)

Terminal window
# 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

POST Create snapshot before production deployment
/api/v1/containers/{container_id}/snapshots
Click "Run" to execute the request

6. Create production alias

POST Create production alias
/api/v1/proxy/aliases
Click "Run" to execute the request

Result: https://myapp.node-us.containers.hoody.com

7. Point custom domain

DNS: api.mycompany.com CNAME myapp.node-us.containers.hoody.com

Result: https://api.mycompany.com (automatic SSL)

8. Configure production permissions (JWT auth)

Terminal window
# 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.


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.

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.

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.

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).


Error:

{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Alias is already in use on this server"
}

Solutions:

  1. Choose a different alias name
  2. Use a suffix: my-app-v2, my-app-prod
  3. Check existing aliases: GET /api/v1/proxy/aliases?project_id={id}

Check:

  1. Enabled status: GET /api/v1/proxy/aliases/{id} → Check enabled: true
  2. Container running: GET /api/v1/containers/{id} → Check status: "running"
  3. Service running: Check container’s service is actually started
  4. Permissions: Verify you can access via cryptographic URL first

For custom domains:

  • CNAME changes take 5-60 minutes to propagate globally
  • Test from multiple locations or wait before troubleshooting
  • Use dig api.mycompany.com to verify DNS points to alias

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.com

Both 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)

  1. Connect a Domain → - Point your custom domain to an alias
  2. 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