Skip to content

First VPS deployment

This is the supported first-deployment path: an Ubuntu or Debian VPS, Docker Engine, Docker Compose, one model provider, and Telegram long polling.

No inbound application port is required for Telegram. Blacki binds its HTTP port to the VPS loopback interface unless you explicitly opt out.

Before you start

You need:

Install Docker Engine from Docker's official instructions for Ubuntu or Debian. Install the Docker Compose plugin from Docker's repository so it receives package updates.

Verify the host:

docker --version
docker compose version
git --version

Do not run setup.sh unattended

The repository's legacy setup.sh performs broad root-level changes, including an OS upgrade, firewall changes, Docker daemon configuration, and docker-group membership. It is not the supported first-deployment path. Review it line by line before using it on a disposable host.

1. Clone Blacki

git clone https://github.com/QueryPlanner/blacki.git
cd blacki
cp .env.minimal .env
chmod 600 .env

The Docker build context is allowlisted by .dockerignore; .env, Git data, runtime state, logs, and unrelated local files are not sent to the builder.

2. Configure the assistant

Open .env in your editor and replace every replace-me value:

AGENT_NAME=my-blacki
ROOT_AGENT_MODEL=openrouter/google/gemini-2.5-flash
OPENROUTER_API_KEY=replace-me
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=replace-me

AGENT_NAME is required. Keep only the API key for the provider you use. The full configuration reference shows the Google AI Studio alternative and optional integrations.

The safe deployment defaults are:

HOST_PORT=8080
SERVE_WEB_INTERFACE=false
RELOAD_AGENTS=false
RESTART_POLICY=unless-stopped

3. Validate before starting

docker compose -f compose.yaml -f compose.prod.yaml config --quiet

This catches missing required Compose values and invalid YAML without starting the service. It does not validate model or Telegram credentials.

4. Build and start

docker compose -f compose.yaml -f compose.prod.yaml up --build -d
docker compose -f compose.yaml -f compose.prod.yaml ps

The first build installs the locked Python dependencies and can take several minutes. docker compose ps should eventually report the agent service as healthy. The Compose healthcheck calls /ready, which returns success only after the required SQLite resource is initialized and answering queries.

If startup fails:

docker compose -f compose.yaml -f compose.prod.yaml logs --tail=200 agent

5. Verify the deployment

Inspect the application health details from the VPS:

curl --fail http://127.0.0.1:8080/ready

/live is a process-only liveness endpoint. /ready and its compatibility alias /health treat SQLite as critical and return HTTP 503 during startup or when the database is unavailable. Optional Mem0 memory is deliberately not a readiness dependency.

Secure browser access

The ADK web interface is a development interface and is disabled in the VPS sample. To inspect it temporarily:

  1. Start the development overlay with docker compose -f compose.yaml -f compose.dev.yaml up -d.
  2. From your computer, open an SSH tunnel:
ssh -L 8080:127.0.0.1:8080 your-user@your-vps
  1. Open http://127.0.0.1:8080 locally.
  2. Return to the production overlay when finished.

The supported overlays cannot be changed to a public bind through .env. An authenticated reverse proxy is a separate deployment decision and is outside this guide.

Use a prebuilt image only when verified

The source-build path above works without a container registry. If you publish an image from your own fork, verify its tag and visibility first, then set:

IMAGE=ghcr.io/your-owner/blacki:your-tag

Authenticate to GHCR if the package is private, then use:

docker compose -f compose.yaml -f compose.prod.yaml pull
docker compose -f compose.yaml -f compose.prod.yaml up --no-build -d

--no-build makes the prebuilt-image path explicit. Do not assume that the QueryPlanner package is anonymously pullable; that has not been verified.

Important change for existing installations

Older Compose defaults could publish port 8080 on all host interfaces and enable the web UI and agent reload. The base file now publishes no host port; both supported overlays force loopback. Production also forces the UI and reload off, while the development overlay enables both without public exposure. After the first successful start, continue with Day-two operations.