Skip to content
Hoody.com

The Hoody Proxy is the foundational infrastructure that makes “everything is a URL” possible.

It’s not just about web servers. Every single container feature—terminals, displays, files, databases, browsers, scripts—flows through this proxy. This unified approach transforms isolated containers into a web-native computing fabric.


Official Technical Reference:

The Hoody Proxy is infrastructure (runs on your server), not API endpoints you call directly. However, you configure it via the Hoody API:

Proxy Configuration:

Related Infrastructure:

The proxy infrastructure automatically handles TLS, routing, and IP preservation—you just configure aliases and permissions via the API.


Physical Reality: The Hoody Proxy runs as a container on YOUR bare metal server—the same machine hosting your containers.

What it does:

  • Routes ALL traffic to container services (terminal, display, files, exec, sqlite, browser, agent, code, curl, notifications, daemon, cron, pipe, notes, watch, run, proxy logs, tunnel)
  • Terminates TLS for every connection (automatic HTTPS everywhere)
  • Preserves real client IPs (no x-forwarded-for headers needed)
  • Generates automatic URLs for all services
  • Enforces authentication and permissions
  • Handles modern protocols (HTTP/1.1, HTTP/2, HTTP/3, WebSocket)

What it runs on: A dedicated container on your server with access to:

  • Host network stack (for IP preservation)
  • Container networking (for service routing)
  • TLS certificate management
  • Permission configuration files

Every container capability becomes a URL through the proxy:

  • display-X — Your desktop in a browser
  • http-X — Any HTTP server is proxified
  • https-X — Any HTTPS server is proxified
  • ssh-22 — Native SSH, works with any clients
  • terminal-X — Your shell with multiplayer
  • files-X — Your filesystem as HTTP
  • exec-X — Any script becomes an API
  • browser-X — Automated browser for AI & humans
  • curl-X — Complex APIs made simple
  • sqlite-X — Instant databases everywhere
  • daemon-X — Long-running services
  • notify-X — Native notifications from the web
  • code-X — VSCode in your browser
  • agent-X — AI with full system control

The breakthrough: You’re not just hosting websites. Your terminal sessions, desktop environments, file systems, databases—everything becomes web-native through automatic URL generation.


When you spawn a container, it immediately gets URLs for all services:

https://{projectId}-{containerId}-{service}-{instance}.{serverName}.containers.hoody.icu
└────┬────┘ └────┬─────┘ └───┬───┘ └───┬───┘ └─────┬─────┘
Project Container Service Instance Your Server
(24-char) (24-char) Name Number Location

Example for one container:

Terminal: https://67e89abc123def456789abcd-890abcdef12345678901cdef-terminal-1.node-us.containers.hoody.icu
Display: https://67e89abc123def456789abcd-890abcdef12345678901cdef-display-1.node-us.containers.hoody.icu
Files: https://67e89abc123def456789abcd-890abcdef12345678901cdef-files-1.node-us.containers.hoody.icu
SQLite: https://67e89abc123def456789abcd-890abcdef12345678901cdef-sqlite-1.node-us.containers.hoody.icu
Exec: https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.icu
Browser: https://67e89abc123def456789abcd-890abcdef12345678901cdef-browser-1.node-us.containers.hoody.icu
Agent: https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-us.containers.hoody.icu
Code: https://67e89abc123def456789abcd-890abcdef12345678901cdef-code-1.node-us.containers.hoody.icu
cURL: https://67e89abc123def456789abcd-890abcdef12345678901cdef-curl-1.node-us.containers.hoody.icu
Notify: https://67e89abc123def456789abcd-890abcdef12345678901cdef-n-1.node-us.containers.hoody.icu
Daemon: https://67e89abc123def456789abcd-890abcdef12345678901cdef-daemon-1.node-us.containers.hoody.icu
Cron: https://67e89abc123def456789abcd-890abcdef12345678901cdef-cron-1.node-us.containers.hoody.icu
Pipe: https://67e89abc123def456789abcd-890abcdef12345678901cdef-pipe-1.node-us.containers.hoody.icu
Notes: https://67e89abc123def456789abcd-890abcdef12345678901cdef-notes-1.node-us.containers.hoody.icu
Watch: https://67e89abc123def456789abcd-890abcdef12345678901cdef-watch-1.node-us.containers.hoody.icu
Run: https://67e89abc123def456789abcd-890abcdef12345678901cdef-run-1.node-us.containers.hoody.icu

