Create, Edit, Delete
Section titled “Create, Edit, Delete”Containers are HTTP computers you create on demand. Creation takes 1-5 seconds, or under a second when a warm prespawn container matches. You configure a container through the fields in the create request, change most of them later with an update, and remove it with a delete.
This page covers those three operations, the configuration fields they accept, the lifecycle states a container moves through, and the list endpoints. Projects & Containers covers how the two objects relate.
API endpoints summary
Section titled “API endpoints summary”This Foundation page explains container CRUD concepts and workflows. The endpoint reference lives here:
Container creation:
- POST /api/v1/projects/{id}/containers - Create new container
- GET /api/v1/containers - List all containers
- GET /api/v1/containers/{id} - Get container details
Container modification:
- PATCH /api/v1/containers/{id} - Update container configuration
Container deletion:
- DELETE /api/v1/containers/{id} - Delete container permanently
Related operations:
- Container Operations - Start/stop/pause/resume
- Projects - Project management
Create a container
Section titled “Create a container”With hoody_kit: true, a new container comes up with the full Hoody Kit HTTP service stack already installed.
The create request
Section titled “The create request” Within 1-5 seconds the container is running (prespawn) or creating (regular), the full Hoody Kit HTTP stack is live, and the service URLs are generated.
Startup timing depends on whether a warm container was available:
- With prespawn: sub-second, claimed from the warm pool
- Without prespawn: 1-5 seconds, created on demand
The response carries the container record:
{ "statusCode": 201, "message": "Container created successfully", "data": { "id": "890abcdef12345678901cdef", "project_id": "67e89abc123def456789abcd", "server_id": "63f8b0e5c9a1b2d3e4f5a6b7", "server_name": "node-us", "name": "dev-environment", "status": "creating", "hoody_kit": true, "dev_kit": true }}The service URLs are live immediately:
Terminal: https://67e89abc123def456789abcd-890abcdef12345678901cdef-terminal-1.node-us.containers.hoody.comDisplay: https://67e89abc123def456789abcd-890abcdef12345678901cdef-display-1.node-us.containers.hoody.comFiles: https://67e89abc123def456789abcd-890abcdef12345678901cdef-files-1.node-us.containers.hoody.comExec: https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.comSQLite: https://67e89abc123def456789abcd-890abcdef12345678901cdef-sqlite-1.node-us.containers.hoody.com+ the rest of the 19 Kit services...Configuration options
Section titled “Configuration options”The create request body accepts the following fields.
Essential parameters
Section titled “Essential parameters”{ "name": "my-container"}- 3-100 characters
- Alphanumeric + hyphens/underscores
- Unique within project
- Use
"rand"or omit for auto-generated name
{ "server_id": "63f8b0e5c9a1b2d3e4f5a6b7"}- Required during creation
- Determines where container runs
- Get it from
GET /api/v1/rentals(or its aliasGET /api/v1/servers), your own inventory - Not
GET /api/v1/servers/available: that’s the rental marketplace, and its ids are for renting a server, not for placing a container - Choose by geography, capacity, or price
{ "hoody_kit": true}true: install the Hoody Kit HTTP services (terminal, display, files, sqlite, browser, exec, agent, code, curl, cron, notifications, pipe, notes, watch, run, tunnel, proxy logs, daemon)false: plain Linux container- Recommended:
true, unless you specifically want a plain container - Cannot be changed after creation
{ "dev_kit": true}true: include developer-focused Kit services (editor, agent, and related developer tooling) on top ofhoody_kitfalse: omit the developer stack to keep the image smaller- Default:
truewhenhoody_kit: true - Cannot be changed after creation
Image selection
Section titled “Image selection”Set container_image to choose the operating system:
{ "container_image": "debian/13"}Available images:
debian/13- Debian 13 Trixie (recommended default)ubuntu/24.04- Ubuntu 24.04 LTSubuntu/22.04- Ubuntu 22.04 LTSalpine/3.19- Alpine Linux (minimal)fedora/<release>- Fedora (pick an available release fromGET /api/v1/images/public?os=fedora)
Default: if omitted or null, the system default image is used. That is currently debian/13 (Debian 13 Trixie). You can override it with any image from the marketplace.
See: Container Images for complete marketplace and OS options.
Realm assignment
Section titled “Realm assignment”Assign a container to one or more realms for API-level isolation:
{ "realm_ids": ["64a2c4e9f3d5e2b6a8c7d8e1", "65b3d5f0a4e6f3c7b9d8e9f2"]}Realms are not private networks. They segregate the Hoody API:
- Different realms use different API endpoints:
https://{realmId}.api.hoody.com - AI agents in one realm can’t discover containers in another
- Auth tokens can be scoped to specific realms
- Production/staging/development separated at API level
When creating from a realm-scoped host:
- The target project must already include that realm.
- The scoped realm is merged into container
realm_ids. - Realm-restricted auth tokens are forced to the active scoped realm only.
See: Realms for complete API segregation details.
Environment variables
Section titled “Environment variables”Pass environment variables for your application:
{ "environment_vars": { "NODE_ENV": "production", "DATABASE_URL": "postgresql://...", "API_KEY": "your-secret-key" }}These are available in the container immediately.
SSH access
Section titled “SSH access”Provide your SSH public key:
{ "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx..."}Generate a separate key pair per container:
# Generate new key pair for each containerssh-keygen -t ed25519 -f ~/.ssh/hoody-container-1 -N ""ssh-keygen -t ed25519 -f ~/.ssh/hoody-container-2 -N ""
# Use different public keyscontainer_1: {"ssh_public_key": "ssh-ed25519 AAAA... (from container-1.pub)"}container_2: {"ssh_public_key": "ssh-ed25519 AAAA... (from container-2.pub)"}Reusing a key breaks routing: two containers cannot share one SSH identity.
See: SSH Access for SSH configuration.
Container color
Section titled “Container color”Each container can carry a hex color, shown in the UI:
{ "color": "#3498db" // HEX color (with or without #)}The scheme borrows from Qubes OS, which uses color to mark security domains (red for untrusted, green for trusted). A color makes a container identifiable in a long list without reading its name.
Common schemes:
- WebOS builders: one color per workspace or application
- Security zones: red for public-facing, green for internal, blue for database
- Multi-user teams: one color per user or team
- Environment types: yellow for dev, orange for staging, green for production
Additional options
Section titled “Additional options”{ "comment": "Development environment for Project X", "autostart": true, // Auto-start when host reboots (default: true) "ai": true, // Enable AI features (default: true) "cache": true, // Use cached images (faster creation) "bypass_prespawn": true, // Non-default: skip warm claiming only when you require a guaranteed fresh build "ramdisk": true, // enabled by default, set false to disable "ramdisk_scope": "container" // "container" is the only accepted value today}autostart (default true)
true: the container starts automatically when the host machine rebootsfalse: the container stays stopped after a host reboot and needs a manual start
The default is true so services stay available across server maintenance and restarts.
ramdisk (enabled by default)
/ramdiskis mounted by default for temporary storage in RAM. Setramdisk: falseto leave it out.- RAM is allocated as you write, so an empty
/ramdiskconsumes none. - Capacity is a shared per-server pool: 512 MiB by default, never more than 50% of that server’s memory, shared by all your containers on that server. The size is not adjustable.
- It is memory, not disk: it counts against your server’s memory, not its disk space.
ramdisk_scope:/ramdiskis private to each container. A sharedprojectscope exists in the data model but is not currently accepted: asking forramdisk_scope: "project"on create or update returns 400 while a permission boundary is corrected.containeris the only value the API takes today.- Data survives container restarts. It is lost when the host machine reboots.
- Useful for caches, build artifacts, and temporary processing that needs the speed.
- See: /ramdisk for usage patterns and memory balancing.
Creation examples
Section titled “Creation examples”Development container
Section titled “Development container”The full Kit stack, AI enabled, autostart on, and a color for the UI:
Use case: a day-to-day working container that comes back automatically after a host reboot.
Production API container
Section titled “Production API container”Scoped to a single realm, on debian/13, with the app’s environment set at creation:
Then configure:
- Create proxy alias for clean URL
- Set proxy permissions for authentication
- Configure firewall rules for security
Minimal utility container
Section titled “Minimal utility container”An Alpine container that stays stopped until you start it:
Use case: backup jobs you run occasionally, on a small image.
AI agent container
Section titled “AI agent container”For AI orchestration, with the provider keys passed as environment variables:
The hoody-agent service is then reachable at:
https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-us.containers.hoody.comUpdate a container
Section titled “Update a container”Update workflow
Section titled “Update workflow”No stop is normally required. PUT /api/v1/containers/{id} accepts updates while the container is running, paused, or stopped, except that narrowing ramdisk_scope to container is rejected while running. Updates are refused while the container is being claimed or quarantined; enabling autostart also returns 409 Conflict until a network policy is in force and any hard access suspension is lifted. Environment-variable changes do not generally require a restart: after successful live synchronization, new exec/console processes see them immediately, and the dedicated containers env endpoints also update /etc/environment for new SSH/console logins; already-running processes must re-exec.
hoody containers update $CONTAINER_ID \ --name renamed-container \ --environment-vars NODE_ENV=stagingawait client.api.containers.update(CONTAINER_ID, { name: 'renamed-container', environment_vars: { NODE_ENV: 'staging' }});curl -X PATCH "https://api.hoody.com/api/v1/containers/{container_id}" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "renamed-container", "environment_vars": {"NODE_ENV": "staging"} }'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
Renames CONTAINER_ID and switches its NODE_ENV to staging in one call. New exec and console sessions pick up the change immediately; a process already running needs to re-exec to see it.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/CONTAINER_ID&method=PATCH&bearer_token=TOKEN&json={"name":"renamed-container","environment_vars":{"NODE_ENV":"staging"}}&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.
Editable and fixed fields
Section titled “Editable and fixed fields”Metadata:
name- rename the containercolor- change the UI colorcomment- update the description
Configuration:
environment_vars- add, modify, or remove environment variablesssh_public_key- change the SSH access keyrealm_ids- update API realm membership (realm-restricted tokens cannot modify this)autostart- enable or disable auto-startai- enable or disable AI featuresramdisk- enable or disable the ramdisk mountramdisk_scope-containeris accepted (and is how aproject-scoped row narrows back); widening toprojectis unavailable and returns 400. Narrowing back tocontaineris rejected while the container is running; pause or stop it first
Fixed at creation:
container_image- the OS is permanent; create a new container to change ithoody_kit- service installation is permanentdev_kit- the developer tooling choice is permanentserver_id- a container cannot move servers; use copy instead
Update examples
Section titled “Update examples”Change environment variables
# Switch from staging to productionPATCH /api/v1/containers/{id}{ "environment_vars": { "NODE_ENV": "production", "API_BASE_URL": "https://api.mycompany.com" }}Move to a different realm
# Isolate to production networkPATCH /api/v1/containers/{id}{ "realm_ids": ["64a2c4e9f3d5e2b6a8c7d8e1"]}Delete a container
Section titled “Delete a container”A delete removes the container and all of its data permanently.
The delete request
Section titled “The delete request” What gets deleted:
- the container filesystem and all data
- environment variables
- network configuration
- firewall rules
- all service URLs, which become inaccessible
- Snapshots: they cascade-delete with the container. Copy the container first if you need to keep its state.
- Existing copies: they keep running as independent containers, but can no longer be synced, because the source link is broken.
Safe deletion workflow
Section titled “Safe deletion workflow”# 1. Create final snapshothoody snapshots create --container $CONTAINER_ID --alias "before-deletion-2025-11-09"
# 2. Stop running containerhoody containers manage $CONTAINER_ID stop
# 3. Permanent deletionhoody containers delete $CONTAINER_ID
# 4. Cleanup (optional) - delete proxy aliaseshoody proxy delete $ALIAS_ID// 1. Create final snapshotawait client.api.containers.createSnapshot(CONTAINER_ID, { alias: 'before-deletion-2025-11-09' });
// 2. Stop running containerawait client.api.containers.manage(CONTAINER_ID, 'stop');
// 3. Permanent deletionawait client.api.containers.delete(CONTAINER_ID);
// 4. Cleanup (optional)await client.api.proxyAliases.delete(ALIAS_ID);# 1. Create final snapshotcurl -X POST "https://api.hoody.com/api/v1/containers/{id}/snapshots" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "before-deletion-2025-11-09"}'
# 2. Stop running containercurl -X POST "https://api.hoody.com/api/v1/containers/{id}/stop" \ -H "Authorization: Bearer $HOODY_TOKEN"
# 3. Permanent deletioncurl -X DELETE "https://api.hoody.com/api/v1/containers/{id}" \ -H "Authorization: Bearer $HOODY_TOKEN"
# 4. Cleanup (optional) - delete proxy aliasescurl -X DELETE "https://api.hoody.com/api/v1/proxy/aliases/{alias_id}" \ -H "Authorization: Bearer $HOODY_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
Four links for the safe-deletion sequence: snapshot, stop, delete, then remove the proxy alias. Route them through a different running container’s curl-1 — CONTAINER_ID is stopped and then deleted partway through, so it can’t serve the later steps of its own deletion.
# Create 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-deletion-2025-11-09"}&response=transparent
# Stop container
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
# Delete container
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&method=DELETE&bearer_token=TOKEN&response=transparent
# Delete proxy alias
https://PROJECT_ID-OTHER_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.
Best practice: keep snapshots of production containers for disaster recovery.
The Hoody Kit
Section titled “The Hoody Kit”Setting hoody_kit: true installs the full Hoody Kit HTTP stack.
Installed services
Section titled “Installed services”Interact and visualize:
- Terminal (hoody-terminal) - web-based terminal
- Display (hoody-display) - full desktop environment
- Browser (hoody-browser) - Chrome automation
Data and state:
- Files (hoody-files) - filesystem access
- SQLite (hoody-sqlite) - database and KV store
Automate and orchestrate:
- Exec (hoody-exec) - scripts as HTTP APIs
- cURL (hoody-curl) - HTTP request wrapper
Operate and monitor:
- Daemons (hoody-daemon) - process management
- Notifications (hoody-notifications) - alerts
- Code (hoody-code) - VS Code instances
- Cron (hoody-cron) - scheduled task runner
- Pipe (hoody-pipe) - data streaming between services
- Agent (hoody-agent) - collaborative WebOS interface
Installation time: included in container creation, with no extra wait.
See: The Hoody Kit for complete service documentation.
Container lifecycle states
Section titled “Container lifecycle states”A container moves through these states:
creating → running → (paused) → stopped → deleting ↓ ↑ (can pause) (can restart)State descriptions
Section titled “State descriptions”| State | Description | Transitions available |
|---|---|---|
creating | Container being provisioned | → running (automatic) |
running | Container is active | → stopped, paused |
paused | Container suspended | → running (resume) |
stopped | Container is stopped | → running (start) |
failed | Creation or operation failed | → deleting (cleanup) |
copying | Being copied to another location | → running (when complete) |
deleting | Being permanently removed (async) | (record is removed on completion) |
Read the current state:
See: Managing Containers for state transitions.
List containers
Section titled “List containers”All containers
Section titled “All containers” Project containers
Section titled “Project containers” Filters and pagination
Section titled “Filters and pagination” Runtime information
Section titled “Runtime information”Add runtime=true to get live service status:
The response adds:
- active terminal sessions
- display connections
- running services, with PIDs
- network services and ports
- command history
Use this to confirm services are up before you call their URLs.
Complete workflow example
Section titled “Complete workflow example”Create a project, pick a server, create a container, and confirm it is running:
# 1. Create a projecthoody projects create --alias "client-acme" --color "#e74c3c"
# 2. Check your servershoody servers list
# 3. Create a containerhoody containers create --project $PROJECT_ID \ --server-id $SERVER_ID \ --name "acme-frontend" \ --hoody-kit \ --dev-kit
# 4. Verify it's runninghoody containers get $CONTAINER_ID
# 5. Container URLs are live:# https://{project_id}-{container_id}-terminal-1.{server_name}.containers.hoody.com# https://{project_id}-{container_id}-display-1.{server_name}.containers.hoody.comimport { HoodyClient } from 'hoody-sdk';const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: TOKEN });
// 1. Create a projectconst project = await client.api.projects.create({ alias: 'client-acme', color: '#e74c3c'});
// 2. Get server ID from rentalsconst rentals = await client.api.rentals.list();const serverId = rentals.data[0].server_id;
// 3. Create a containerconst container = await client.api.containers.create(project.data.id, { name: 'acme-frontend', server_id: serverId, hoody_kit: true, ssh_public_key: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...'});
// 4. Verify it's runningconst status = await client.api.containers.get(container.data.id);console.log(status.data.status); // 'running'# 1. Create a projectcurl -X POST "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "client-acme", "color": "#e74c3c"}'
# 2. Check your serverscurl "https://api.hoody.com/api/v1/rentals" \ -H "Authorization: Bearer $HOODY_TOKEN"
# 3. Create a containercurl -X POST "https://api.hoody.com/api/v1/projects/{project_id}/containers" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "acme-frontend", "server_id": "{server_id}", "hoody_kit": true, "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..." }'
# 4. Verify it's runningcurl "https://api.hoody.com/api/v1/containers/{container_id}" \ -H "Authorization: Bearer $HOODY_TOKEN"
# 5. Container URLs are live:# https://{project_id}-{container_id}-terminal-1.{server_name}.containers.hoody.comOne 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 four calls as GET links: create the project, check available servers, create the container, then confirm it’s running. Route them through a different running container’s curl-1 (OTHER_CONTAINER_ID below) — the project and container being created in this sequence don’t exist yet, so they can’t serve their own creation.
# Create project
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=POST&bearer_token=TOKEN&json={"alias":"client-acme","color":"%23e74c3c"}&response=transparent
# Check servers
https://PROJECT_ID-OTHER_CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/rentals&method=GET&bearer_token=TOKEN&response=transparent
# Create container
https://PROJECT_ID-OTHER_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={"name":"acme-frontend","server_id":"SERVER_ID","hoody_kit":true,"ssh_public_key":"ssh-ed25519%20AAAAC3NzaC1lZDI1NTE5AAAA..."}&response=transparent
# Verify running
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&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.
Best practices
Section titled “Best practices”Let prespawn claim a warm container
Section titled “Let prespawn claim a warm container”Prespawn pools are maintained by the platform, not configured per account. A create claims a warm prespawn container whenever one matches, which is where sub-second availability comes from. Pass bypass_prespawn: true only when you need a guaranteed fresh build.
Generate a unique SSH key per container
Section titled “Generate a unique SSH key per container”Never reuse SSH keys. Generate a new ed25519 key pair for each container so Hoody’s SSH Proxy can route to it.
ssh-keygen -t ed25519 -f ~/.ssh/container-{name} -N ""Isolate AI agents in separate realms
Section titled “Isolate AI agents in separate realms”Give each AI agent its own realm. An agent scoped to realm A cannot discover or manage containers in realm B, so the separation holds at the API level.
Color-code containers by purpose
Section titled “Color-code containers by purpose”Pick a scheme and keep to it: red for public-facing, green for internal services, blue for databases, yellow for development. A color is faster to scan than a name.
Snapshot before you delete
Section titled “Snapshot before you delete”Create a snapshot before permanently deleting a container you may need again. The snapshot keeps all of its data available for recovery.
Set autostart by priority
Section titled “Set autostart by priority”Use autostart: true for services that must come back after a host reboot, and autostart: false for development containers, which saves resources between sessions.
Default to debian/13
Section titled “Default to debian/13”Unless you have a specific requirement, use debian/13 for its stability, security updates, and package availability.
Use /ramdisk for temporary data
Section titled “Use /ramdisk for temporary data”/ramdisk is enabled by default. Use it for caches, build artifacts, and other temporary processing that benefits from RAM speed. An empty ramdisk consumes no RAM.
Useful questions
Section titled “Useful questions”Can I change the OS after creating a container?
Section titled “Can I change the OS after creating a container?”No. The container_image is permanent. To move to a different OS:
- Snapshot your data
- Create a new container with the image you want
- Transfer the data through storage shares or a manual copy
- Delete the old container
How many containers can I create?
Section titled “How many containers can I create?”Optionally limited by the max_containers quota on your project (unset by default, so there’s no per-project cap unless you set one). Get the current quota via GET /api/v1/projects/{id}. Each server also enforces a per-server live-container limit (an explicit max_containers, or a free-tier default if none is set); exceeding it returns SERVER_CONTAINER_LIMIT. There is no platform-wide limit, so you can create as many projects as you need.
What happens if container creation fails?
Section titled “What happens if container creation fails?”Status becomes failed. Read the error from GET /api/v1/containers/{id}. Common causes:
- server out of capacity
- invalid image name
- resource quota exceeded
- network issues
Delete the failed container and try again.
Can I create containers without hoody_kit?
Section titled “Can I create containers without hoody_kit?”Yes. Set hoody_kit: false for a plain Linux container. That container comes with limits:
- Hoody Proxy: not attached, so container services are not reachable over HTTP
- Hoody Kit HTTP stack: not installed, so there is no terminal, display, files, or exec service
- SSH: the only way in, and only if you provide
ssh_public_keyor inherit one from the project defaults - Neither: without
hoody_kitand without an SSH key, the container is unreachable
Use when: you want minimal overhead, custom service installations, or you manage everything over SSH yourself.
Recommendation: use hoody_kit: true unless one of those cases applies.
Do I get charged for stopped containers?
Section titled “Do I get charged for stopped containers?”Storage charges apply to stopped containers, because they still occupy disk space. CPU and RAM charges stop when the container stops. To reduce cost, delete containers you no longer use or keep their storage allocation small.
Can I create containers on multiple servers at once?
Section titled “Can I create containers on multiple servers at once?”Yes. Each create is an independent HTTP request, so 100 containers across 10 servers can be created in parallel. This is the usual pattern for auto-scaling and for test fleets.
What’s the fastest way to create a container?
Section titled “What’s the fastest way to create a container?”Do nothing special. The platform keeps warm prespawn pools, and a matching container is claimed in milliseconds without you asking. Creation takes 1-5 seconds when no prespawn matches, or when you set bypass_prespawn: true.
Can I automate container creation with CI/CD?
Section titled “Can I automate container creation with CI/CD?”Yes. Create an auth token, store it as a GitHub secret, and call curl from your workflow. Container creation is an HTTP POST, so it works in any CI/CD system.
How do I see which services are running?
Section titled “How do I see which services are running?”Query with the runtime=true parameter:
GET /api/v1/containers/{id}?runtime=trueThe response shows active services with PIDs, ports, and connection status.
Troubleshooting
Section titled “Troubleshooting”Container stuck in “creating”
Section titled “Container stuck in “creating””Problem: container status stays at “creating” for longer than expected.
Typical creation time: 1-5 seconds, or sub-second with prespawn.
If it runs longer than 2 minutes:
-
Check server status:
Terminal window curl "https://api.hoody.com/api/v1/servers/{server_id}" \-H "Authorization: Bearer $HOODY_TOKEN"# Verify server is "ready", not "maintenance" -
Check server capacity:
- the server may be at capacity
- try a different
server_id
-
Wait and re-check:
- complex images take longer
- the first creation on a server takes longer, because the image is pulled
- Hoody Kit installation adds ~10-15 seconds
-
If it is stuck past 5 minutes:
- delete and recreate
- or contact support with the container_id
Update request returns 400
Section titled “Update request returns 400”Problem: the update request returns 400 Bad Request.
Common causes:
-
Invalid values:
- the name must be unique within the project
- the color must be valid HEX
- the SSH public key must be unique and cannot be reused across containers
realm_idsmust be an array of valid realm IDs
-
Immutable fields:
container_imagecannot changehoody_kitcannot changeserver_idcannot change
Creation fails immediately
Section titled “Creation fails immediately”Problem: the response shows status: "failed" right away.
Check error details:
curl "https://api.hoody.com/api/v1/containers/{failed_container_id}" \ -H "Authorization: Bearer $HOODY_TOKEN"
# Look for error message in responseCommon causes:
-
Invalid image name:
Terminal window # Wrong: "ubuntu:22.04" or "ubuntu-22.04"# Correct: "ubuntu/24.04" or "debian/13" -
Server quota exceeded:
- the server is out of CPU or RAM
- choose a different server
-
Project quota:
Terminal window # Check project limitsGET /api/v1/projects/{id}# Look at: max_containers
Delete request refused
Section titled “Delete request refused”Problem: the delete operation fails.
Two things are not prerequisites: you do not need to stop the container first, and proxy aliases never block a delete. Aliases, status logs, SSH keys, and storage shares are cascade-deleted with the container record.
If DELETE /api/v1/containers/{id} is refused, check:
-
Permissions:
- verify you own the container
- check you are using the correct auth token, with
containers.deleteand a realm that covers the container
-
The container is not your default container:
- the project’s default container cannot be deleted
-
The container is not mid-claim:
- a container still being claimed from the prespawn pool is refused until the claim settles. Retry shortly.
-
The container is not flagged for admin review:
- a quarantined container cannot be deleted. Contact support.
Service URLs unreachable after creation
Section titled “Service URLs unreachable after creation”Problem: the container was created, but its service URLs return errors.
Debug steps:
-
Verify the container is running:
Terminal window GET /api/v1/containers/{id}# Check: "status": "running" -
Wait for services to start:
- the container may be running while its services are still initializing
- wait 30-60 seconds after
status: "running"
-
Check runtime information:
Terminal window GET /api/v1/containers/{id}?runtime=true# Verify services are listed in runtime_info -
Verify
hoody_kitwas enabled:Terminal window GET /api/v1/containers/{id}# Check: "hoody_kit": true
What’s next
Section titled “What’s next”Once the container is running:
- Managing Containers → - start, stop, pause, and resume operations
- Snapshots → - back up and restore container state
- Copy & Sync → - duplicate containers across projects and servers
Access and networking:
- Hoody Proxy → - make services reachable
- Network Configuration → - proxy and VPN routing
- Firewall → - security rules
What this page covered:
- containers are created with an HTTP POST
- Hoody Kit installs the full HTTP service stack during creation
- container configuration can be updated (when stopped)
- deletion is permanent, so snapshot first
- service URLs follow a predictable pattern