Skip to content

Docker Deployment

Use this page when you want to run FastForward as a standalone container on a single host. For Kubernetes clusters, see Kubernetes deployment.

Terminal window
docker run -d \
--name ffwd \
-v /var/log:/var/log:ro \
-v ./config.yaml:/etc/ffwd/config.yaml:ro \
-v ffwd-data:/var/lib/ffwd \
-p 9090:9090 \
--cpus 1.0 \
--memory 256m \
ghcr.io/strawgate/fastforward:latest \
run --config /etc/ffwd/config.yaml
FlagPurpose
-v /var/log:/var/log:roGives FastForward read-only access to host log files
-v ./config.yaml:/etc/ffwd/config.yaml:roInjects your pipeline configuration (read-only)
-v ffwd-data:/var/lib/ffwdPersists checkpoint data between container restarts
-p 9090:9090Exposes the diagnostics/admin API on the host
--cpus 1.0Limits the container to one CPU core
--memory 256mHard memory cap; the OOM killer fires if exceeded
Terminal window
# Named volume (recommended — Docker manages the lifecycle)
-v ffwd-data:/var/lib/ffwd
# Host-path bind mount (useful when you need direct access to checkpoint files)
-v /opt/ffwd/data:/var/lib/ffwd

Your configuration must reference the same directory:

storage:
data_dir: /var/lib/ffwd

For most single-host deployments, one CPU core and 256 MB of memory are a reasonable starting point. Increase these if your host generates a high volume of logs or if you run complex SQL transforms.

Terminal window
# Conservative — suitable for light-to-moderate log volumes
docker run -d --cpus 0.5 --memory 128m ...
# Production — high-throughput hosts (>10 k lines/s)
docker run -d --cpus 2.0 --memory 512m ...

Monitor ffwd_stage_seconds_total (metric prefix will change in a future release) and container memory usage via docker stats to decide whether you need to adjust. See Monitoring & Diagnostics for details on available metrics.

Use -e flags to inject secrets or endpoint addresses without baking them into the configuration file. FastForward interpolates ${VAR} references in YAML values at startup.

Terminal window
docker run -d \
--name ffwd \
-e OTEL_ENDPOINT=https://collector.internal:4318 \
-e OTEL_TOKEN=my-secret-token \
-v /var/log:/var/log:ro \
-v ./config.yaml:/etc/ffwd/config.yaml:ro \
-v ffwd-data:/var/lib/ffwd \
-p 9090:9090 \
--cpus 1.0 \
--memory 256m \
ghcr.io/strawgate/fastforward:latest \
run --config /etc/ffwd/config.yaml

Then reference them in config.yaml:

output:
type: otlp
endpoint: "${OTEL_ENDPOINT}"
compression: zstd
auth:
bearer_token: "${OTEL_TOKEN}"

When FastForward receives logs over TCP or UDP (instead of tailing files), you need to publish the listener ports.

Terminal window
docker run -d \
--name ffwd \
-v ./config.yaml:/etc/ffwd/config.yaml:ro \
-v ffwd-data:/var/lib/ffwd \
-p 9090:9090 \
-p 5140:5140/tcp \
-p 5140:5140/udp \
--cpus 1.0 \
--memory 256m \
ghcr.io/strawgate/fastforward:latest \
run --config /etc/ffwd/config.yaml

Matching input configuration:

pipelines:
syslog-tcp:
inputs:
- type: tcp
listen: 0.0.0.0:5140
format: raw
syslog-udp:
inputs:
- type: udp
listen: 0.0.0.0:5140
format: raw

A Compose file is the easiest way to run FastForward alongside an OpenTelemetry Collector on the same host. The example below tails host logs, forwards them over OTLP to the collector sidecar, and exposes the diagnostics API.

docker-compose.yml
services:
ffwd:
image: ghcr.io/strawgate/fastforward:latest
command: ["run", "--config", "/etc/ffwd/config.yaml"]
volumes:
- /var/log:/var/log:ro
- ./config.yaml:/etc/ffwd/config.yaml:ro
- ffwd-data:/var/lib/ffwd
ports:
- "9090:9090"
environment:
- OTEL_ENDPOINT=http://otel-collector:4318
deploy:
resources:
limits:
cpus: "1.0"
memory: 256M
depends_on:
- otel-collector
restart: unless-stopped
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config", "/etc/otelcol/config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otelcol/config.yaml:ro
ports:
- "4317:4317" # gRPC receiver
- "4318:4318" # HTTP receiver
restart: unless-stopped
volumes:
ffwd-data:

Start the stack:

Terminal window
docker compose up -d
docker compose logs -f ffwd
Terminal window
# Process and startup logs
docker ps --filter name=ffwd
docker logs --tail=100 ffwd
# Diagnostics
curl -s http://localhost:9090/live | jq .
curl -s http://localhost:9090/admin/v1/status | jq .

You should see increasing inputs[*].lines_total and outputs[*].lines_total when logs are present.

To verify the OTLP output is connected:

Terminal window
# Check that the output reports no errors
curl -s http://localhost:9090/admin/v1/status | jq '.pipelines[].output'

If a config/image update causes failures:

Terminal window
# Stop and remove current container
docker rm -f ffwd
# Run last known-good image or config
docker run -d \
--name ffwd \
-v /var/log:/var/log:ro \
-v ./config.last-known-good.yaml:/etc/ffwd/config.yaml:ro \
-v ffwd-data:/var/lib/ffwd \
-p 9090:9090 \
ghcr.io/strawgate/fastforward:<known-good-tag> \
run --config /etc/ffwd/config.yaml

Then validate with the same diagnostics commands above.

The release workflow builds multi-arch images for linux/amd64 and linux/arm64 using a distroless base image. See Dockerfile and .github/workflows/release.yml for details.