---
title: "Docker Deployment Guide"
---

# 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](mailto: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.

```bash
# 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

```bash
# 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:

```bash
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:

```bash
# 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

```bash
# 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

```yaml
# 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

```yaml
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

```yaml
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](/docs/proxy/) for the full configuration reference.

## Volumes and Persistence

### Data Volume

```bash
# 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

```bash
# 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:

```bash
# 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

```yaml
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)

```bash
# 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)

```bash
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

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

### Secrets

```bash
# 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

```bash
docker logs heliosdb
docker logs -f heliosdb  # Follow logs
```

### Shell Access

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

### Check Configuration

```bash
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

```bash
# 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>
```
