Skip to content

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.

Terminal window
# HeliosDB-Lite (database server) — run inside the unpacked source distribution
docker build -f deployment/docker/Dockerfile -t heliosdb-lite:latest .
# HeliosProxy (connection pooler): published image; pin a release tag in production
docker pull ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latest

Run HeliosDB

Terminal window
# Simple single-node deployment
# HELIOSDB_JWT_SECRET is mandatory: the server refuses to start without it
docker network create heliosdb-net
docker 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:latest

Run 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:

Terminal window
curl -fsSLo proxy.toml \
https://raw.githubusercontent.com/HeliosDatabase/HeliosDB-Proxy/main/config/proxy.example.toml

The 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:

Terminal window
# 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:latest

The 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

Terminal window
# HeliosDB-Lite (inside the unpacked source distribution)
docker build -t heliosdb-lite:local -f deployment/docker/Dockerfile .
# HeliosProxy: use the published image
docker pull ghcr.io/heliosdatabase/hdb-heliosdb-proxy:latest

Docker Compose Deployments

Single Node

docker-compose.yml
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 VariableDefaultDescription
HELIOSDB_JWT_SECRET-Required. REST API token signing secret; the server refuses to start without it
HELIOSDB_DATA_DIR/dataData storage directory
HELIOSDB_LOG_LEVELinfoLog level (trace, debug, info, warn, error)
HELIOSDB_MODEserverOperating mode
HELIOSDB_REST_PORT8080REST API port
HELIOSDB_PG_PORT5432PostgreSQL protocol port
HELIOSDB_ENCRYPTION_KEY-Encryption key (hex)
HELIOSDB_API_KEY-API authentication key
HELIOSDB_MAX_CONNECTIONS100Maximum client connections
HELIOSDB_CACHE_SIZE_MB512Query 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:

PlaceholderDefault in exampleDescription
HELIOS_PROXY_LISTEN0.0.0.0:6432Client listen address
HELIOS_PROXY_ADMIN127.0.0.1:9090Admin API address (non-loopback requires admin_token)
HELIOS_PROXY_POOL_MAX50[pool] max_connections
HELIOS_PROXY_POOL_MODEtransaction[pool_mode] mode (session/transaction/statement)
HELIOS_PROXY_PRIMARY_HOSTdb-primaryHost of the primary [[nodes]] entry
HELIOS_PROXY_STANDBY1_HOSTdb-standby1Host of the standby [[nodes]] entry

See the HeliosProxy documentation for the full configuration reference.

Volumes and Persistence

Data Volume

Terminal window
# Create named volume
docker 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 volume
docker run --rm -v heliosdb_data:/data -v $(pwd):/backup alpine \
tar czf /backup/heliosdb_backup.tar.gz /data

Host Directory

Terminal window
# 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:latest

Health Checks

Both images include built-in health checks:

Terminal window
# Check HeliosDB health
curl http://localhost:8080/health
# Check HeliosProxy health
curl http://localhost:9090/health
# Docker health status
docker inspect --format='{{.State.Health.Status}}' heliosdb

Resource 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: 2G

Networking

Bridge Network (default)

Terminal window
# Create network
docker network create helios-net
# Run containers on network
docker run --network helios-net --name heliosdb ...
docker run --network helios-net --name proxy ...

Host Network (for performance)

Terminal window
docker run --network host -e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" heliosdb-lite:latest

Security Considerations

Non-root User

Both images run as non-root user helios (UID 1000).

Read-only Root Filesystem

Terminal window
docker run --read-only \
-e HELIOSDB_JWT_SECRET="$(openssl rand -hex 32)" \
-v heliosdb_data:/data \
-v heliosdb_tmp:/tmp \
heliosdb-lite:latest

Secrets

Terminal window
# Using Docker secrets
echo "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:latest

Troubleshooting

View Logs

Terminal window
docker logs heliosdb
docker logs -f heliosdb # Follow logs

Shell Access

Terminal window
# Note: Images use slim base, shell is /bin/sh
docker exec -it heliosdb /bin/sh

Check Configuration

Terminal window
docker exec heliosdb cat /etc/helios/heliosdb.toml

Common 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 main or heliosproxy branches
  • Git tags (v*)
  • Pull requests (build only, no push)

See .github/workflows/docker-publish.yml for workflow details.

Manual Registry Push

Terminal window
# Login to registry
docker login ghcr.io
# Tag and push
docker tag heliosdb-lite:local registry.example.com/myorg/heliosdb-lite:<release>
docker push registry.example.com/myorg/heliosdb-lite:<release>