Skip to content
Hoody.com

Containers transition between states via HTTP endpoints. Start them when needed, pause for efficiency, stop for maintenance, resume instantly.

After creating containers, you need to manage their lifecycle through various operational states.


Official Technical Reference:

This Foundation page explains container operation concepts and patterns. For complete endpoint documentation:

Lifecycle Operations:

Status Tracking:

Related:


Containers exist in distinct operational states:

start
stopped ────────→ running
↑ ↓
│ │ pause
│ ↓
│ paused
│ ↓
│ │ resume
│ ↓
└────── stop ── running
StateDescriptionAvailable Operations
runningContainer is active, all services availablestop, force-stop, restart, pause
stoppedContainer is halted, no processes runningstart, restart, delete
pausedContainer suspended, state frozen in RAMresume, stop, force-stop
creatingBeing provisioned (automatic)(wait for completion)
failedOperation faileddelete
copyingBeing duplicated(wait for completion)

Bring a stopped container back to life.

POST Start a stopped container
/api/v1/containers/{container_id}/start
Click "Run" to execute the request

Response:

{
"statusCode": 200,
"message": "Container operation completed successfully",
"data": {
"error": false,
"operation": "start",
"container_id": "890abcdef12345678901cdef",
"project_id": "012cdef123456789abcdef01",
"message": "Container started successfully",
"status": "running"
}
}

What happens:

  1. Container processes initialize
  2. Hoody Kit services start (if enabled)
  3. Network connectivity established
  4. Service URLs become accessible

Start typically completes in seconds — heavier containers take longer.

Containers start automatically when:

  • Just created (if not autostart: false)
  • Server boots (if autostart: true)
  • Restored from snapshot

Manual start needed when:

  • Container was previously stopped
  • After maintenance/updates
  • For cost optimization (keep containers stopped when not in use)

Gracefully shut down a running container.

POST Gracefully stop a running container
/api/v1/containers/{container_id}/stop
Click "Run" to execute the request

What happens:

  1. SIGTERM sent to all processes
  2. Processes given time to clean up
  3. If they do not exit, SIGKILL is sent (forced termination)
  4. Container status changes to stopped

Use case: Normal shutdown before updates, maintenance, or resource conservation.

Immediately terminate all processes:

POST Force stop a container immediately
/api/v1/containers/{container_id}/force-stop
Click "Run" to execute the request

What happens:

  • SIGKILL sent immediately (no graceful shutdown)
  • All processes terminated instantly
  • No cleanup time given

When to force-stop:

  • Graceful stop hangs or times out
  • Emergency situations (runaway process)
  • Container is unresponsive

Stop then start in one operation.

POST Restart a container
/api/v1/containers/{container_id}/restart
Click "Run" to execute the request

Equivalent to:

  1. Graceful stop
  2. Wait for stopped state
  3. Start

Use cases:

  • Apply configuration changes
  • Clear in-memory state
  • Recover from issues
  • Regular maintenance restarts

Restart time: one graceful stop plus one start, back to back.


Suspend container without full shutdown.

POST Pause a running container
/api/v1/containers/{container_id}/pause
Click "Run" to execute the request

What happens:

  • All container processes frozen
  • State saved in RAM
  • No CPU usage
  • Minimal memory usage
  • Service URLs return errors

Use cases:

  • Temporary suspension during resource constraints
  • Freeze state for debugging
  • Quick pause/resume cycles
POST Resume a paused container
/api/v1/containers/{container_id}/resume
Click "Run" to execute the request

What happens:

  • Processes unfrozen
  • Execution continues exactly where paused
  • All state preserved (open files, network connections, terminal sessions)
  • Service URLs become accessible again

Resume time: Nearly instant

Pause/Resume

Speed:

  • Pause: ~1 second
  • Resume: ~1-2 seconds

State:

  • All processes frozen
  • RAM state preserved
  • Network connections maintained
  • Open files preserved

Limitations:

  • Requires RAM for state
  • Already-running processes keep the environment they started with; they see updated variables only after they re-exec
  • Snapshots cannot be created while paused; resume or stop first. Snapshots capture filesystem state only, not RAM

Best for: Quick suspension

Stop/Start

Speed:

  • Stop: ~5-10 seconds
  • Start: ~5-15 seconds

State:

  • All processes terminated
  • RAM state lost
  • Network connections closed
  • Filesystem preserved

