Compose Profiles
FreeSDN uses Docker Compose profiles to gate optional services. The core stack (Postgres, logdb, Valkey, API, worker, scheduler, pg-backup, Caddy edge) runs at every tier without any profile. Profiles add capabilities on top.
Set profiles in your env file as a comma-separated list:
# In .env.proCOMPOSE_PROFILES=io-worker,monitoringOr override from the command line for a one-off run:
docker compose --env-file .env.pro --profile cameras up -d go2rtcProfile reference
Section titled “Profile reference”io-worker - dedicated I/O Celery worker
Section titled “io-worker - dedicated I/O Celery worker”Adds: worker-io
Queues handled: discovery, sync, metrics
This worker handles vendor API calls: device discovery, controller sync, and metrics collection. These tasks are slow (network I/O bound) and can block the default worker if they share a queue. The io-worker profile isolates them so adapter timeouts do not starve quick tasks like alert notifications and heartbeats.
When to use: Pro and Max tiers. If you manage more than ~20 devices or run scheduled discovery, enable this profile.
COMPOSE_PROFILES=io-worker,...WORKER_IO_QUEUES=discovery,sync,metricsCELERY_IO_CONCURRENCY=2 # raise to 4 on Max if you have many controllersWORKER_IO_MEM_LIMIT=1Gmonitoring - Flower dashboard
Section titled “monitoring - Flower dashboard”Adds: flower
Port: Internal only (not published to the host in production)
Flower is the Celery task monitoring UI. It shows worker status, task history, queue depths, and allows manual task revocation. In production, Flower is internal-only - access it via a tunnel or the admin reverse proxy.
When to use: Pro and Max tiers, or whenever you want visibility into Celery.
COMPOSE_PROFILES=...,monitoringFLOWER_BASIC_AUTH=admin:__CHANGE_ME__Access Flower by proxying into the container:
# Flower is bridge-internal - no host port is published. Use an SSH tunnel:ssh -L 5555:localhost:5555 user@host# Or exec into the worker and inspect tasks directly:docker compose --env-file .env.pro exec flower celery -A app.core.celery_app inspect activecameras - go2rtc camera restream sidecar
Section titled “cameras - go2rtc camera restream sidecar”Adds: go2rtc
go2rtc provides RTSP-to-HLS/WebRTC transcoding for the Video Surveillance module. Without this profile, camera live streams in the UI may not work (depending on the browser and stream format).
When to use: Any tier where you use the Video Surveillance module with live streaming.
COMPOSE_PROFILES=...,camerascollector - SNMP trap / Syslog / NetFlow listener
Section titled “collector - SNMP trap / Syslog / NetFlow listener”Adds: collector
Publishes: UDP 514 (syslog), 162 (SNMP traps), 2055 (NetFlow) on the host
The Observability module’s UDP receivers also load inside the api process, but that path cannot reliably accept external UDP: under multi-worker Gunicorn only one worker can bind a given UDP port, and the api container is non-root and read_only with no cap_add, so it cannot bind the privileged ports 514 and 162 at all. The collector profile starts one dedicated, non-root process (python -m app.modules.collector.run) that binds the receivers deterministically and publishes them to the host.
It needs neither root nor a Linux capability: the service sets the namespaced sysctl net.ipv4.ip_unprivileged_port_start=0, which lets the unprivileged user bind 514/162 inside that container’s network namespace only.
When to use: any tier where devices send SNMP traps, syslog, or NetFlow to FreeSDN. Without this profile, the Observability module still stores and searches data, but nothing external can reach the listeners.
COMPOSE_PROFILES=...,collector
# Optional - these set the PUBLISHED host mapping (host and container side# alike). Compose does not pass them into the container, so moving a listener# also means setting the matching per-org port in the collector config.# Defaults shown.COLLECTOR_SYSLOG_PORT=514COLLECTOR_SNMP_PORT=162COLLECTOR_NETFLOW_PORT=2055Or as a one-off run:
docker compose --env-file .env.pro --profile collector up -dSee Observability for enabling each receiver and setting the source-IP allow-list.
pooling - PgBouncer connection pooler
Section titled “pooling - PgBouncer connection pooler”Adds: pgbouncer (for the primary DB) and pgbouncer-logdb (for TimescaleDB)
PgBouncer sits between the application containers and PostgreSQL and multiplexes many application connections onto a smaller number of actual DB connections. This prevents “too many clients” errors when Gunicorn workers, Celery workers, and scheduled tasks all hold connection pools simultaneously.
When to use: Max tier, or Pro tier once you exceed ~50 managed devices or start seeing TooManyConnectionsError in API logs.
COMPOSE_PROFILES=...,pooling
# After enabling, point the application at PgBouncer instead of Postgres:DB_HOST=pgbouncerDB_PORT=6432LOGDB_HOST=pgbouncer-logdbLOGDB_PORT=6432dr - off-site encrypted backup sync
Section titled “dr - off-site encrypted backup sync”Adds: pg-backup-offsite (rclone-based sync sidecar)
The dr profile runs an rclone process that copies the locally-encrypted GPG dumps from the pg_backups volume to your configured off-site destination (S3, Backblaze B2, Azure Blob, GCS, SFTP, WebDAV, and 60+ other providers). Off-site retention defaults to 30 days and runs independently of local 7-day retention.
When to use: Max tier. Strongly recommended for any production deployment where data loss would have business impact.
COMPOSE_PROFILES=...,dr
BACKUP_OFFSITE_REMOTE=backupremote # name of the remote in rclone.confBACKUP_OFFSITE_PATH=freesdn-backups # path/bucket on the remoteOne-time setup:
# Generate rclone config on any machine with rclone installed:rclone config# Save the resulting config as ./secrets/rclone.conf in the repoSee Backups and Restore for the full backup strategy, GPG key setup, and restore procedure.
metrics - Prometheus + exporters
Section titled “metrics - Prometheus + exporters”Adds: prometheus, redis-exporter, postgres-exporter, logdb-exporter
This profile starts a Prometheus instance configured to scrape the FreeSDN API’s /metrics endpoint (auth token required) and the three infrastructure exporters. The Prometheus scrape config is loaded from docker/prometheus/prometheus.yml; alert rules are loaded from observability/prometheus/alerts.yml.
When to use: Pro and Max tiers when you want integrated Prometheus metrics. For large deployments with an existing Prometheus infrastructure, scrape the /metrics endpoint directly instead.
COMPOSE_PROFILES=...,metricsMETRICS_AUTH_TOKEN=<openssl rand -hex 32> # required; see ConfigurationSee Monitoring for the key custom metrics and recommended Grafana dashboards.
nginx - nginx edge (escape hatch)
Section titled “nginx - nginx edge (escape hatch)”Adds: edge-nginx as an alternative edge proxy
Use this instead of the default Caddy edge when your environment standardizes on nginx, or when TLS is terminated at an upstream hardware/cloud load balancer. See Networking and TLS for the detailed usage pattern.
# Use nginx edge, suppress CaddyCOMPOSE_PROFILES=nginx,...# Then start with --scale edge=0 to prevent Caddy from startingdocker compose --env-file .env.pro up -d --scale edge=0vpn - privileged VPN sidecar (opt-in)
Section titled “vpn - privileged VPN sidecar (opt-in)”Adds: vpn, a root container with cap_add: [NET_ADMIN] and /dev/net/tun
FreeSDN runs capless by default: no privileged container, and the api is an ordinary bridge service. The vpn profile starts a single sidecar that concentrates all the elevated network privilege (root, NET_ADMIN, /dev/net/tun, net.ipv4.ip_forward=1) in one place and runs the tunnel daemons there. It reuses the backend image with a VPN-only entrypoint.
The profile alone is not enough. It starts the sidecar; the docker-compose.vpn.yml overlay is what rewires the rest, setting network_mode: service:vpn and VPN_MODE=sidecar on the api, adding the shared control volumes, and repointing the Caddy edge at vpn:8000. Enable both together:
COMPOSE_PROFILES=vpn \ docker compose --env-file .env.pro \ -f docker-compose.yml -f docker-compose.vpn.yml up -dWhen to use: only when FreeSDN itself must route into remote-site overlay tunnels. Leave it off otherwise - the default capless topology is the intended one.
Recommended profile combinations by tier
Section titled “Recommended profile combinations by tier”| Tier | Typical COMPOSE_PROFILES value |
|---|---|
| Lite | (empty - core services only) |
| Pro | io-worker,monitoring |
| Pro + cameras | io-worker,monitoring,cameras |
| Pro + pooling | io-worker,monitoring,pooling |
| Pro + observability ingest | io-worker,monitoring,collector |
| Max | io-worker,monitoring,pooling,dr |
| Max + metrics | io-worker,monitoring,pooling,dr,metrics |
| Max + cameras | io-worker,monitoring,pooling,dr,cameras |
The vpn profile is deliberately absent from these combinations: it also requires the docker-compose.vpn.yml overlay on the command line, so it is not a drop-in addition to COMPOSE_PROFILES.
All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.