Skip to content

Deployment

Bub can be used interactively in a local terminal (see Terminal interaction), or deployed to a server to run as a long-lived process:

  • Persistent gateway (Gateway): listen on channels such as Telegram and Feishu around the clock and respond to messages.
  • Cloud isolated sandbox (Remote Workspace): provide a complete development toolchain inside an isolated container, accessed through the terminal with bub chat, keeping the host machine safe.

There are two main deployment approaches:

Approach Scenario Advantages
Docker Compose (recommended) Cloud servers, VPS, NAS, local containers Works out of the box with Node/pnpm/Python/Git and other toolchains included; isolated environment, easy to back up and upgrade
Daemon mode Linux / Windows hosts that already have a Python environment Low resource usage; register as a system background service in one step with bub gateway --install

Complete the following preparation before deploying:

  1. Model configuration: specify BUB_MODEL and BUB_API_KEY in .env. See Configuration for details.
  2. Channel credentials and allowlist: when connecting channels such as Telegram, always configure an allowlist (for example BUB_TELEGRAM_ALLOW_USERS) to prevent unauthorized access from consuming tokens.
  3. Data persistence: session state (Tape), history, and plugins are stored in the data directory (host ~/.bub, container /data). Make sure persistent storage is in place when deploying.

The official image (ghcr.io/bubbuild/bub) bundles Python 3.12, uv, Git, Node.js, pnpm, and common command-line tools. The host only needs to provide configuration files and storage volumes.

Fetch docker-compose.yml and env.example into the deployment directory:

mkdir -p bub-deploy && cd bub-deploy
curl -O https://raw.githubusercontent.com/bubbuild/bub/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/bubbuild/bub/main/env.example
cp env.example .env

Fill in the core parameters in .env:

# Model
BUB_MODEL=openrouter:openrouter/free
BUB_API_KEY=sk-or-...

# Channel (Telegram as an example)
BUB_TELEGRAM_TOKEN=123456789:your-telegram-bot-token
BUB_TELEGRAM_ALLOW_USERS=123456789,your_telegram_username

# Host data directory and workspace (optional)
# BUB_HOME_HOST=~/.bub
# BUB_WORKSPACE_PATH=.

docker compose reads .env from the current directory automatically. Never commit an .env containing tokens to a public repository.

By default, docker-compose.yml contains three volume mounts:

volumes:
  - ${BUB_WORKSPACE_PATH:-.}:/workspace
  - ${BUB_HOME_HOST:-${HOME}/.bub}:/data
  - ${BUB_AGENT_HOME:-${HOME}/.agents}:/root/.agents
Container path Corresponding host path Description
/workspace BUB_WORKSPACE_PATH (default current directory) Workspace: the directory where the Agent executes commands and reads/writes files
/data BUB_HOME_HOST (default ~/.bub) Data directory: stores Tape, history, and managed plugins (/data/bub-project)
/root/.agents BUB_AGENT_HOME (default ~/.agents) Global skills: Agent skills directory reused across projects

BUB_HOME=/data is set inside the container, so session data and plugins survive container destruction and recreation.

Pull the image and start it in the background:

docker compose pull
docker compose up -d
docker compose logs -f app

In production, pin a specific tag in .env (for example BUB_IMAGE=ghcr.io/bubbuild/bub:0.6.0).

Check the container status and gateway logs:

docker compose ps
docker compose logs -f app

When the Telegram gateway starts normally, it outputs:

telegram.start allow_users_count=1 allow_chats_count=0 proxy_enabled=False
telegram.start polling

Check that an environment variable was injected (without printing its value):

docker compose exec app sh -c 'test -n "$BUB_TELEGRAM_TOKEN" && echo token-present'

Compose enables stdin_open and tty by default. Even if the container runs the gateway in the background, you can enter the container at any time and start an interactive conversation:

docker compose exec -it app bub chat

This lets you pair-program directly with the Agent using the preinstalled toolchain in a fully isolated cloud sandbox.

On container startup, entrypoint.sh runs the following in order:

  1. Install Python dependencies: if /workspace/bub-reqs.txt exists, install them automatically with uv pip install.

  2. Sync plugins: activate the virtual environment and run bub install to sync the managed plugins in /data/bub-project.

  3. Run the entrypoint: if /workspace/startup.sh exists, run it with bash; otherwise run bub gateway.

Create startup.sh in the workspace and make it executable:

#!/bin/bash
# /workspace/startup.sh
set -euo pipefail

# You must use exec to replace the process so that system signals are delivered to the gateway correctly
exec /app/.venv/bin/bub gateway --enable-channel telegram

Managed plugins live in the persistent volume /data/bub-project. Install them directly inside the container without rebuilding the image:

# Install a plugin
docker compose exec app bub install https://github.com/owner/repo.git@v1.2.0

# Update plugins
docker compose exec app bub update

# Restart to activate the new plugins
docker compose restart app

Tape is an append-only JSONL file. Before upgrading, pause writes and make a backup:

# 1. Stop writes and back up
docker compose stop app
tar -czf "bub-data-$(date +%Y%m%d-%H%M%S).tar.gz" "$HOME/.bub"
cp .env ".env.bak-$(date +%Y%m%d-%H%M%S)"

# 2. Pull the new image and start
docker compose pull
docker compose up -d

To roll back, simply switch back to the old tag in .env (for example BUB_IMAGE=ghcr.io/bubbuild/bub:0.6.0) and restart.


On a host that already has a Python environment, you can use the built-in --install command of bub gateway to register it directly as a system background service:

  • Linux: registers as a systemd user service at ~/.config/systemd/user/bub-gateway.service.
  • Windows: registers as a scheduled task for the current user (auto-start at login, automatic restart on failure).
  • macOS: --install is not supported yet; use launchd, tmux, or the Docker approach above.

Run the following in the workspace directory that contains .env:

# Create the environment and install the app
uv venv && source .venv/bin/activate
uv pip install 'bub[app]'

# Install and start the background service in one step
bub gateway --install

The installer automatically records the current Python interpreter path, workspace directory, and environment variables.

After a Linux user logs out of SSH, user-level services are suspended by default. To keep running around the clock, enable linger:

loginctl enable-linger $USER

Common management commands:

# Check status
systemctl --user status bub-gateway

# Follow logs in real time
journalctl --user -u bub-gateway -f

# Restart and stop
systemctl --user restart bub-gateway
systemctl --user stop bub-gateway

To remove the background service:

bub gateway --uninstall

  • Strict allowlist: configure BUB_TELEGRAM_ALLOW_USERS or BUB_TELEGRAM_ALLOW_CHATS; messages that fail validation are rejected or silently dropped.
  • Minimize the workspace: mount only the project directories you need into the workspace, and do not let the Agent access directories containing host keys or critical system paths.
  • Step limit: cap the steps per task with BUB_MAX_STEPS to guard against infinite loops and API quota consumption. It is unlimited by default (sys.maxsize), so production deployments should set it explicitly, for example to 50.
  • Credential security: inject secrets through .env or environment variables, and never commit tokens to version control.
  • Regular backups: periodically archive and back up the Tape files in ~/.bub (or the container’s /data).