Self-hosting
Guide

Deploy Agent Barn to Kubernetes

Deploy Agent Barn, its supporting services, agent runtimes, and monitoring stack to a Kubernetes cluster using Helmfile.

For
Platform administrators, DevOps engineers, and Kubernetes operators
On this page
  1. What you will deploy
  2. Before you begin
  3. 1. Verify the cluster
  4. 2. Get the deployment files
  5. 3. Configure the deployment
  6. 4. Configure DNS and TLS
  7. 5. Deploy Agent Barn
  8. 6. Verify the deployment
  9. 7. Complete the first-time setup
  10. Upgrade the deployment
  11. Troubleshooting
  12. Deployment constraints

Deploy Agent Barn and its supporting services to an existing Kubernetes cluster using the Helm charts and Helmfile configuration included with the project.

This guide uses the production namespace agent-farm. The repository and product are named Agent Barn, but the Kubernetes namespaces deliberately retain the earlier agent-farm name.

What you will deploy

By the end of this guide, you will have:

  • The Agent Barn API, Ingest API, background worker, and web application
  • PostgreSQL databases for Agent Barn, LiteLLM, and Firecrawl
  • Redis for background processing
  • LiteLLM connected to OpenRouter
  • A self-hosted Firecrawl service
  • Prometheus, Grafana, Alertmanager, and Agent Barn dashboards
  • TLS ingress for the web application, API, and Grafana
  • A Kubernetes namespace in which Agent Barn can create agent workloads
  • Persistent storage for application databases, monitoring, and agents

Starting an Agent later creates a dedicated Deployment, Service, Secret, ConfigMap, PVC, and related runtime configuration inside the same namespace.

Before you begin

Kubernetes cluster

You need an existing Kubernetes cluster with:

  • A working kubectl context
  • A default StorageClass, or the name of a StorageClass you can select
  • Support for dynamically provisioned ReadWriteOnce volumes
  • A Traefik ingress controller with the traefik IngressClass
  • cert-manager
  • A cert-manager ClusterIssuer named letsencrypt-http01
  • DNS control for the web application, API, and Grafana hostnames
  • Enough capacity for the platform services and the agents you plan to run
WorkloadDefault storage
Agent Barn PostgreSQL5 GiB
LiteLLM PostgreSQL2 GiB
Firecrawl PostgreSQL2 GiB
Prometheus10 GiB
Each running Agent1 GiB

Plan additional capacity for database growth, monitoring retention, backups, and simultaneous agent workloads.

Command-line tools

Install these tools on the machine from which you will deploy:

Confirm that they are available:

Shell
kubectl version --client
helm version
helmfile --version
helm plugin list

If diff is not listed as a Helm plugin, install it:

Shell
helm plugin install https://github.com/databus23/helm-diff

External accounts and credentials

You will need:

  • An OpenRouter API key
  • Credentials for the container registry holding the Agent Barn images
  • A Slack incoming-webhook URL for deployment alerts
  • Three DNS hostnames pointing to your ingress endpoint

The following integrations are optional:

  • Cloudflare Email Sending for invitations, password resets, and notifications
  • A Google OAuth web client for Google Workspace authentication

Kubernetes permissions

The deployment identity must be able to manage the Helm releases and their resources in agent-farm.

The default production bootstrap also applies:

  • The agent-farm Namespace
  • The agent-farm-user ServiceAccount
  • A Role and RoleBinding used by deployment and monitoring jobs

The kubeconfig mounted into the Agent Barn API must allow it to manage agent Deployments, Services, PVCs, Secrets, ConfigMaps, and Pods in the target namespace. It also needs access to pod logs, exec, and port-forward operations used by Agent health and log features.

Verify the cluster

Confirm that kubectl is connected to the intended cluster:

Shell
kubectl config current-context
kubectl cluster-info
kubectl get nodes

Check the required cluster services:

Shell
kubectl get ingressclass traefik
kubectl get clusterissuer letsencrypt-http01
kubectl get storageclass

Check whether your deployment identity can create and manage resources:

Shell
kubectl auth can-i create namespaces
kubectl auth can-i create deployments --namespace agent-farm
kubectl auth can-i create services --namespace agent-farm
kubectl auth can-i create secrets --namespace agent-farm
kubectl auth can-i create persistentvolumeclaims --namespace agent-farm
kubectl auth can-i create ingresses --namespace agent-farm