Benefits:

  • Configured services start from a clean runtime state; stop/start does not automatically make systemd services inherit Incus environment variables
  • Can create snapshots
  • Zero RAM usage
  • Clean state on restart

Best for: Maintenance, updates

Choose pause/resume for temporary suspension. Choose stop/start when you need a clean state or need configured services restarted. Environment-variable changes generally do not require a container restart: new incus exec processes see successful live syncs immediately, dedicated containers env writes affect new SSH/console logins, and systemd services do not automatically inherit Incus environment variables after stop/start.


Terminal window
# Morning: Start your dev container
hoody containers manage $DEV_ID start
# Work all day via container URLs
# https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
# https://{project}-{container}-display-1.{server}.containers.hoody.icu
# Evening: Pause (instant resume tomorrow)
hoody containers manage $DEV_ID pause

Why pause instead of stop:

  • Resume is near-instant (vs a full stop/start cycle)
  • Terminal sessions preserved
  • Open editors maintained
  • No state lost
Terminal window
# 1. Stop container gracefully
hoody containers manage $PROD_ID stop
# 2. Update configuration
hoody containers update $PROD_ID --environment-vars CONFIG_VERSION=2.0
# 3. Restart with new config
hoody containers manage $PROD_ID start

Stop containers when not in use:

// Stop non-critical containers during off-hours.
// `/api/v1/containers` returns all your containers — filter client-side by name.
const nonCritical = ['staging-api', 'test-db', 'dev-frontend'];
const { data: all } = await fetch(
'https://api.hoody.icu/api/v1/containers',
{ headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }}
).then(r => r.json());
const targets = all.containers.filter(
c => nonCritical.includes(c.name) && c.status === 'running'
);
for (const c of targets) {
await fetch(
`https://api.hoody.icu/api/v1/containers/${c.id}/stop`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }
}
);
}

Automate with cron: Schedule stops at 6 PM, starts at 8 AM.

Terminal window
# Unresponsive container? Try graceful stop first
hoody containers manage $CONTAINER_ID stop
# If that hangs or fails, force it
hoody containers manage $CONTAINER_ID force-stop
# Restart clean
hoody containers manage $CONTAINER_ID start

Track every state transition with detailed logs.

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

Response:

{
"statusCode": 200,
"message": "Status logs retrieved successfully",
"data": {
"logs": [
{
"id": "63f8b0e5c9a1b2d3e4f5a6b7",
"container_id": "890abcdef12345678901cdef",
"from_status": "stopped",
"to_status": "running",
"transition_time": "2025-11-09T14:30:00.000Z",
"duration_ms": 12450,
"triggered_by": "user_abc123",
"metadata": {
"command": "start"
}
},
{
"from_status": "running",
"to_status": "stopped",
"transition_time": "2025-11-09T10:15:00.000Z",
"duration_ms": 8320,
"triggered_by": "automation_script"
}
],
"pagination": {
"total": 47,
"page": 1,
"limit": 10,
"totalPages": 5
}
}
}

What you learn:

  • When states changed
  • How long transitions took
  • Who/what triggered the change
  • Complete audit trail

1. Debugging Issues:

Terminal window
# Check if container had recent failures
GET /api/v1/containers/{id}/status-logs?sort_order=desc&limit=20
# Look for: failed states, unexpected stops, slow starts

2. Performance Analysis:

Terminal window
# Analyze startup times
GET /api/v1/containers/{id}/status-logs
# Check duration_ms for "stopped → running" transitions
# Optimize if consistently slow

3. Audit Trail:

Terminal window
# Who stopped the production container?
GET /api/v1/containers/{prod_id}/status-logs
# Check triggered_by field for user/automation identification

Understanding how long operations take:

OperationTypical DurationWhat Happens
Start5-15 secondsBoot processes, start services
Stop5-10 secondsGraceful shutdown, cleanup
Force-Stop<1 secondImmediate kill
Restart10-25 secondsStop + Start
Pause~1 secondFreeze all processes
Resume1-2 secondsUnfreeze, continue execution

Factors affecting timing:

  • Container image complexity
  • Number of running processes
  • Allocated resources
  • Hoody Kit services (more services = slightly longer)
  • Server load

Start all project containers:

// Get all containers in project
const response = await fetch(
`https://api.hoody.icu/api/v1/projects/${projectId}/containers`,
{ headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }}
);
const containers = await response.json();
// Start all stopped containers
for (const container of containers.data.containers) {
if (container.status === 'stopped') {
await fetch(
`https://api.hoody.icu/api/v1/containers/${container.id}/start`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }
}
);
console.log(`Started: ${container.name}`);
}
}

Stop containers based on criteria:

// Stop all paused containers (free up RAM).
// The list endpoint takes no status filter — filter client-side on the returned array.
const { data } = await fetch(
'https://api.hoody.icu/api/v1/containers',
{ headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }}
).then(r => r.json());
const paused = data.containers.filter(c => c.status === 'paused');
for (const container of paused) {
await fetch(
`https://api.hoody.icu/api/v1/containers/${container.id}/stop`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }
}
);
}

Restart multiple containers simultaneously:

const containerIds = [
'890abcdef12345678901cdef',
'901bcdef12345678901cdefa',
'012cdef123456789abcdef01'
];
// Restart all in parallel
await Promise.all(
containerIds.map(id =>
fetch(`https://api.hoody.icu/api/v1/containers/${id}/restart`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}` }
})
)
);
console.log('All containers restarted');

Control whether containers start automatically on server boot.

Terminal window
# Enable autostart
hoody containers update $CONTAINER_ID --autostart

Now this container auto-starts when:

  • Server reboots
  • Server maintenance completes
  • After power failure recovery

Enable autostart for:

  • Production services (must be always available)
  • Critical infrastructure (databases, APIs)
  • Monitoring containers (must run continuously)
  • Automation containers (CI/CD, cron jobs)

Disable autostart for:

  • Development environments (start manually when needed)
  • Testing containers (ephemeral)
  • Resource-intensive containers (start on-demand)
  • Temporary/experimental containers

Terminal window
# 1. Snapshot current state (safety)
hoody snapshots create --container $CONTAINER_ID --alias "pre-deploy-2025-11-09"
# 2. Access terminal to deploy, then deploy code
# 3. Restart container for clean state
hoody containers manage $CONTAINER_ID restart
# 4. Verify services are running
hoody containers get $CONTAINER_ID --runtime true

If deployment fails: Restore snapshot to roll back.

// Automated maintenance script
async function performMaintenance(containerId) {
const token = process.env.HOODY_TOKEN;
const headers = { 'Authorization': `Bearer ${token}` };
// 1. Stop container
await fetch(
`https://api.hoody.icu/api/v1/containers/${containerId}/stop`,
{ method: 'POST', headers }
);
// 2. Wait for stopped
await waitForStatus(containerId, 'stopped');
// 3. Update resources
await fetch(
`https://api.hoody.icu/api/v1/containers/${containerId}`,
{
method: 'PATCH',
headers: {
...headers,
'Content-Type': 'application/json'
},
body: JSON.stringify({
environment_vars: {
"UPDATED": "true"
}
})
}
);
// 4. Restart
await fetch(
`https://api.hoody.icu/api/v1/containers/${containerId}/start`,
{ method: 'POST', headers }
);
// 5. Verify running
const status = await fetch(
`https://api.hoody.icu/api/v1/containers/${containerId}`,
{ headers }
).then(r => r.json());
return status.data.status === 'running';
}
// Run at 2 AM via cron
performMaintenance('890abcdef12345678901cdef');

Pause containers during low-usage periods:

Terminal window
# List containers (filter by status client-side)
hoody containers list
# Pause each non-critical container
hoody containers manage $CONTAINER_ID pause
# Morning: Resume all paused
hoody containers list
hoody containers manage $CONTAINER_ID resume

Result: Paused containers consume no CPU on your server; their frozen state simply stays in RAM until you resume.

Terminal window
# 1. Start green container
hoody containers manage $GREEN_ID start
# 2. Verify green is healthy
hoody containers get $GREEN_ID --runtime true
# 3. Re-point alias to green (delete + recreate — container_id is immutable)
hoody proxy delete $ALIAS_ID
hoody proxy create --container-id $GREEN_ID \
--alias "prod" --program "http" --port 3000 --target-path "/"
# 4. Monitor green in production
# 5. After verification, stop blue
hoody containers manage $BLUE_ID stop

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

Key fields:

  • status: Current state (running, stopped, paused)
  • updated_at: Last modification time
