try.directtry.direct

How to Add a Missing Service to a Stacker Deployment

What Happens When a Service Is Missing?

You've created a project on the Stacker dashboard, deployed it to a cloud server, and everything looks good — except the main application container isn't there. Only the database is running. This usually happens when the project was set up without a proper application template, leaving you with a half-empty stack.

In this guide, we'll walk through a real scenario: an Umami analytics project that was deployed with only PostgreSQL and no Umami container. You'll learn how to inspect the deployment, add the missing app via the Stacker API, deploy it, and verify everything works — all from the command line.

Quick Answer

Use stacker agent status to inspect your deployment, then register the missing app via the Stacker API (POST /project/{id}/apps) and deploy it with stacker agent deploy-app.

Step 1: Inspect the Current Deployment

Start by checking what's actually running on your deployment agent. Use the stacker agent status command with your deployment hash:

stacker agent status --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926

This shows you the running containers, their images, and their states:

────────────────────────────────────────────────────────────────────────────────────────────
Agent:     ● online
Heartbeat: 2026-07-01T18:31:56.563318Z
────────────────────────────────────────────────────────────────────────────────────────────
APP                NAME                   IMAGE                          ENABLED
postgres           postgres               postgres:latest                yes
────────────────────────────────────────────────────────────────────────────────────────────
CONTAINER                STATE        PORTS                  IMAGE
project-postgres-1       ⟳ restarting 5432                   postgres:latest
statuspanel_agent        ▶ running    -                      registry-intl.eu-central-1.…
statuspanel              ▶ running    -                      registry-intl.eu-central-1.…
────────────────────────────────────────────────────────────────────────────────────────────

Notice only postgres appears in the APP list. The Umami analytics container is completely absent.

Step 2: Get Detailed App Configuration

For more detail, use the --json flag. This reveals the exact environment variables, port mappings, volumes, and network configuration of the running apps:

stacker agent status --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926 --json

Look for the apps array in the JSON output. For our postgres app:

{
  "apps": [
    {
      "code": "postgres",
      "image": "postgres:latest",
      "environment": {
        "POSTGRES_DB": "umami",
        "POSTGRES_USER": "umami",
        "POSTGRES_PASSWORD": "umami"
      },
      "ports": [{"host_port": 5432, "container_port": 5432}],
      "networks": ["default_network"],
      ...
    }
  ]
}

This tells us the database credentials (umami for user, password, and database name) — exactly what we need to configure the Umami container's DATABASE_URL.

Step 3: Check If a Template Exists

See what templates are available in the marketplace:

stacker templates | grep -i umami
stacker catalog | grep -i umami

If nothing shows up, there's no Umami template you can simply install. You'll need to register the app manually.

Step 4: Create the App via the Stacker API

Apps are managed through the Stacker REST API. The endpoint is a POST to /project/{project_id}/apps — and it's an upsert, so you can safely run it multiple times.

First, find your project ID and get your auth token from ~/.config/stacker/credentials.json:

# List projects to find your project ID
stacker projects | grep umami
# Output: 243    umami   2026-06-30T08:49:12...

# Your access token is stored here
cat ~/.config/stacker/credentials.json

Now create the Umami app:

TOKEN="*******token*******"

curl -s -X POST "https://try.direct/stacker/project/243/apps" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "umami",
    "name": "Umami Analytics",
    "image": "ghcr.io/umami-software/umami:postgresql-latest",
    "environment": {
      "DATABASE_URL": "postgresql://umami:umami@postgres:5432/umami",
      "HASH_SALT": "3b8e9f1a7c2d5e4f6a0b9c8d7e6f5a4b3c2d1e0f"
    },
    "ports": [
      {"host_port": 3000, "container_port": 3000, "protocol": "tcp"}
    ],
    "depends_on": ["postgres"],
    "restart_policy": "always",
    "enabled": true,
    "deploy_order": 2
  }'

Successful response:

{
  "message": "OK",
  "item": {
    "id": 28,
    "project_id": 243,
    "code": "umami",
    "name": "Umami Analytics",
    "image": "ghcr.io/umami-software/umami:postgresql-latest",
    "environment": {
      "DATABASE_URL": "postgresql://umami:umami@postgres:5432/umami",
      "HASH_SALT": "3b8e9f1a7c2d5e4f6a0b9c8d7e6f5a4b3c2d1e0f"
    },
    "ports": [{"container_port": 3000, "host_port": 3000, "protocol": "tcp"}],
    "restart_policy": "always",
    "enabled": true,
    "deploy_order": 2,
    "created_at": "2026-07-01T18:39:11.469030Z",
    "updated_at": "2026-07-01T18:39:11.469030Z",
    "config_version": 1
  }
}

Step 5: Plan and Deploy the App

First, preview what deploy-app will do:

stacker agent deploy-app umami \
  --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926 \
  --plan

Expected plan output:

{
  "hasChanges": true,
  "actions": [
    {
      "kind": "redeploy_app",
      "target": "app",
      "appCode": "umami",
      "reason": "explicit deploy-app plan targets a single app"
    },
    {
      "kind": "sync_app_config",
      "target": "app",
      "appCode": "umami",
      "reason": "app config version is ahead of the synced Vault/runtime version"
    }
  ]
}

Apply the plan:

stacker agent deploy-app umami \
  --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926

Successful deployment output:

Command:  cmd_513774de-e91e-4357-b886-8565f3ce3ef2
Type:     deploy_app
Status:   ✓ completed

{
  "app_code": "umami",
  "container_state": "running",
  "deployed_at": "2026-07-01T18:40:36Z",
  "status": "deployed"
}

Step 6: Verify Everything Is Running

Check the status again:

stacker agent status --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926
────────────────────────────────────────────────────────────────────────────────────────────
Agent:     ● online
Heartbeat: 2026-07-01T18:40:36.661528Z
────────────────────────────────────────────────────────────────────────────────────────────
APP                NAME                   IMAGE                          ENABLED
postgres           postgres               postgres:latest                yes
umami              Umami Analytics        ghcr.io/umami-software/umam…   yes
────────────────────────────────────────────────────────────────────────────────────────────
CONTAINER                STATE        PORTS                  IMAGE
umami                    ▶ running    -                      ghcr.io/umami-software/umam…
postgres                 ▶ running    -                      postgres:latest
statuspanel_agent        ▶ running    -                      registry-intl.eu-central-1.…
statuspanel              ▶ running    -                      registry-intl.eu-central-1.…
────────────────────────────────────────────────────────────────────────────────────────────

Both postgres and umami are now listed as apps and running. You can inspect the logs to confirm the application started correctly:

stacker agent logs umami \
  --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926

Look for key log lines:

✓ DATABASE_URL is defined.
✓ Database connection successful.
✓ Database is up to date.

> umami@3.2.0 start-server
> node server.js

▲ Next.js 16.2.6
- Local:         http://localhost:3000
- Network:       http://0.0.0.0:3000
✓ Ready in 0ms

Step 7: Configure a Domain

Set a public domain for the new app via the API:

curl -s -X PUT "https://try.direct/stacker/project/243/apps/umami/domain" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain": "umami.try.direct", "ssl_enabled": true}'

Then configure the reverse proxy on the agent:

stacker agent configure-proxy umami \
  --domain umami.try.direct \
  --port 3000 \
  --ssl \
  --deployment deployment_c837325f-34b3-4d1f-b4a0-e55a49cf8926 \
  --force

Troubleshooting Common Issues

Issue 1: "service refers to undefined network"

If the existing app has networks configured but the Docker Compose file lacks the network definition, update the existing app to remove the network reference:

curl -s -X POST "https://try.direct/stacker/project/243/apps" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "code": "postgres", "image": "postgres:latest", ... }'

Omitting the networks field lets Docker Compose use its default network, which all services can share.

Issue 2: "service refers to undefined volume"

Named volumes must be defined at the top level of the Compose file. If the deploy-app command complains about undefined volumes, remove the volumes configuration from the app definition (the data persists on disk via the existing container).

Issue 3: Vault is unavailable

Some operations (like configure-proxy) require HashiCorp Vault for credential resolution. If Vault is unavailable, the proxy configuration step will fail. In this case, the app will still run and be accessible on its internal port — you can configure DNS and SSL manually on the server.

Key Commands Reference

CommandPurpose
stacker agent status --deployment <hash> Inspect running containers and apps
stacker agent status --deployment <hash> --json Detailed JSON view with config
stacker projects | grep <name> Find your project ID
POST /project/{id}/appsRegister a new app (via API)
stacker agent deploy-app <code> --deployment <hash> Deploy the registered app to the agent
stacker agent logs <code> --deployment <hash> View container logs
stacker agent configure-proxy <code> --domain ... --port ... Set up reverse proxy and SSL

How It All Fits Together

The Stacker platform separates app registration from app deployment (done through the CLI, which sends commands to the remote agent). This two-step process gives you full control:

  • API — Define the Docker image, environment variables, port mappings, volumes, restart policy, and deployment order
  • CLI — Push the configuration to the remote server, pull the image, create the container, and wire it into the existing Docker Compose project

This approach works for any containerized application, not just Umami. Whether you're adding Redis, a custom API, or a background worker, the workflow is identical.

The next time you find a project deployed without its main application container, you now have the exact steps to fix it — inspect, register, deploy, verify.

Try It Yourself

Deploy this stack or browse pre-built templates in the marketplace. Your first deployment is always free.