If your identity cannot create namespaces, ask the cluster administrator to create agent-farm and provision the required namespace-scoped deployment identity before continuing.

Get the deployment files

Use a release bundle

The recommended deployment artifact is the Agent Barn release bundle. It contains:

  • The Helm charts
  • helmfile.yaml.gotmpl
  • Kubernetes bootstrap manifests
  • deploy.sh
  • A release-specific .env.deploy with compatible image tags

Download the bundle for the release you want to deploy, then extract it:

Shell
tar -xzf agent-barn-deploy-RELEASE_TAG.tar.gz
cd agent-barn-deploy

Replace RELEASE_TAG with the release you downloaded.

Deploy from the source repository

You can also use the deployment files directly from the public repository:

Shell
git clone https://github.com/aai-labs/agent-barn.git
cd agent-barn
git checkout RELEASE_TAG
cp .env.deploy.spec .env.deploy

Use a released tag or a commit whose API, UI, Hermes, and OpenClaw image tags are available in your registry.

Configure the deployment

Open .env.deploy in a text editor and replace every required blank value.

The file is sourced as a shell environment file. Use plain KEY=value entries and avoid spaces around the equals sign.

Cluster and namespace

VariableRequirementDescription
KUBECONFIGRequiredAbsolute path to the kubeconfig used by kubectl, Helm, and Helmfile
NAMESPACERequiredTarget namespace; use agent-farm for the production deployment
POD_KUBECONFIG_B64OptionalBase64 kubeconfig used by the API; when omitted, deploy.sh derives it from KUBECONFIG
STORAGE_CLASSOptionalStorageClass for databases, Prometheus, and Agent PVCs; leave empty to use the cluster default

Use an absolute kubeconfig path:

Environment
KUBECONFIG=/home/your-user/.kube/agent-barn-production.yaml
NAMESPACE=agent-farm
STORAGE_CLASS=REPLACE_WITH_STORAGE_CLASS

Container registry

VariableRequirementDescription
REGISTRY_PREFIXRequiredRegistry path prepended to all Agent Barn image repositories
REGISTRY_SERVERRequiredRegistry hostname used for authentication
REGISTRY_USERNAMERequiredRegistry username
REGISTRY_PASSWORDRequiredRegistry password or access token
API_IMAGE_REPOSITORYRequiredAPI image repository
UI_IMAGE_REPOSITORYRequiredUI image repository
HERMES_IMAGE_REPOSITORYRequiredHermes runtime image repository
OPENCLAW_IMAGE_REPOSITORYRequiredOpenClaw runtime image repository
API_IMAGE_TAGRequiredReleased API image tag
UI_IMAGE_TAGRequiredReleased UI image tag
HERMES_IMAGE_TAGRequiredCompatible Hermes image tag
OPENCLAW_IMAGE_TAGRequiredCompatible OpenClaw image tag

If you downloaded a release bundle, the registry paths and image tags should already be populated. Add the credentials supplied for that registry without changing the pinned versions.

A GitHub token is not required to read the public agent-barn or aai-cli repositories. Kubernetes only needs credentials for the registry from which it pulls the deployment images.

Database configuration

Agent Barn deploys three independent PostgreSQL instances:

VariableRequirementDefault user or database
POSTGRES_APP_USERRequiredagentfarm
POSTGRES_APP_PASSWORDRequiredGenerate a strong password
POSTGRES_APP_DBRequiredagentfarm
POSTGRES_LITELLM_USERRequiredlitellm
POSTGRES_LITELLM_PASSWORDRequiredGenerate a different strong password
POSTGRES_LITELLM_DBRequiredlitellm
POSTGRES_FIRECRAWL_USERRequiredfirecrawl
POSTGRES_FIRECRAWL_PASSWORDRequiredGenerate a different strong password
POSTGRES_FIRECRAWL_DBRequiredfirecrawl

Generate independent passwords:

Shell
openssl rand -hex 24
openssl rand -hex 24
openssl rand -hex 24

Store these values in your secret manager before deploying.

LiteLLM and OpenRouter

VariableRequirementDescription
LITELLM_MASTER_KEYRequiredStable LiteLLM administrative key beginning with sk-
OPENROUTER_API_KEYRequiredAPI key issued by OpenRouter
AGENT_DEFAULT_MODELOptionalDefault in litellm/openrouter/<model> format
AGENT_MODEL_ALLOWLISTOptionalComma-separated model patterns