GET Get container with live service data
/api/v1/containers/{container_id}
Click "Run" to execute the request

Shows:

  • Active terminal sessions
  • Display connections
  • Running services (PIDs, ports)
  • Network services
  • Memory/CPU usage
GET Get status history
/api/v1/containers/{container_id}/status-logs
Click "Run" to execute the request

Analyze:

  • Frequency of restarts (stability indicator)
  • Downtime duration
  • Who triggered changes
  • Operation timing patterns

1. Always Snapshot Before Risky Operations

Section titled “1. Always Snapshot Before Risky Operations”
Terminal window
# Before forcing stop or major changes
POST /api/v1/containers/{id}/snapshots
{"alias": "before-maintenance"}
Terminal window
# Preferred (gives processes time to cleanup)
POST /api/v1/containers/{id}/stop
# Last resort only (can corrupt data)
POST /api/v1/containers/{id}/force-stop
Terminal window
# Don't assume success - verify
async function stopContainer(id) {
await fetch(`https://api.hoody.icu/api/v1/containers/${id}/stop`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` }
});
// Poll until stopped
let attempts = 0;
while (attempts < 30) {
const status = await fetch(
`https://api.hoody.icu/api/v1/containers/${id}`,
{ headers: { 'Authorization': `Bearer ${token}` }}
).then(r => r.json());
if (status.data.status === 'stopped') {
return true;
}
await new Promise(r => setTimeout(r, 1000));
attempts++;
}
throw new Error('Container did not stop in time');
}
Terminal window
# Add context to operations via comments
# (Though API doesn't accept comment on operations, document externally)
# In your automation scripts:
// Stopping container for scheduled backup - see RUNBOOK.md section 4.2
await stopContainer(prodId);

5. Coordinate with Team for Shared Containers

Section titled “5. Coordinate with Team for Shared Containers”

Before stopping shared containers:

  • Notify team via chat/email
  • Check who’s connected: GET /api/v1/containers/{id}?runtime=true
  • Look at runtime_info.displays.connected_clients and runtime_info.terminals
  • Schedule during off-hours when possible

See: Multiplayer by Default for collaboration context.


Can I start multiple containers simultaneously?

Section titled “Can I start multiple containers simultaneously?”

Yes! Operations are independent HTTP requests. Start 100 containers in parallel:

