Understanding Containers
Section titled “Understanding Containers”A Hoody container is a full Debian 13 Linux computer that arrives online. It runs systemd and has its own filesystem, its own network, and 18 built-in HTTP services, and every process, file, and database inside it has a URL from the moment it exists. It is closer to a machine than to a Docker image: you can install Docker, Podman, LXC, or a virtual machine inside one and run your own containers on top.
The primary interface is HTTP rather than SSH or a deploy pipeline: every process running inside is already an HTTPS endpoint, served with HTTP/2, so you fetch a container instead of shelling into it. ssh hoody.com still opens the Hoody CLI and Agent from any terminal, and nothing stops you from deploying to a container the conventional way. The proxy issues and renews the certificates; you never create or renew one yourself.
Included services
Section titled “Included services”Every container created with Hoody Kit enabled (hoody_kit: true) includes the services below. They all answer on the same hostname shape, and only the service label changes between them:
https://{projectId}-{containerId}-{service}-{instance}.{server}.containers.hoody.com| Capability | Service label |
|---|---|
| Shell access | terminal-1 |
| File system | files-1 |
| Database | sqlite-1 |
| Desktop display | display-1 |
| Browser automation | browser-1 |
| Script execution | exec-1 |
| AI agent (Hoody Agent) | agent-1 |
| VS Code | code-1 |
| HTTP composition | curl-1 |
| Background processes | daemon-1 |
| Scheduled tasks | cron-1 |
| Push notifications | n-1 |
| Data streaming | pipe-1 |
| Collaborative notebooks | notes-1 |
| File watching | watch-1 |
| Application launch | run-1 |
| TCP tunneling | tunnel-1 |
| Proxy access logs | logs-1 |
Substituting a real project, container, and server gives the shell for that container. Both ids are 24 hexadecimal characters:
https://67e89abc123def456789abcd-890abcdef12345678901cdef-terminal-1.node-us.containers.hoody.comAll 18 ship in every Kit-enabled container. They are reachable from any device with a browser, and can be driven from any terminal through the Hoody CLI (ssh hoody.com).
Create a container
Section titled “Create a container”# Create a container in your projecthoody containers create --project $PROJECT_ID --name "backend" --server-id $SERVER_ID
# List your containershoody containers listimport { HoodyClient } from 'hoody-sdk';const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const container = await client.api.containers.create(PROJECT_ID, { server_id: SERVER_ID, name: 'backend'});
// The new container is already onlineconsole.log(container.data.id);curl -X POST https://api.hoody.com/api/v1/projects/$PROJECT_ID/containers \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"server_id": "'"$SERVER_ID"'", "name": "backend"}'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
The same call as a single GET URL. It runs through the curl-1 service of a
container you already have, so the first container comes from one of the other
tabs. Every container after that can come from a link.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/PROJECT_ID/containers&method=POST&bearer_token=TOKEN&json={"server_id":"SERVER_ID","name":"backend"}&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 URL structure
Section titled “The URL structure”Every service in every container has a predictable URL:
https://{projectId}-{containerId}-{serviceName}-{serviceId}.{node}.containers.hoody.comFor example:
https://PROJECT_ID-CONTAINER_ID-terminal-1.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-files-1.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-display-1.node-us.containers.hoody.comDifferences from Docker
Section titled “Differences from Docker”| Feature | Docker | Hoody Containers |
|---|---|---|
| Base system | Minimal layers | Full Debian 13 + systemd |
| Networking | Internal bridge, port mapping | Every service has a public URL |
| Access method | docker exec / SSH | HTTP from anywhere |
| Built-in services | None; you bring everything | 18 HTTP services included |
| Collaboration | Not designed for it | Multiplayer by default |
| Snapshots | Volume snapshots only | Full filesystem snapshots and restore |
| Multiple instances | Separate containers | terminal-1, terminal-2… in the same container |
Docker containers are build artifacts; Hoody containers are computers.
Multiple instances
Section titled “Multiple instances”A container can run several instances of the same service. Three terminals, two databases, and a browser:
https://PROJECT_ID-CONTAINER_ID-terminal-1.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-terminal-2.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-terminal-3.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-sqlite-1.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-sqlite-2.node-us.containers.hoody.comhttps://PROJECT_ID-CONTAINER_ID-browser-1.node-us.containers.hoody.comAll six run in the same container. Each instance has its own URL, its own process, and its own state.
Container lifecycle
Section titled “Container lifecycle”# Start a stopped containerhoody containers manage $CONTAINER_ID start
# Stop a running containerhoody containers manage $CONTAINER_ID stop
# Snapshot before making changeshoody snapshots create --container $CONTAINER_ID --alias "before-experiment"
# Restore if something breakshoody snapshots restore --container $CONTAINER_ID --name $SNAPSHOT_NAME// Startawait client.api.containers.manage(CONTAINER_ID, 'start');
// Stopawait client.api.containers.manage(CONTAINER_ID, 'stop');
// Snapshotconst snapshot = await client.api.containers.createSnapshot(CONTAINER_ID, { alias: 'before-experiment'});
// Restoreawait client.api.containers.restoreSnapshot(CONTAINER_ID, SNAPSHOT_NAME);# Startcurl -X POST https://api.hoody.com/api/v1/containers/$CONTAINER_ID/start \ -H "Authorization: Bearer $TOKEN"
# Stopcurl -X POST https://api.hoody.com/api/v1/containers/$CONTAINER_ID/stop \ -H "Authorization: Bearer $TOKEN"
# Snapshotcurl -X POST https://api.hoody.com/api/v1/containers/$CONTAINER_ID/snapshots \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "before-experiment"}'
# Restorecurl -X PUT https://api.hoody.com/api/v1/containers/$CONTAINER_ID/snapshots/$SNAPSHOT_NAME \ -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
Each action as a single GET URL. Route them through a different running
container’s curl-1 (OTHER_CONTAINER_ID below): a stopped container cannot
serve the request that starts it.
# Start
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/CONTAINER_ID/start&method=POST&bearer_token=TOKEN&response=transparent
# Stop
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/CONTAINER_ID/stop&method=POST&bearer_token=TOKEN&response=transparent
# Snapshot
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/CONTAINER_ID/snapshots&method=POST&bearer_token=TOKEN&json={"alias":"before-experiment"}&response=transparent
# Restore
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/CONTAINER_ID/snapshots/SNAPSHOT_NAME&method=PUT&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.
Container cost
Section titled “Container cost”Pricing is per server, not per container: you pay for the bare metal, and the containers on it carry no per-unit cost. Once a server exists, you can create as many as its capacity allows.
Under per-VPS pricing, three environments at $40 a month each cost $120 a month. On Hoody, one server carries all of them. That removes the usual reason to ration environments: a dev container, a staging copy, an experiment, and an AI playground can each get their own container.
Next: The Hoody Proxy →