Generate a LiteLLM master key:

Shell
echo "sk-$(openssl rand -hex 24)"

Keep this key stable. LiteLLM uses it when managing the virtual keys assigned to Agents.

Agent Barn application secrets

VariableRequirementDescription
SECRET_SIGNING_KEYRequiredSigns Agent Barn authentication tokens
AGENT_TOKEN_ENCRYPTION_KEYRequiredFernet-compatible key used to encrypt stored credentials
PLATFORM_ADMIN_CREDENTIALSRequiredInitial platform administrator in email:password format
ENVIRONMENTRequiredDeployment name stamped into the application and alerts
FIRECRAWL_API_KEYRequiredShared key protecting the internal Firecrawl service

Generate the signing key:

Shell
openssl rand -hex 32

Generate the Fernet-compatible encryption key:

Shell
openssl rand -base64 32 | tr '+/' '-_' | tr -d '\n'

Generate the Firecrawl key:

Shell
openssl rand -hex 24

Configure the administrator and environment:

Environment
PLATFORM_ADMIN_CREDENTIALS=[email protected]:REPLACE_WITH_STRONG_PASSWORD
ENVIRONMENT=production

The administrator password must contain at least eight characters, including an uppercase letter, a lowercase letter, and a digit.

Public hostnames

VariableRequirementExample
UI_HOSTRequiredagentbarn.example.com
API_HOSTRequiredapi.agentbarn.example.com
WEB_APP_URLRequiredhttps://agentbarn.example.com
GRAFANA_HOSTRequiredgrafana.agentbarn.example.com

Configure hostnames without URL schemes in the *_HOST values:

Environment
UI_HOST=agentbarn.example.com
API_HOST=api.agentbarn.example.com
WEB_APP_URL=https://agentbarn.example.com
GRAFANA_HOST=grafana.agentbarn.example.com

Monitoring

The current Helmfile requires:

VariableRequirementDescription
SLACK_ALERTS_WEBHOOK_URLRequiredSlack incoming webhook used by Alertmanager
GRAFANA_ADMIN_PASSWORDRequiredInitial Grafana administrator password
GRAFANA_HOSTRequiredPublic Grafana hostname

Add these entries to .env.deploy if they are not already present:

Environment
SLACK_ALERTS_WEBHOOK_URL=REPLACE_WITH_SLACK_WEBHOOK
GRAFANA_ADMIN_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
GRAFANA_HOST=grafana.agentbarn.example.com

Optional email delivery

Leave all three values empty to disable transactional email:

Environment
CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_API_TOKEN=
SENDER_EMAIL=

To enable it:

  • Create or select a Cloudflare Email Sending account.
  • Verify the sending domain.
  • Give the API token the Email Sending: Edit permission.
  • Set SENDER_EMAIL to an address on the verified domain.

Use an environment-specific mail. subdomain, such as:

Environment
SENDER_EMAIL=[email protected]

All three values must be configured for delivery to be enabled.

Optional Google Workspace authentication

Leave these values empty to disable Google OAuth:

Environment
GOOGLE_CLOUD_CLIENT_ID=
GOOGLE_CLOUD_CLIENT_SECRET=

To enable it, create a Google OAuth 2.0 Web application client and register this redirect URI:

Text
https://agentbarn.example.com/api/v1/integrations/google/callback

Then set the client ID and client secret in .env.deploy.

Configure DNS and TLS

Point the following DNS records to the public address of your Traefik ingress controller:

  1. UI_HOST
  2. API_HOST
  3. GRAFANA_HOST

Find the ingress address using the command appropriate for your cluster. For example:

Shell
kubectl get services --all-namespaces
kubectl get ingressclass traefik

Confirm that DNS resolves before deploying:

Shell
dig +short agentbarn.example.com
dig +short api.agentbarn.example.com
dig +short grafana.agentbarn.example.com

Confirm that the expected ClusterIssuer is ready:

Shell
kubectl get clusterissuer letsencrypt-http01
kubectl describe clusterissuer letsencrypt-http01

Deploy Agent Barn

Build the pinned monitoring chart dependencies:

Shell
helm dependency build helm/monitoring

Review the active Kubernetes context one final time:

Shell
kubectl config current-context

Deploy the stack:

Shell
./deploy.sh