No DNS configuration needed. The proxy automatically makes services accessible.


Request flow for every container service:

User/AI/Device
https://67e89abc...890abc-terminal-1.node-us.containers.hoody.icu/execute
Hoody Proxy Container (on your server)
├─ Terminates TLS (port 443)
├─ Parses URL: projectId, containerId, service=terminal, instance=1
├─ Validates authentication (if permissions configured)
├─ Preserves real client IP
└─ Routes to internal service
Container's terminal service (internal port 76)
Response (through proxy, back to client)

Key insight: External clients see HTTPS on port 443; the Hoody Proxy maps each service URL to its internal port automatically.


When enabled, the Hoody Kit runs its HTTP services on 0.0.0.0 at reserved ports inside each container’s own network namespace — in-container listeners with their own port space, not public ports, and never shared between containers. Two things follow: which ports are free for your apps, and how you reach the Kit.

Every fixed core-service port is below 80 (the highest is 78), so 80 is the recommended starting line for your own HTTP apps. Ports 80499 are always clear of the Kit.

Above 500, a few services and their dynamic pools come into play — Hoody assigns pool ports as you start browser, display, or code instances, so a port that’s unused right now can be claimed later. If you run your app on a higher port, check it against the tables below.

Core Kit services — one fixed port each, all below 80:

PortServicePortService
4hoody-curl60hoody-cron
5hoody-sqlite61hoody-watch
44hoody-run74hoody-terminal (CLI)
45hoody-agent75hoody-exec
46hoody-notes76hoody-terminal
48hoody-pipe77hoody-daemon
50hoody-tunnel78hoody-files
55hoody-workspaces
59hoody-proxy

Higher ports & dynamic pools:

ServiceFixed portDynamic pool
hoody-code3971instances from 60000
hoody-display3998sessions from 4000
hoody-notifications3999
hoody-browser23333displays from 500; HTTP instances from 30000

Kit services listen only on their in-container ports, and you can’t reach them there directly. A request to localhost:<port> (or the container’s own address) from inside the container fails — most services answer 403, and hoody-files closes the connection. Kit services only accept requests that arrive through the Hoody Proxy.

