Docker Deployment Guide
This guide covers building, running, and deploying HeliosDB and HeliosProxy using Docker containers.
Quick Start
Build the Images
No pre-built public images are published. HeliosDB-Lite is available to licensed customers — contact sales@heliosdb.com — and its image is built from the licensed source distribution. HeliosProxy is Apache-2.0 and can be built straight from its public repository. For multi-host or Kubernetes deployments, push both images to your own private registry.
# HeliosDB-Lite (database server) — run inside the unpacked source distributiondocker build -f deployment/docker/Dockerfile -t heliosdb-lite:latest .
# HeliosProxy (connection pooler): published image; pin a release tag in productiondocker pull ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latestRun HeliosDB
# Simple single-node deployment# HELIOSDB_JWT_SECRET is mandatory: the server refuses to start without itdocker network create heliosdb-netdocker run -d \ --name heliosdb \ --network heliosdb-net \ -p 5432:5432 \ -p 8080:8080 \ -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" \ -v heliosdb_data:/data \ heliosdb-lite:latestRun HeliosProxy
HeliosProxy is configured by a TOML file, not by environment variables alone. The
image starts with --config /etc/helios/proxy.toml and contains no config, so you must
mount one. Start from the example in the HeliosProxy repository:
curl -fsSLo proxy.toml \ https://raw.githubusercontent.com/HeliosDatabase/HeliosDB-Proxy/main/config/proxy.example.tomlThe example declares one primary and one standby [[nodes]] block. For a single
HeliosDB-Lite node, delete the standby block. String values in the file accept
${VAR:-default} substitution, so the backend host can be passed through the environment:
# Connection pooler (requires the HeliosDB container above)docker run -d \ --name heliosproxy \ --network heliosdb-net \ -p 6432:6432 \ -v "$PWD/proxy.toml:/etc/helios/proxy.toml:ro" \ -e HELIOS_PROXY_PRIMARY_HOST=heliosdb \ -e HELIOS_PROXY_POOL_MODE=session \ ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latestThe admin API (health, metrics) binds to 127.0.0.1:9090 inside the container by
default. To publish it, set admin_token in proxy.toml, set
HELIOS_PROXY_ADMIN=0.0.0.0:9090, and add -p 9090:9090. Without a token the proxy
refuses to bind the admin API to a non-loopback address.
Building Images Locally
Manual Build
# HeliosDB-Lite (inside the unpacked source distribution)docker build -t heliosdb-lite:local -f deployment/docker/Dockerfile .
# HeliosProxy: use the published imagedocker pull ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latestDocker Compose Deployments
Single Node
version: '3.8'
services: heliosdb: image: heliosdb-lite:latest ports: - "5432:5432" - "8080:8080" volumes: - heliosdb_data:/data environment: - HELIOSDB_LOG_LEVEL=info - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET}
volumes: heliosdb_data:With HeliosProxy
version: '3.8'
services: heliosdb: image: heliosdb-lite:latest ports: - "5432:5432" environment: - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET} volumes: - heliosdb_data:/data
proxy: image: ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latest ports: - "6432:6432" # Client connections volumes: # proxy.example.toml from HeliosDB-Proxy, standby [[nodes]] block removed - ./proxy.toml:/etc/helios/proxy.toml:ro environment: - HELIOS_PROXY_PRIMARY_HOST=heliosdb - HELIOS_PROXY_POOL_MODE=session depends_on: - heliosdb
volumes: heliosdb_data:HA Cluster with Proxy
version: '3.8'
services: # Replication needs an image built with the `ha-tier1` feature # (the stock Dockerfile builds only `encryption,vector-search`). helios-primary: image: heliosdb-lite:latest command: ["start", "--data-dir", "/data", "--listen", "0.0.0.0", "--port", "5432", "--replication-role", "primary", "--standby-hosts", "helios-standby1:5433,helios-standby2:5433"] environment: - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET} volumes: - primary_data:/data
helios-standby1: image: heliosdb-lite:latest command: ["start", "--data-dir", "/data", "--listen", "0.0.0.0", "--port", "5432", "--replication-role", "standby", "--primary-host", "helios-primary:5433"] environment: - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET} volumes: - standby1_data:/data depends_on: - helios-primary
helios-standby2: image: heliosdb-lite:latest command: ["start", "--data-dir", "/data", "--listen", "0.0.0.0", "--port", "5432", "--replication-role", "standby", "--primary-host", "helios-primary:5433"] environment: - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET} volumes: - standby2_data:/data depends_on: - helios-primary
proxy: image: ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latest ports: - "6432:6432" volumes: # proxy.example.toml from HeliosDB-Proxy plus a third [[nodes]] block # for the second standby (host = "${HELIOS_PROXY_STANDBY2_HOST:-helios-standby2}") - ./proxy.toml:/etc/helios/proxy.toml:ro environment: - HELIOS_PROXY_PRIMARY_HOST=helios-primary - HELIOS_PROXY_STANDBY1_HOST=helios-standby1 - HELIOS_PROXY_STANDBY2_HOST=helios-standby2 - HELIOS_PROXY_POOL_MODE=session depends_on: - helios-primary - helios-standby1 - helios-standby2
volumes: primary_data: standby1_data: standby2_data:Image Configuration
HeliosDB-Lite
| Environment Variable | Default | Description |
|---|---|---|
HELIOSDB_JWT_SECRET | - | Required. REST API token signing secret; the server refuses to start without it |
HELIOSDB_DATA_DIR | /data | Data storage directory |
HELIOSDB_LOG_LEVEL | info | Log level (trace, debug, info, warn, error) |
HELIOSDB_MODE | server | Operating mode |
HELIOSDB_REST_PORT | 8080 | REST API port |
HELIOSDB_PG_PORT | 5432 | PostgreSQL protocol port |
HELIOSDB_ENCRYPTION_KEY | - | Encryption key (hex) |
HELIOSDB_API_KEY | - | API authentication key |
HELIOSDB_MAX_CONNECTIONS | 100 | Maximum client connections |
HELIOSDB_CACHE_SIZE_MB | 512 | Query cache size |
HeliosProxy
HeliosProxy reads its settings from the mounted /etc/helios/proxy.toml. It has no
fixed set of environment variables: any value in the file can reference one with
${VAR:-default}. The config/proxy.example.toml uses these placeholders:
| Placeholder | Default in example | Description |
|---|---|---|
HELIOS_PROXY_LISTEN | 0.0.0.0:6432 | Client listen address |
HELIOS_PROXY_ADMIN | 127.0.0.1:9090 | Admin API address (non-loopback requires admin_token) |
HELIOS_PROXY_POOL_MAX | 50 | [pool] max_connections |
HELIOS_PROXY_POOL_MODE | transaction | [pool_mode] mode (session/transaction/statement) |
HELIOS_PROXY_PRIMARY_HOST | db-primary | Host of the primary [[nodes]] entry |
HELIOS_PROXY_STANDBY1_HOST | db-standby1 | Host of the standby [[nodes]] entry |
See the HeliosProxy documentation for the full configuration reference.
Volumes and Persistence
Data Volume
# Create named volumedocker volume create heliosdb_data
# Run with volume (HELIOSDB_JWT_SECRET is mandatory)docker run -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" -v heliosdb_data:/data heliosdb-lite:latest
# Backup volumedocker run --rm -v heliosdb_data:/data -v $(pwd):/backup alpine \ tar czf /backup/heliosdb_backup.tar.gz /dataHost Directory
# Mount host directory (HELIOSDB_JWT_SECRET is mandatory)docker run -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" -v /path/to/data:/data heliosdb-lite:latestHealth Checks
Both images include built-in health checks:
# Check HeliosDB healthcurl http://localhost:8080/health
# Check HeliosProxy healthcurl http://localhost:9090/health
# Docker health statusdocker inspect --format='{{.State.Health.Status}}' heliosdbResource Limits
services: heliosdb: image: heliosdb-lite:latest environment: - HELIOSDB_JWT_SECRET=${HELIOSDB_JWT_SECRET:?set HELIOSDB_JWT_SECRET} deploy: resources: limits: cpus: '4' memory: 8G reservations: cpus: '1' memory: 2GNetworking
Bridge Network (default)
# Create networkdocker network create helios-net
# Run containers on networkdocker run --network helios-net --name heliosdb ...docker run --network helios-net --name proxy ...Host Network (for performance)
docker run --network host -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" heliosdb-lite:latestSecurity Considerations
Non-root User
Both images run as non-root user helios (UID 1000).
Read-only Root Filesystem
docker run --read-only \ -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" \ -v heliosdb_data:/data \ -v heliosdb_tmp:/tmp \ heliosdb-lite:latestSecrets
# Using Docker secretsecho "my-secret-key" | docker secret create heliosdb_api_key -
docker service create \ --secret heliosdb_api_key \ -e HELIOSDB_API_KEY_FILE=/run/secrets/heliosdb_api_key \ heliosdb-lite:latestTroubleshooting
View Logs
docker logs heliosdbdocker logs -f heliosdb # Follow logsShell Access
# Note: Images use slim base, shell is /bin/shdocker exec -it heliosdb /bin/shCheck Configuration
docker exec heliosdb cat /etc/helios/heliosdb.tomlCommon Issues
Container exits immediately
- Check logs:
docker logs heliosdb - Verify data directory permissions
- Check port conflicts
Cannot connect
- Verify port mapping:
docker port heliosdb - Check firewall rules
- Ensure health check passes
Performance issues
- Increase memory limits
- Use host networking
- Check I/O performance of volume mount
CI/CD Integration
GitHub Actions
Images are automatically built on:
- Push to
mainorheliosproxybranches - Git tags (
v*) - Pull requests (build only, no push)
See .github/workflows/docker-publish.yml for workflow details.
Manual Registry Push
# Login to registrydocker login ghcr.io
# Tag and pushdocker tag heliosdb-lite:local registry.example.com/myorg/heliosdb-lite:<release>docker push registry.example.com/myorg/heliosdb-lite:<release>