The script:

  1. Loads values from .env.deploy.
  2. Verifies that helmfile and kubectl are available.
  3. Derives the API pod kubeconfig when POD_KUBECONFIG_B64 is not supplied.
  4. Applies the agent-farm namespace and bootstrap RBAC manifest.
  5. Runs helmfile sync --wait.
  6. Applies database migrations through an API chart hook.
  7. Generates the LiteLLM API key used by Agent Barn.
  8. Waits for the Helm releases to become ready.

The releases are installed in dependency order:

ReleasePurpose
postgres-appAgent Barn application database
postgres-litellmLiteLLM database
postgres-firecrawlFirecrawl database
redisBackground task transport
litellmModel proxy and per-Agent virtual keys
firecrawlSelf-hosted web retrieval
agentbarn-apiProduct API, Ingest API, worker, migrations, and reconciliation
agentbarn-uiAgent Barn web application
monitoringPrometheus, Grafana, Alertmanager, and dashboards

Verify the deployment

  • Helm releases are installed.
  • Workloads become ready.
  • Persistent volume claims are bound.
  • Ingress and certificate resources are ready.
  • The public API and web application respond.

Check the Helm releases:

Shell
helm list --namespace agent-farm

Check the workloads:

Shell
kubectl get deployments,statefulsets,pods --namespace agent-farm

Check persistent volumes:

Shell
kubectl get pvc --namespace agent-farm

Check ingress and certificate resources:

Shell
kubectl get ingress --namespace agent-farm
kubectl get certificate --namespace agent-farm
kubectl get certificaterequest --namespace agent-farm

Expected: All long-running pods eventually report Running, and their ready-container counts are complete.

Verify the public API:

Shell
curl --fail https://api.agentbarn.example.com/api/v1/health

A healthy response resembles:

JSON
{
  "status": "ok",
  "db": "connected"
}

Verify the web application:

Shell
curl --head https://agentbarn.example.com

Open these URLs in a browser:

Text
https://agentbarn.example.com
https://grafana.agentbarn.example.com

If a pod is not ready, inspect it before retrying the deployment:

Shell
kubectl describe pod POD_NAME --namespace agent-farm
kubectl logs POD_NAME --namespace agent-farm

Complete the first-time setup

Sign in at WEB_APP_URL using the address and password from PLATFORM_ADMIN_CREDENTIALS.

A fresh Agent Barn database contains the platform administrator but no Organization. Complete the initial setup in this order:

  1. Sign in as the platform administrator.
  2. Create an Organization.
  3. Add or invite Organization members.
  4. Configure shared credentials and integrations.
  5. Hire an Agent from a predefined template.
  6. Configure its chat platform and model.
  7. Start the Agent.

After starting the first Agent, verify that Kubernetes created its resources:

Shell
kubectl get deployments,pods,services,pvc \
  --namespace agent-farm \
  --selector agentbarn.io/component=agent

Each Agent receives a 1 GiB PVC by default. Its generated resources remain isolated by Agent identity within the agent-farm namespace.

Deployment complete

Agent Barn and its supporting services are running, and the cluster is ready to host Agent workloads.

Next guide Configure a production deployment

Upgrade the deployment

Before upgrading:

  • Back up all three PostgreSQL databases.
  • Back up the stable application and LiteLLM keys.
  • Review the release notes.
  • Confirm that all four Agent Barn image tags belong to the target release.
  • Review chart or configuration changes.
  • Plan for a brief LiteLLM interruption during replacement.

Update the pinned image tags in .env.deploy, then run:

Shell
helm dependency build helm/monitoring
./deploy.sh

The API chart runs database migrations before installation or upgrade.

LiteLLM uses a non-overlapping update strategy because two 2 GiB LiteLLM pods may not fit inside the namespace quota simultaneously. Its replacement can briefly interrupt model requests.

Troubleshooting

Helm reports missing chart dependencies

helm dependency build helm/monitoring

Build the monitoring dependencies and retry:

Shell
helm dependency build helm/monitoring
./deploy.sh

The namespace or RBAC bootstrap fails

kubectl auth can-i create namespaces

Check your active identity:

Shell
kubectl auth whoami
kubectl auth can-i create namespaces
kubectl auth can-i create roles --namespace agent-farm
kubectl auth can-i create rolebindings --namespace agent-farm

