Skip to content
Hoody.com

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.


This Foundation page explains container CRUD concepts and workflows. The endpoint reference lives here:

Container creation:

Container modification:

Container deletion:

Related operations:


With hoody_kit: true, a new container comes up with the full Hoody Kit HTTP service stack already installed.

POST Create a new container
/api/v1/projects/{project_id}/containers
Click "Run" to execute the 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.com
Display: https://67e89abc123def456789abcd-890abcdef12345678901cdef-display-1.node-us.containers.hoody.com
Files: https://67e89abc123def456789abcd-890abcdef12345678901cdef-files-1.node-us.containers.hoody.com
Exec: https://67e89abc123def456789abcd-890abcdef12345678901cdef-exec-1.node-us.containers.hoody.com
SQLite: https://67e89abc123def456789abcd-890abcdef12345678901cdef-sqlite-1.node-us.containers.hoody.com
+ the rest of the 19 Kit services...

The create request body accepts the following fields.

{
"name": "my-container"
}
  • 3-100 characters
  • Alphanumeric + hyphens/underscores
  • Unique within project
  • Use "rand" or omit for auto-generated name

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 LTS
  • ubuntu/22.04 - Ubuntu 22.04 LTS
  • alpine/3.19 - Alpine Linux (minimal)
  • fedora/<release> - Fedora (pick an available release from GET /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.

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.

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.

Provide your SSH public key:

{
"ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx..."
}

Generate a separate key pair per container:

Terminal window
# Generate new key pair for each container
ssh-keygen -t ed25519 -f ~/.ssh/hoody-container-1 -N ""
ssh-keygen -t ed25519 -f ~/.ssh/hoody-container-2 -N ""
# Use different public keys
container_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.

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
{
"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 reboots
  • false: 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)

  • /ramdisk is mounted by default for temporary storage in RAM. Set ramdisk: false to leave it out.
  • RAM is allocated as you write, so an empty /ramdisk consumes 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: /ramdisk is private to each container. A shared project scope exists in the data model but is not currently accepted: asking for ramdisk_scope: "project" on create or update returns 400 while a permission boundary is corrected. container is 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.

The full Kit stack, AI enabled, autostart on, and a color for the UI:

POST Create a development container
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request

Use case: a day-to-day working container that comes back automatically after a host reboot.

Scoped to a single realm, on debian/13, with the app’s environment set at creation:

POST Create a production API container
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request

Then configure:

  1. Create proxy alias for clean URL
  2. Set proxy permissions for authentication
  3. Configure firewall rules for security

An Alpine container that stays stopped until you start it:

POST Create a minimal utility container
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request

Use case: backup jobs you run occasionally, on a small image.

For AI orchestration, with the provider keys passed as environment variables:

POST Create an AI agent container
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request

The hoody-agent service is then reachable at:

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

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.

Terminal window
hoody containers update $CONTAINER_ID \
--name renamed-container \
--environment-vars NODE_ENV=staging

Metadata:

  • name - rename the container
  • color - change the UI color
  • comment - update the description

Configuration:

  • environment_vars - add, modify, or remove environment variables
  • ssh_public_key - change the SSH access key
  • realm_ids - update API realm membership (realm-restricted tokens cannot modify this)
  • autostart - enable or disable auto-start
  • ai - enable or disable AI features
  • ramdisk - enable or disable the ramdisk mount
  • ramdisk_scope - container is accepted (and is how a project-scoped row narrows back); widening to project is unavailable and returns 400. Narrowing back to container is 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 it
  • hoody_kit - service installation is permanent
  • dev_kit - the developer tooling choice is permanent
  • server_id - a container cannot move servers; use copy instead

Change environment variables

Terminal window
# Switch from staging to production
PATCH /api/v1/containers/{id}
{
"environment_vars": {
"NODE_ENV": "production",
"API_BASE_URL": "https://api.mycompany.com"
}
}

Move to a different realm

Terminal window
# Isolate to production network
PATCH /api/v1/containers/{id}
{
"realm_ids": ["64a2c4e9f3d5e2b6a8c7d8e1"]
}

A delete removes the container and all of its data permanently.

DELETE Delete a container permanently
/api/v1/containers/{container_id}
Click "Run" to execute the 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.
Terminal window
# 1. Create final snapshot
hoody snapshots create --container $CONTAINER_ID --alias "before-deletion-2025-11-09"
# 2. Stop running container
hoody containers manage $CONTAINER_ID stop
# 3. Permanent deletion
hoody containers delete $CONTAINER_ID
# 4. Cleanup (optional) - delete proxy aliases
hoody proxy delete $ALIAS_ID

Best practice: keep snapshots of production containers for disaster recovery.


Setting hoody_kit: true installs the full Hoody Kit HTTP stack.

Interact and visualize:

Data and state:

Automate and orchestrate:

Operate and monitor:

Installation time: included in container creation, with no extra wait.

See: The Hoody Kit for complete service documentation.


A container moves through these states:

creating → running → (paused) → stopped → deleting
↓ ↑
(can pause) (can restart)
StateDescriptionTransitions available
creatingContainer being provisionedrunning (automatic)
runningContainer is activestopped, paused
pausedContainer suspendedrunning (resume)
stoppedContainer is stoppedrunning (start)
failedCreation or operation faileddeleting (cleanup)
copyingBeing copied to another locationrunning (when complete)
deletingBeing permanently removed (async)(record is removed on completion)

Read the current state:

GET Get container status
/api/v1/containers/{container_id}
Click "Run" to execute the request

See: Managing Containers for state transitions.


GET List all containers for your account
/api/v1/containers
Click "Run" to execute the request
GET List containers in a specific project
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request
GET Filter and paginate containers
/api/v1/containers
Click "Run" to execute the request

Add runtime=true to get live service status:

GET Get container with runtime information
/api/v1/containers/{container_id}
Click "Run" to execute the request

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.


Create a project, pick a server, create a container, and confirm it is running:

Terminal window
# 1. Create a project
hoody projects create --alias "client-acme" --color "#e74c3c"
# 2. Check your servers
hoody servers list
# 3. Create a container
hoody containers create --project $PROJECT_ID \
--server-id $SERVER_ID \
--name "acme-frontend" \
--hoody-kit \
--dev-kit
# 4. Verify it's running
hoody 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.com

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.

Never reuse SSH keys. Generate a new ed25519 key pair for each container so Hoody’s SSH Proxy can route to it.

Terminal window
ssh-keygen -t ed25519 -f ~/.ssh/container-{name} -N ""

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.

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.

Create a snapshot before permanently deleting a container you may need again. The snapshot keeps all of its data available for recovery.

Use autostart: true for services that must come back after a host reboot, and autostart: false for development containers, which saves resources between sessions.

Unless you have a specific requirement, use debian/13 for its stability, security updates, and package availability.

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


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:

  1. Snapshot your data
  2. Create a new container with the image you want
  3. Transfer the data through storage shares or a manual copy
  4. Delete the old container

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.

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_key or inherit one from the project defaults
  • Neither: without hoody_kit and 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.

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.

Query with the runtime=true parameter:

Terminal window
GET /api/v1/containers/{id}?runtime=true

The response shows active services with PIDs, ports, and connection status.


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:

  1. 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"
  2. Check server capacity:

    • the server may be at capacity
    • try a different server_id
  3. 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
  4. If it is stuck past 5 minutes:

    • delete and recreate
    • or contact support with the container_id

Problem: the update request returns 400 Bad Request.

Common causes:

  1. 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_ids must be an array of valid realm IDs
  2. Immutable fields:

    • container_image cannot change
    • hoody_kit cannot change
    • server_id cannot change

Problem: the response shows status: "failed" right away.

Check error details:

Terminal window
curl "https://api.hoody.com/api/v1/containers/{failed_container_id}" \
-H "Authorization: Bearer $HOODY_TOKEN"
# Look for error message in response

Common causes:

  1. Invalid image name:

    Terminal window
    # Wrong: "ubuntu:22.04" or "ubuntu-22.04"
    # Correct: "ubuntu/24.04" or "debian/13"
  2. Server quota exceeded:

    • the server is out of CPU or RAM
    • choose a different server
  3. Project quota:

    Terminal window
    # Check project limits
    GET /api/v1/projects/{id}
    # Look at: max_containers

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:

  1. Permissions:

    • verify you own the container
    • check you are using the correct auth token, with containers.delete and a realm that covers the container
  2. The container is not your default container:

    • the project’s default container cannot be deleted
  3. The container is not mid-claim:

    • a container still being claimed from the prespawn pool is refused until the claim settles. Retry shortly.
  4. The container is not flagged for admin review:

    • a quarantined container cannot be deleted. Contact support.

Problem: the container was created, but its service URLs return errors.

Debug steps:

  1. Verify the container is running:

    Terminal window
    GET /api/v1/containers/{id}
    # Check: "status": "running"
  2. Wait for services to start:

    • the container may be running while its services are still initializing
    • wait 30-60 seconds after status: "running"
  3. Check runtime information:

    Terminal window
    GET /api/v1/containers/{id}?runtime=true
    # Verify services are listed in runtime_info
  4. Verify hoody_kit was enabled:

    Terminal window
    GET /api/v1/containers/{id}
    # Check: "hoody_kit": true

Once the container is running:

  1. Managing Containers → - start, stop, pause, and resume operations
  2. Snapshots → - back up and restore container state
  3. Copy & Sync → - duplicate containers across projects and servers

Access and networking:

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