await Promise.all(
containerIds.map(id =>
fetch(`https://api.hoody.icu/api/v1/containers/${id}/start`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` }
})
)
);

What happens to service URLs when container is stopped?

Section titled “What happens to service URLs when container is stopped?”

All service URLs return connection errors or 503 Service Unavailable. The URLs exist but services aren’t running. On restart, same URLs become accessible again.

Can I pause a container, then update its configuration?

Section titled “Can I pause a container, then update its configuration?”

Yes for most fields — PATCH /api/v1/containers/{id} (name, autostart, environment variables, SSH key) works in any state, including paused. Notes: environment-variable changes do not generally require a container restart — after a successful live sync, new incus exec processes see updated values immediately, and the dedicated containers env endpoints also rewrite /etc/environment so new SSH/console logins see them, while already-running processes must re-exec — and narrowing ramdisk_scope is rejected while the container is running. Snapshots, however, can’t be created while paused.

Does autostart work across server reboots?

Section titled “Does autostart work across server reboots?”

Yes. When your server restarts (maintenance, updates, power cycle), all containers with autostart: true start automatically once the server is back online.

Can I be notified when operations complete?

Section titled “Can I be notified when operations complete?”

Not directly via the API. Poll container status or status-logs endpoints. Or use hoody-notifications service within containers to send alerts when operations complete.

What happens if I stop a container while someone is using it?

Section titled “What happens if I stop a container while someone is using it?”

All connections terminate immediately. Active terminal sessions close. Display disconnects. File operations fail. Always coordinate with users before stopping shared containers. Consider multiplayer implications.

Do paused containers count toward resource quotas?

Section titled “Do paused containers count toward resource quotas?”

A paused container keeps its frozen state in the server’s RAM and its disk usage unchanged, and it still counts toward any container-count limit. Only its CPU goes quiet.

Can containers auto-restart if they crash?

Section titled “Can containers auto-restart if they crash?”

Not automatically via the API. Implement monitoring that checks status and restarts if needed. Or use systemd inside containers for process-level auto-restart. Or configure autostart: true for server boot recovery.

What’s the difference between restart and stop+start?

Section titled “What’s the difference between restart and stop+start?”

Functionally identical. restart is convenience endpoint that does stop then start in one call. Same total time, same result, less API calls.


Problem: Start operation fails or container stuck in “creating”

Solutions:

  1. Check status logs:

    Terminal window
    GET /api/v1/containers/{id}/status-logs?limit=5&sort_order=desc
    # Look for error messages in metadata
  2. Verify server is available:

    Terminal window
    GET /api/v1/servers/{server_id}
    # Check: status should be "ready", not "maintenance"
  3. Check resource availability:

    • Server may be at capacity
    • Try reducing allocated resources
    • Or move to different server via copy
  4. Look for image issues:

    Terminal window
    GET /api/v1/containers/{id}
    # Check container_image is valid

Problem: Stop operation doesn’t complete

Cause: Container processes not responding to SIGTERM

Solutions:

  1. Retry the graceful stop:

    Terminal window
    POST /api/v1/containers/{id}/stop
  2. Force stop if necessary:

    Terminal window
    POST /api/v1/containers/{id}/force-stop
  3. Check what’s running:

    Terminal window
    # SSH or terminal into container
    ps aux
    # Identify stuck processes

Problem: Resume operation returns error

Causes & Solutions:

  1. Server rebooted during pause:

    • Paused state is lost on server reboot
    • Solution: Start container instead of resume
  2. RAM pressure:

    • Server may have deallocated paused container memory
    • Solution: Start fresh (state lost)

Problem: Valid operation returns 400 error

Check operation validity:

Current StateValid Operations
runningstop, force-stop, restart, pause
stoppedstart, restart, delete
pausedresume, stop, force-stop
creating(none - wait for completion)
faileddelete

The API’s own gate is coarse: the container must be in running, stopped, or paused to be managed at all. Finer refusals (starting an already-running container, for instance) come from the host.

Common mistakes:

  • Starting an already running container
  • Stopping an already stopped container
  • Pausing a stopped container
  • Resuming a running container

Solution: Check current status first:

Terminal window
GET /api/v1/containers/{id}
# Verify status before operation

Service URLs Still Not Working After Start

Section titled “Service URLs Still Not Working After Start”

Problem: Container status shows “running” but service URLs fail

Debug steps:

  1. Wait for services to initialize:

    • Status changes to “running” before all services are ready
    • Wait 30-60 seconds after start
  2. Check runtime info:

    Terminal window
    GET /api/v1/containers/{id}?runtime=true
    # Verify services appear in runtime_info.services
    # Check for "active" status
  3. Verify hoody_kit is enabled:

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

    Terminal window
    # SSH or terminal into container
    systemctl status hoody-terminal
    systemctl status hoody-display
    # etc.

Problem: Container restarts unexpectedly

Check causes:

  1. Autostart enabled + server rebooted:

    Terminal window
    GET /api/v1/containers/{id}
    # Check: "autostart": true
  2. Check status logs for pattern:

    Terminal window
    GET /api/v1/containers/{id}/status-logs?limit=20
    # Look for frequent "stopped → running" transitions
    # Check triggered_by field
  3. Process-level crashes:

    • Container OS auto-restarts
    • Check logs inside container
    • Or configure alerting via hoody-notifications

Master container operations:

  1. Snapshots → - Capture state before operations, restore if needed
  2. Copy & Sync → - Duplicate containers for redundancy
  3. Images → - Choose optimal OS for your workload

Operational topics:

Understanding gained:

  • Containers transition via HTTP operations
  • Stop/start for a clean runtime state or to restart configured services, not as a general environment-variable propagation mechanism
  • Pause/resume for quick suspension
  • Force-stop only in emergencies
  • Status logs track all transitions
  • Autostart controls boot behavior

Start containers when needed.
Pause for quick suspension.
Stop for maintenance.
Resume instantly.
All via HTTP endpoints. All in seconds.

Test container operations directly from your browser:

Manage container lifecycle - set operation to: start, stop, force-stop, restart, pause, or resume

Path Parameters

Authentication

Not Authenticated

Use the authentication widget in the header to login or set an API token

Authentication: Authorization: Bearer header (auto-attached for trusted domains)

Custom Headers

Request Body (JSON)