Keep the two traffic directions separate:

  • Expose your app → listen on 0.0.0.0:{port}, then reach it at https://{projectId}-{containerId}-http-{port}.{serverName}.containers.hoody.icu or through a proxy alias.
  • Reach a Kit service → use its service URL (e.g. https://{projectId}-{containerId}-files-1.{serverName}.containers.hoody.icu), an alias, or the hoody CLI — never its raw port.

The Kit is yours to control. Use hoody-daemon to stop or disable any service — the supported, reversible way — or terminate its processes directly.

When you run a web server in a container, access it via the http program:

Example: Apache2 on port 80

Terminal window
# Install Apache2 in container
apt-get install apache2
# Apache runs on port 80 by default
# Access via http program
https://67e89abc...890abc-http-80.node-us.containers.hoody.icu

Example: Node.js API on port 3000

Terminal window
# Your Node.js app
app.listen(3000, () => {
console.log('API running on port 3000');
});
# Access via http program
https://67e89abc...890abc-http-3000.node-us.containers.hoody.icu

Example: Multiple web services in one container

Terminal window
# Frontend on port 3000
# Backend on port 5000
# Admin panel on port 8000
# Access each separately
https://67e89abc...890abc-http-3000.node-us.containers.hoody.icu (frontend)
https://67e89abc...890abc-http-5000.node-us.containers.hoody.icu (backend)
https://67e89abc...890abc-http-8000.node-us.containers.hoody.icu (admin)

The pattern: http-{port} in the URL routes to your service on that port.

All accessed via HTTPS (port 443) externally. The proxy translates to your internal port automatically.


Every connection is encrypted. Zero configuration required.

  • Wildcard certificates (*.{serverName}.containers.hoody.icu) protect all service URLs
  • Automatic provisioning - certificates managed by Hoody
  • Automatic renewal - no manual intervention
  • TLS 1.2+ - modern encryption standards
  • HTTPS enforcement - HTTP automatically redirects to HTTPS

Your container URLs never appear in public Certificate Transparency logs.

Standard Let’s Encrypt certificates are public—anyone can see what domains you’re hosting. Hoody uses per-server wildcard certificates (*.{serverName}.containers.hoody.icu), so your specific container URLs remain private.

Unguessable URLs, not a permission boundary:

  • 24-character hex container IDs = 2^96 possible combinations
  • Even knowing your project ID, guessing a container ID: trillions of years at 1B attempts/second
  • URLs are effectively unguessable

The default proxy permission for a newly created container is allow — the URL is the only access gate until you add proxy permissions. Treat the URL like a bearer credential: anyone it leaks to (browser history, chat logs, referer headers, screenshots) can hit the container directly. For real access control, set proxy permissions instead of relying on URL secrecy.


This is unique to Hoody: Applications see the real client IP address directly in remoteAddr—no special configuration, no header parsing.

Most proxies hide the client IP behind the proxy’s IP, requiring applications to parse X-Forwarded-For headers. This breaks:

  • Legacy applications (don’t know about proxy headers)
  • Standard firewalls (can’t filter by real IP)
  • Analytics tools (see proxy IP instead of user IP)

Hoody solves this at the infrastructure level:

We run a TPROXY-based edge on the host that preserves the original client connection information end-to-end. When traffic reaches your container, it sees the true client IP as if there were no proxy at all.

What this means:

// Any application, any language
app.get('/', (req, res) => {
const clientIP = req.connection.remoteAddress;
console.log(`Request from: ${clientIP}`);
// Shows: 203.0.113.50 (real client)
// NOT: 10.0.0.1 (proxy IP)
});

It just works. No configuration. No code changes. No proxy headers.


The proxy handles modern web protocols automatically:

  • HTTP/1.1 - Universal compatibility
  • HTTP/2 - Multiplexing for faster connections
  • HTTP/3 (QUIC) - Low-latency over UDP
  • Automatic negotiation - Client gets best protocol it supports
  • WebSocket - For terminal sessions, real-time updates, live displays
  • Bi-directional - Full-duplex communication
  • Multiplayer support - Multiple WebSocket connections to same service

Example: Hoody Terminal uses WebSocket through the proxy for real-time command execution. Multiple users can connect to the same terminal URL, each with their own WebSocket—multiplayer by default.


Containers can run multiple instances of each service:

One Container, Multiple Service Instances:

https://67e89abc...890abc-terminal-1.node-us.containers.hoody.icu
https://67e89abc...890abc-terminal-2.node-us.containers.hoody.icu
https://67e89abc...890abc-terminal-3.node-us.containers.hoody.icu
https://67e89abc...890abc-display-1.node-us.containers.hoody.icu
https://67e89abc...890abc-display-2.node-us.containers.hoody.icu
https://67e89abc...890abc-sqlite-1.node-us.containers.hoody.icu
https://67e89abc...890abc-sqlite-2.node-us.containers.hoody.icu

Each instance is isolated. Terminal-1 is a different session than Terminal-2. Display-1 is a separate desktop from Display-2.

The proxy routes to the correct instance automatically based on the instance number in the URL.


The proxy enforces access control for container services:

By default, anyone with the URL can access. But the URL contains:

  • 24-char project ID (2^96 possibilities)
  • 24-char container ID (2^96 possibilities)

Practically unguessable. But anyone the URL reaches — proxies, CI logs, browser history, screenshots, referer headers — can hit the container directly, so treat the URL like a bearer credential rather than a real access gate. For anything you wouldn’t paste into a public channel, add explicit proxy permissions before exposing it.

Layer on authentication as needed:

$TOKEN in the HTTP examples below refers to a Hoody API bearer token. Obtain one with hoody auth login or create an automation token per the authentication guide, then export it as TOKEN before running the snippets.

Terminal window
# Whole-document `permissions replace` does not work from the CLI today — its
# --groups/--permissions values are transmitted as strings (and the container
# variant never sends the required body `container` field), so the API rejects
# them. Build the document with the granular commands below, or send it in one
# call with the SDK/HTTP tabs.
# Project-level permissions (apply to all containers)
hoody projects proxy groups ip set --project $PROJECT_ID \
--group-name <name> --range 203.0.113.0/24 --if-match file:v<N>
hoody projects proxy groups permissions set --project $PROJECT_ID \
--group-name <name> --program terminal --access true --if-match file:v<N>
hoody projects proxy default --project $PROJECT_ID --default deny --if-match file:v<N>
# Container-level permissions (override project settings)
hoody containers proxy groups ip set -c $CONTAINER_ID \
--group-name <name> --range 0.0.0.0/0 --if-match file:v<N>
hoody containers proxy groups permissions set -c $CONTAINER_ID \
--group-name <name> --program http --access 8080 --if-match file:v<N>
hoody containers proxy default -c $CONTAINER_ID --default deny --if-match file:v<N>
# Each write bumps file_version. Before every project write, re-read it with:
# hoody projects proxy permissions get --project $PROJECT_ID -o json
# Before every container write, re-read it with:
# hoody containers proxy permissions get -c $CONTAINER_ID -o json

Authentication methods:

  • JWT - Token-based with claims validation
  • Password - Username/password via HTTP Basic Auth
  • IP-based - Allow/deny by IP address or CIDR range
  • Bearer token - Custom token validation

Program-specific permissions:

  • Terminal - Execute vs read-only
  • Files - Read vs write vs delete
  • Display - View vs control
  • Database - Query vs modify

See: Proxy Permissions → for complete configuration.


How do you know what URLs a container has?

Option 1: Construct URLs (Deterministic Pattern)

Section titled “Option 1: Construct URLs (Deterministic Pattern)”
// You know: projectId, containerId, serverName
const projectId = "67e89abc123def456789abcd";
const containerId = "890abcdef12345678901cdef";
const serverName = "node-us";
// Construct any service URL
const terminalUrl = `https://${projectId}-${containerId}-terminal-1.${serverName}.containers.hoody.icu`;
const displayUrl = `https://${projectId}-${containerId}-display-1.${serverName}.containers.hoody.icu`;
const sqliteUrl = `https://${projectId}-${containerId}-sqlite-1.${serverName}.containers.hoody.icu`;
Terminal window
# Get container details with live service information
hoody containers get $CONTAINER_ID --runtime true
GET Get container details with live service information
/api/v1/containers/{containerId}?runtime=true
Click "Run" to execute the request

Response includes live service information:

{
"data": {
"id": "890abcdef12345678901cdef",
"project_id": "67e89abc123def456789abcd",
"server_name": "node-us",
"runtime_info": {
"terminals": [
{ "id": "1", "display": 1, "username": "user" }
],
"displays": [
{ "display": 1, "pid": 12345, "connected_clients": 2 }
],
"services": [
{ "name": "hoody-sqlite", "status": "running", "pid": 23456 }
]
}
}
}

Then construct URLs for running services.


The Hoody API does NOT use the container pattern:

Hoody API: https://api.hoody.icu
(platform management, no project/container prefix)
Container: https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
(container service, includes project/container IDs)

Why the difference:

  • Hoody API manages the platform (create containers, configure networks, manage billing)
  • Container services run inside containers (execute commands, access files, query databases)

One API spawns containers. Container URLs are what you spawned.


Create memorable URLs for production:

Terminal window
# Create a memorable alias instead of cryptographic URLs
hoody proxy create --container-id $CONTAINER_ID --alias my-api --program http --port 3000

Result: my-api.{serverName}.containers.hoody.icu routes to your container’s HTTP service.

See: Proxy Aliases →

Point your own domain to container services:

Terminal window
# Create alias as CNAME target
hoody proxy create --container-id $CONTAINER_ID --alias my-app --program http --port 3000
# Then point your domain via DNS
# api.mycompany.com CNAME my-app.node-us.containers.hoody.icu
# SSL certificate provisioned automatically

See: Connect a Domain →

Route different paths to different containers:

Terminal window
# Create alias with target path routing
hoody proxy create --container-id $CONTAINER_ID \
--alias my-app --program http --port 3000 \
--target-path /api/v1 --allow-path-override

Routing:

  • my-app.node-us.containers.hoody.icu/api/v1/users → Container’s /api/v1/users
  • my-app.node-us.containers.hoody.icu/api/v1/posts → Container’s /api/v1/posts

Configure who can access what:

Project level (applies to all containers):

Terminal window
# Set project-level proxy permissions (IP-restricted).
# `projects proxy permissions replace` cannot express this today, so build the
# document one field at a time, re-reading file_version between commands with
# `hoody projects proxy permissions get --project $PROJECT_ID -o json`
hoody projects proxy groups ip set --project $PROJECT_ID \
--group-name developers --range 203.0.113.0/24 --if-match file:v<N>
hoody projects proxy groups permissions set --project $PROJECT_ID \
--group-name developers --program terminal --access true --if-match file:v<N>
hoody projects proxy groups permissions set --project $PROJECT_ID \
--group-name developers --program files --access true --if-match file:v<N>
hoody projects proxy default --project $PROJECT_ID --default deny --if-match file:v<N>

Container level (overrides project):

Terminal window
# Override permissions for a specific container (public HTTP only).
# `containers proxy permissions replace` cannot express this today, so build the
# document one field at a time, re-reading file_version between commands with
# `hoody containers proxy permissions get -c $CONTAINER_ID -o json`
hoody containers proxy groups ip set -c $CONTAINER_ID \
--group-name public --range 0.0.0.0/0 --if-match file:v<N>
hoody containers proxy groups permissions set -c $CONTAINER_ID \
--group-name public --program http --access '[8080]' --if-match file:v<N>
hoody containers proxy groups permissions set -c $CONTAINER_ID \
--group-name public --program files --access false --if-match file:v<N>
hoody containers proxy default -c $CONTAINER_ID --default deny --if-match file:v<N>

See: Proxy Permissions → for complete authentication configuration.


When every capability is HTTP:

  1. Any device can control any container

    • Phone → Terminal → Execute deployment
    • Tablet → Display → Access full desktop
    • Smart watch → Files → Read logs
    • IoT device → Agent → Trigger workflow
  2. Any service can call any other service

    • hoody-exec calls hoody-terminal to run commands
    • hoody-terminal calls hoody-sqlite to store results
    • hoody-agent orchestrates everything via HTTP
    • External APIs integrate via hoody-curl
  3. Any AI can orchestrate everything

    • LLMs already understand HTTP
    • No SDK needed
    • No custom training
    • Just make HTTP requests
  4. Everything is embeddable

    • Terminals in documentation
    • Desktops in dashboards
    • Databases in spreadsheets
    • All via <iframe src="...hoody.icu">

The proxy makes this possible by transforming every container capability into a first-class web citizen.


Important: Each of your bare metal servers runs its own Hoody Proxy container.

This means:

Server 1 (node-us):
└─ Hoody Proxy Container
├─ Routes traffic to Server 1's containers
└─ URLs: ...node-us.containers.hoody.icu
Server 2 (node-eu):
└─ Hoody Proxy Container
├─ Routes traffic to Server 2's containers
└─ URLs: ...node-eu.containers.hoody.icu

Container URLs include the server name (node-us, node-eu) so you know which proxy handles them.

Cross-server communication: Containers on different servers communicate via their public URLs (through their respective proxies). Use Realms for API isolation (token scoping and safety), not networking.


Proxy handles concurrent connections:

  • Thousands of WebSocket connections per service
  • HTTP keep-alive for efficiency
  • Connection pooling to backend services
  • Graceful degradation under load

The proxy does not cache — it streams. Request and response bodies pass straight through (no cache zones, proxy_buffering off). Set Cache-Control headers in your services for client-side/CDN caching; the proxy forwards them untouched.

Per-service limits are set by the individual Kit services (hoody-files, hoody-exec, hoody-sqlite, etc.); the proxy streams request and response bodies without imposing its own size ceiling. Check each service’s OpenAPI spec for the exact limits — there is no single global “request body: X MB” ceiling enforced at the proxy layer today.


Clear distinction:

Hoody Proxy (Infrastructure)

Location: Container on your server

Responsibilities:

  • TLS termination
  • URL routing
  • IP preservation
  • Authentication enforcement
  • Protocol handling
  • Certificate management

You configure: Aliases, permissions, routing rules

Container Services (Capabilities)

Location: Inside your containers

Responsibilities:

  • Actual functionality
  • Command execution
  • File operations
  • Database queries
  • Display rendering

You use: The HTTP endpoints they expose

The proxy routes TO services. Services provide capabilities.


Does the Hoody Proxy run on Hoody’s servers or mine?

Section titled “Does the Hoody Proxy run on Hoody’s servers or mine?”

Your server. The Hoody Proxy runs as a container on YOUR bare metal. All container traffic terminates on the machine you rent — there is no central Hoody proxy tier between your users and your containers. Platform management operations go through the Hoody API.

Why can’t I access UDP services through the proxy?

Section titled “Why can’t I access UDP services through the proxy?”

The Hoody Proxy carries HTTP/1.1, HTTP/2, WebSocket (TCP), and HTTP/3 over QUIC — the one UDP-based protocol it supports. Other UDP protocols cannot route through it. For UDP applications, you need to either use Container Firewall to configure direct access, or bring an IPv4 address to the container via IPv4 Management.

Do I need to manage SSL certificates for container services?

Section titled “Do I need to manage SSL certificates for container services?”

No. All *.{serverName}.containers.hoody.icu URLs use wildcard certificates automatically managed by Hoody. For custom domains (via CNAME), SSL is provisioned automatically via Let’s Encrypt when your DNS points to an alias. You never touch certificates.

Can I run my own reverse proxy inside a container?

Section titled “Can I run my own reverse proxy inside a container?”

Yes! You can install nginx, Caddy, Traefik, or any proxy inside containers. The Hoody Proxy routes to your container’s exposed port, then your internal proxy handles further routing. Common pattern: Hoody Proxy → nginx in container → multiple backend services.

What happens if I run multiple HTTP servers in one container?

Section titled “What happens if I run multiple HTTP servers in one container?”

Access them via different ports: http-3000, http-5000, http-8000 in the URL. The Hoody Proxy routes each to the correct internal port automatically. Alternatively, use one internal nginx proxy and route through http-80.

Does the proxy add latency to my applications?

Section titled “Does the proxy add latency to my applications?”

Minimal. The proxy runs on the same physical server as your containers (localhost routing). TLS termination and IP preservation add <1ms overhead. Your application’s response time dominates—proxy latency is negligible.

Can clients access containers without going through the proxy?

Section titled “Can clients access containers without going through the proxy?”

Not by default. All traffic flows through the proxy for security and observability. However, you can configure direct access via IPv4 addresses or SSH which bypass the proxy completely.

Why does my application see the real client IP without proxy headers?

Section titled “Why does my application see the real client IP without proxy headers?”

Hoody uses custom netfilter hooks at the kernel level to preserve the original client connection information. Your container sees the real client IP in remoteAddr as if there were no proxy—no X-Forwarded-For parsing needed.

Can I disable the proxy for a specific container?

Section titled “Can I disable the proxy for a specific container?”

Yes. Via SDK: client.api.proxyPermissionsContainer.updateState(CONTAINER_ID, { enable_proxy: false }, { ifMatch: 'file:v<N>' }), or HTTP: PATCH /api/v1/containers/{id}/proxy/permissions/state with {"enable_proxy": false} and an If-Match: file:v<N> header (the ETag from a prior GET). Note: the CLI hoody containers proxy state command can only enable the proxy (it always sends enable_proxy: true); disabling requires the SDK or HTTP path above. When disabled, the proxy stops serving that container: new requests to its service URLs are answered with 403 instead of being forwarded. This is a kill-switch, not a bypass — the switch is evaluated before authentication groups, permission rules, and the default policy, so nothing can re-open access while it is off. Set it at container level: the container setting wins over the project one in both directions, and because the API persists an explicit enable_proxy: true whenever a container permissions document is saved, a project-level false will not disable a container that has its own document. The container keeps running, and access that does not traverse the proxy (for example SSH) is unaffected. Re-enable to restore group/permission enforcement.

Do I need different proxies for different containers?

Section titled “Do I need different proxies for different containers?”

No. One Hoody Proxy per server handles ALL containers on that server. The proxy routes based on the projectId-containerId pattern in URLs. Each server runs its own proxy instance, but you don’t manage multiple proxies manually.


Problem: Service URLs return connection errors or timeouts

Check container status:

GET Verify container status and running services
/api/v1/containers/{container_id}?runtime=true
Click "Run" to execute the request

Verify:

  • status: “running” (not stopped or error)
  • runtime_info shows services are running

Common causes:

  1. Container not running:

    POST Start the container (use operation=start)
    /api/v1/containers/{container_id}/{operation}
    Click "Run" to execute the request
  2. Service not started in container:

    Terminal window
    # SSH into container and check
    # Or use terminal URL to verify service is running
  3. Wrong service name in URL:

    Terminal window
    # Wrong: ...terminal... (service doesn't exist)
    # Correct: Check container's runtime_info for available services

Problem: Cryptographic or alias URLs return authentication errors

Cause: Proxy permissions configured, but you don’t match any group

Check permissions:

GET Check project-level proxy permissions
/api/v1/projects/{project_id}/proxy/permissions
Click "Run" to execute the request
GET Check container-level proxy permissions
/api/v1/containers/{container_id}/proxy/permissions
Click "Run" to execute the request

Solutions:

  1. If IP-based auth: Verify you’re connecting from whitelisted IP

    Terminal window
    curl https://ifconfig.me # Check your current IP
  2. If JWT/password auth: Ensure credentials are correct

  3. Temporarily remove permissions for testing:

    DELETE Remove container permissions (reverts to open access)
    /api/v1/containers/{container_id}/proxy/permissions
    Click "Run" to execute the request

Problem: All container URLs return 403, and no permission rule explains it

A disabled proxy is not distinguishable from an ordinary access denial by looking at the response: both surface as Error 403: Access denied. for CLI clients and as the standard error page in a browser. Don’t try to diagnose this from the response body — read the switch directly, and check the container level as well as the project level.

Check proxy state:

GET Check if proxy is enabled (look for enable_proxy in response)
/api/v1/projects/{project_id}/proxy/permissions
Click "Run" to execute the request

Solution:

Re-enable proxy at project level:

PATCH Re-enable proxy at project level
/api/v1/projects/{project_id}/proxy/permissions/state
Click "Run" to execute the request

Or at container level:

PATCH Re-enable proxy at container level
/api/v1/containers/{container_id}/proxy/permissions/state
Click "Run" to execute the request

Problem: Browser shows certificate warnings for container URLs

Reality: This shouldn’t happen - every *.{serverName}.containers.hoody.icu URL has a valid wildcard certificate

If it occurs:

  1. Clear browser cache - Old cached certificates might cause issues
  2. Try different browser - Isolate if browser-specific
  3. Check system time - Wrong time causes certificate validation failures
  4. Verify URL: Ensure you’re accessing the container’s real hostname under *.{serverName}.containers.hoody.icu, not a typo

Problem: https://...http-3000.node-us.containers.hoody.icu returns connection error

Solutions:

  1. Verify service is running on that port in container:

    Terminal window
    # SSH or use terminal URL to check
    netstat -tlnp | grep 3000
    # Should show service listening on port 3000
  2. Check it’s the correct port number:

    Terminal window
    # If your app runs on 5000, use:
    # https://...http-5000.node-us.containers.hoody.icu
  3. Ensure service binds to 0.0.0.0 not localhost:

    // Wrong (localhost only)
    app.listen(3000, 'localhost');
    // Correct (accessible from proxy)
    app.listen(3000, '0.0.0.0');

Problem: Application sees proxy IP instead of real client IP

This shouldn’t happen - Hoody preserves real IPs via netfilter hooks

If it occurs:

  1. Verify you’re reading remoteAddr correctly:

    Node.js
    const clientIP = req.connection.remoteAddress;
    // or req.socket.remoteAddress
  2. Contact support - This indicates infrastructure issue


Understand proxy features:

  1. Create Aliases → - Clean URLs: my-app.node-us.containers.hoody.icu
  2. Connect a Domain → - Point api.mycompany.com to containers
  3. Configure Permissions → - Authentication and access control

Explore container services:


The Hoody Proxy is the gateway to everything.
It runs on your server. You control it.
Every container capability becomes a URL.
Real client IPs. Automatic HTTPS. Zero configuration.

This is the infrastructure that enables infinite HTTP computers.