The default deploy.sh applies k8s/agent-farm-user.yaml, including the Namespace, Role, and RoleBinding.

If you only have namespace-scoped access, the namespace and bootstrap identity must be provisioned out of band, and the bootstrap step in deploy.sh must be adapted accordingly.

A pod is stuck in ImagePullBackOff

kubectl describe pod POD_NAME --namespace agent-farm

Inspect the pod:

Shell
kubectl describe pod POD_NAME --namespace agent-farm

Confirm:

  • The registry hostname is correct.
  • The registry username and password are valid.
  • The image repository and tag exist.
  • The generated registry pull Secret contains credentials for REGISTRY_SERVER.

Do not replace a missing release image with an unrelated latest image.

A PVC remains Pending

kubectl describe pvc PVC_NAME --namespace agent-farm

Check the claim and available StorageClasses:

Shell
kubectl describe pvc PVC_NAME --namespace agent-farm
kubectl get storageclass

Confirm that STORAGE_CLASS exists and supports dynamically provisioned ReadWriteOnce volumes.

TLS certificates are not ready

kubectl get certificate,challenge,order --namespace agent-farm

Inspect the ingress, certificates, and cert-manager challenges:

Shell
kubectl describe ingress --namespace agent-farm
kubectl get certificate,certificaterequest,challenge,order --namespace agent-farm

Confirm that:

  • The three hostnames resolve to the ingress endpoint.
  • Traefik accepts the traefik IngressClass.
  • The letsencrypt-http01 ClusterIssuer exists and is ready.
  • Ports 80 and 443 are reachable where required by the issuer.

The migration hook fails

kubectl get jobs --namespace agent-farm

List jobs and inspect the failed migration pod:

Shell
kubectl get jobs --namespace agent-farm
kubectl get pods --namespace agent-farm
kubectl logs JOB_POD_NAME --namespace agent-farm

Confirm that the application PostgreSQL pod is ready and that the configured database password still matches the initialized database.

The LiteLLM key hook fails

kubectl logs JOB_POD_NAME --namespace agent-farm

Inspect the hook job:

Shell
kubectl get jobs --namespace agent-farm
kubectl logs JOB_POD_NAME --namespace agent-farm

Confirm that:

  • LiteLLM is ready.
  • LITELLM_MASTER_KEY is correct.
  • The configured hook ServiceAccount can create and update Secrets.
  • The ServiceAccount exists in agent-farm.

Agent Barn loads, but an Agent cannot start

kubectl logs deployment/agentbarn-api --namespace agent-farm

Inspect the API logs:

Shell
kubectl logs deployment/agentbarn-api \
  --namespace agent-farm \
  --container api

Confirm that the kubeconfig mounted into the API:

  • Targets the correct cluster
  • Can manage resources in agent-farm
  • Uses a reachable in-cluster Kubernetes API endpoint
  • Has not expired
  • Can create Deployments, Services, PVCs, Secrets, and ConfigMaps
  • Can read Pods and pod logs

Also verify that the Hermes and OpenClaw image tags exist in the configured registry.

Grafana starts but shows no Agents

agentbarn.io/component=agent

Agent metrics appear after an Agent has been started with the current resource labels.

For an Agent that predates the monitoring deployment, stop and start it once so Agent Barn recreates its runtime resources and monitoring metadata.

Deployment constraints

Account for these current deployment-tooling constraints when preparing an environment:

  1. .env.deploy.spec defines INGRESS_CLUSTER_ISSUER, but helmfile.yaml.gotmpl does not currently pass it into the API or UI charts. The charts therefore use letsencrypt-http01.
  2. helmfile.yaml.gotmpl requires SLACK_ALERTS_WEBHOOK_URL, GRAFANA_ADMIN_PASSWORD, and GRAFANA_HOST, but those variables are not currently listed in .env.deploy.spec. Add them manually.
  3. deploy.sh does not currently run helm dependency build helm/monitoring. Run it before the deployment.
  4. deploy.sh always applies the production bootstrap manifest at k8s/agent-farm-user.yaml. Changing only NAMESPACE is not sufficient for a staging or custom-namespace deployment.
  5. The API-facing kubeconfig defaults to the same kubeconfig used for the deployment. Production operators should replace this with a dedicated namespace-scoped identity.
  6. The repository and GitHub project are named agent-barn, while the production and staging namespaces intentionally remain agent-farm and agent-farm-staging.
Documentation