Skip to main content

Docker Runner — Self-Host Your Bots on Any Server

The Docker Runner connects VolatiCloud to a Docker host you control — a VPS, cloud VM, or bare-metal server — where each bot runs as its own Freqtrade container. This is the simplest production-capable runner: one Linux box, Docker, and a TLS-protected daemon, and you can run dozens of isolated trading bots cost-effectively.

This page walks you through the secure-production path: TLS certificate generation, Docker daemon configuration, firewall setup, registering the runner in VolatiCloud, and optional S3 backups. For deciding between Docker and Kubernetes, see Runners Overview.

Prerequisites

  • A Linux server with Docker installed (Ubuntu, Debian, Rocky, etc. all work)
  • Network access from VolatiCloud's runner egress IPs to your Docker port (default 2376 for TLS)
  • For production: Docker daemon configured with TLS authentication (not optional — see warning below)
  • Optional: S3-compatible storage for bot database backups (AWS S3, MinIO, Cloudflare R2, etc.)

Quick Setup (Development Only)

warning

Exposing the Docker daemon without TLS is a critical security risk. An unauthenticated Docker daemon over TCP gives anyone on the network root-equivalent access to the host. Only use the unencrypted form for local development on an isolated network. For anything reachable from the public internet, follow the Secure Production Setup below instead.

# /etc/docker/daemon.json — DO NOT use this on the public internet
{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"]
}

Secure Production Setup (with TLS)

The production path uses mutual TLS — the Docker daemon presents a server certificate signed by a CA you control, and VolatiCloud authenticates with a client certificate signed by the same CA. No one without that client certificate can reach the daemon.

Step 1 — Generate TLS Certificates

# Generate CA key and certificate
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

# Generate server key and certificate (replace YOUR_SERVER_IP)
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=YOUR_SERVER_IP" -sha256 -new -key server-key.pem -out server.csr
echo subjectAltName = IP:YOUR_SERVER_IP,IP:127.0.0.1 >> extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnf

# Generate client key and certificate
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile-client.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -extfile extfile-client.cnf

This produces:

FileUsed byStays on
ca.pemBoth server and clientBoth
server-cert.pem, server-key.pemDocker daemonServer only
cert.pem, key.pemVolatiCloud clientPasted into VolatiCloud's runner config

Step 2 — Configure the Docker Daemon

Move the server certificates into a path Docker can read (e.g., /etc/docker/certs/), then edit /etc/docker/daemon.json:

{
"tlsverify": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem",
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"]
}

Restart Docker so the new configuration applies:

sudo systemctl restart docker

Step 3 — Configure the Firewall

Restrict port 2376 to VolatiCloud's runner egress IPs only. With ufw:

ufw allow from <volaticloud-egress-ip> to any port 2376

See Egress IPs for the canonical list once published.

Step 4 — Verify Locally

From the server itself, verify Docker is listening over TLS:

docker --tlsverify \
--tlscacert=ca.pem \
--tlscert=cert.pem \
--tlskey=key.pem \
-H=tcp://YOUR_SERVER_IP:2376 \
version

You should see both client and server versions returned. If the command hangs, the firewall is dropping the connection. If TLS fails, regenerate certificates with the correct subjectAltName.

Registering the Runner in VolatiCloud

Create Runner drawer in Docker mode, with fields for Host URL, TLS CA Certificate, TLS Client Certificate, and TLS Client Key, plus Test Connection and Save Runner buttons in the footer

  1. Open RunnersCreate Runner
  2. Pick the Docker runner type
  3. Fill in the connection fields shown in the table below
  4. Click Test Connection — VolatiCloud connects to your Docker daemon and lists images to verify the credentials work
  5. Click Save Runner
FieldValue
Host URLtcp://YOUR_SERVER_IP:2376
TLS CA CertificateContents of ca.pem
TLS Client CertificateContents of cert.pem
TLS Client KeyContents of key.pem

The TLS materials are encrypted at rest using field-level AES-256-GCM before they're stored.

Optional: S3 Storage for Database Backups

Configuring S3 lets the runner upload each bot's SQLite database on stop and restore it on next start, so trade history persists across container restarts and runner moves.

FieldDescription
EndpointS3 endpoint URL (AWS, MinIO, Cloudflare R2, Backblaze B2)
BucketS3 bucket name
Access KeyS3 access key ID
Secret KeyS3 secret access key
RegionAWS region (e.g., us-east-1)
Use SSLEnable HTTPS for the endpoint

Click Test S3 Connection to verify the credentials. The S3 access key is encrypted at rest with the same field-level encryption as the TLS materials.

The architectural rationale for SQLite-to-S3 backups: ADR-0032 — Bot Database Backup Strategy.

Downloading Historical Data

Bots and backtests need historical OHLCV data on the runner. Pre-cache it once per runner instead of having every bot fetch its own copy:

  1. Open the runner
  2. Click Refresh Data
  3. Pick:
    • Exchange (e.g., Binance)
    • Timeframes (e.g., 1h, 4h)
    • Pair pattern (e.g., .*USDT)
    • Days of history (e.g., 365)
  4. Click Start Download and watch the progress

Downloaded data lives in the runner's data directory and is shared by every bot and backtest on that runner.

Server Sizing Guidelines

BotsRAMCPUStorage
1–52 GB1 vCPU20 GB
5–204 GB2 vCPU50 GB
20–508 GB4 vCPU100 GB
50+16+ GB8+ vCPU200+ GB

Storage scales with retained OHLCV history and per-bot SQLite database size. Consider an SSD for the data volume — backtests do a lot of random reads against historical data.

Troubleshooting

Connection refused

  • Verify Docker is running: sudo systemctl status docker
  • Check the firewall allows port 2376 from VolatiCloud's egress IPs
  • Confirm Docker is listening on TCP: sudo ss -tlnp | grep 2376

TLS handshake failed

  • All three certificates (CA, server, client) must be signed by the same CA
  • Server certificate's subjectAltName must include the IP you're connecting to
  • Check expiry: openssl x509 -noout -dates -in ca.pem

Bot fails to start on the runner

  • Pull the Freqtrade image manually to verify the runner has internet egress: docker pull freqtradeorg/freqtrade:stable
  • Check container logs: docker logs <container-id>
  • Confirm the runner has enough free disk space for the bot's database