This guide covers deploying the Pullbase central server using containers. The central server coordinates environments, monitors Git repositories, and serves the web dashboard.
Agents should run natively on your Linux servers, not in containers. Container agents require privileged access and have significant limitations. See Agent Operations for native agent installation.This page is for deploying the central server only.
Pullbase publishes a container image for the central server (pullbaseio/pullbase). This guide shows how to deploy it with Docker Compose, but the same environment variables apply if you run the image under Kubernetes, Nomad, or another orchestrator.
Prerequisites
- Docker 24.0+ with the Compose plugin (or an equivalent container runtime)
- PostgreSQL 15+ (container service or managed instance)
- Git repository containing your environment configuration (
config.yaml)
- (Production) Reverse proxy for TLS termination
For production clusters, place PostgreSQL on managed infrastructure, store secrets in a vault, and terminate TLS at a reverse proxy. The examples below target a single host for clarity.
Directory layout
/opt/pullbase/
├── docker-compose.yml
├── .env
├── config/
│ └── github-app.pem # optional, mounted read-only
└── logs/ # optional bind mount for log shipping
config/ holds the GitHub App private key or other secrets you mount read-only.
logs/ can be bound if you prefer file-based log collection; otherwise rely on docker logs.
Compose template
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: pullbaseuser
POSTGRES_PASSWORD: pullbasepass
POSTGRES_DB: pullbasedb
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U pullbaseuser -d pullbasedb']
interval: 10s
timeout: 5s
retries: 5
pullbase:
image: pullbaseio/pullbase:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
# Database
PULLBASE_DB_HOST: db
PULLBASE_DB_PORT: 5432
PULLBASE_DB_USER: pullbaseuser
PULLBASE_DB_PASSWORD: pullbasepass
PULLBASE_DB_NAME: pullbasedb
PULLBASE_DB_SSLMODE: disable
# Server
PULLBASE_SERVER_PORT: 8080
PULLBASE_SERVER_HOST: 0.0.0.0
# Authentication
PULLBASE_JWT_SECRET: ${PULLBASE_JWT_SECRET}
PULLBASE_JWT_EXPIRY_HOURS: 24
# Webhooks
PULLBASE_WEBHOOK_SECRET_KEY: ${PULLBASE_WEBHOOK_SECRET_KEY}
# Git integration
PULLBASE_GIT_ENABLED: ${PULLBASE_GIT_ENABLED:-false}
PULLBASE_GIT_CLONE_PATH: /app/git-repos
PULLBASE_GIT_POLL_INTERVAL: 60
# GitHub App (when using private repos)
PULLBASE_GITHUB_APP_ID: ${PULLBASE_GITHUB_APP_ID:-}
PULLBASE_GITHUB_APP_PRIVATE_KEY_PATH: /config/github-app.pem
PULLBASE_GITHUB_APP_API_BASE_URL: https://api.github.com
volumes:
- ./config:/config:ro
ports:
- '8080:8080'
volumes:
postgres_data:
Populate secrets in .env:
cat <<EOF > .env
PULLBASE_JWT_SECRET=$(openssl rand -hex 32)
PULLBASE_WEBHOOK_SECRET_KEY=$(openssl rand -hex 32)
PULLBASE_GIT_ENABLED=false
EOF
Launch the stack
Verify health
curl http://localhost:8080/api/v1/healthz
Tail logs
docker compose logs -f pullbase
TLS configuration
Pullbase supports two approaches for TLS in production.
Option 1: Native TLS
Enable native TLS by adding these environment variables to your Compose file:
environment:
PULLBASE_TLS_ENABLED: "true"
PULLBASE_TLS_CERT_PATH: /config/server.crt
PULLBASE_TLS_KEY_PATH: /config/server.key
Mount your certificates in the config volume:
volumes:
- ./config:/config:ro # Contains server.crt, server.key, github-app.pem
For development, you can start the server with --generate-dev-certs to auto-generate self-signed certificates.
Option 2: Reverse proxy
For existing infrastructure, place Pullbase behind a reverse proxy that handles TLS:
NGINX example
server {
listen 443 ssl http2;
server_name pullbase.example.com;
ssl_certificate /etc/ssl/certs/pullbase.crt;
ssl_certificate_key /etc/ssl/private/pullbase.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://pullbase:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Traefik example
# Add to docker-compose.yml
traefik:
image: traefik:v3.6.2
command:
- "--providers.docker=true"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "[email protected]"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
# Add labels to pullbase service
pullbase:
labels:
- "traefik.enable=true"
- "traefik.http.routers.pullbase.rule=Host(`pullbase.example.com`)"
- "traefik.http.routers.pullbase.entrypoints=websecure"
- "traefik.http.routers.pullbase.tls.certresolver=letsencrypt"
Always use TLS in production. Agents transmit authentication tokens over the network, and the web UI handles user credentials.
External databases
Using Amazon RDS, Azure Database for PostgreSQL, or another managed service?
- Create the database and grant Pullbase a dedicated user.
- Set
PULLBASE_DB_HOST, PULLBASE_DB_USER, PULLBASE_DB_PASSWORD, and PULLBASE_DB_NAME to match the instance.
- Enable TLS by setting
PULLBASE_DB_SSLMODE=require or PULLBASE_DB_SSLMODE=verify-full.
- Remove the
db service from docker-compose.yml.
Upgrades
- Pin the image tag (for example,
pullbaseio/pullbase:vX.Y.Z) and update intentionally.
- Run
docker compose pull && docker compose up -d to roll forward with minimal downtime.
- Review release notes for database migrations and watch container logs during the upgrade.
Automate backups before upgrades: docker compose exec db pg_dump -U pullbaseuser pullbasedb > backup.sql. Managed databases often provide scheduled snapshots—enable them.