Running cang in a container¶
Cang is published as an OCI image and can be run with Podman, Docker, or any OCI-compatible runtime.
The image ships two binaries — cangcang (ingest daemon) and cangjian (web server). Both share one image; the container command selects which to run.
Architecture¶
Cang runs as two containers sharing a pod (Podman) or a shared network (Docker Compose). Both need the same volume mounts:
| Container path | What to mount | Mode |
|---|---|---|
/config/cang.toml |
Your cang.toml config file |
:ro |
/data |
Output directory for snapshots and cang.db |
read-write |
On top of that, cangcang needs each camera root mounted at the same path
declared in cang.toml. cangjian does not need camera mounts — it only
reads the database and snapshot store.
Quick start with Docker Compose¶
Create a minimal cang.toml (see configuration reference):
[server]
output_dir = "/data"
[[camera]]
name = "front-door"
adapter = "dahua"
root = "/cameras/ABC123456"
Note: camera roots inside the container use /cameras/… rather than the
host path. Mount them accordingly in the compose file.
services:
cangcang:
image: registry.marvin8.zone/marvin8/cang:latest
command: cangcang /config/cang.toml
environment:
- TZ=Australia/Brisbane
volumes:
- ./cang.toml:/config/cang.toml:ro
- cang-data:/data
- /mnt/nvr/ABC123456:/cameras/ABC123456:ro
restart: unless-stopped
cangjian:
image: registry.marvin8.zone/marvin8/cang:latest
command: cangjian /config/cang.toml
environment:
- TZ=Australia/Brisbane
ports:
- "8080:8080"
volumes:
- ./cang.toml:/config/cang.toml:ro
- cang-data:/data
restart: unless-stopped
volumes:
cang-data:
The web UI will be available at http://localhost:8080/days.
Systemd Quadlet setup (Podman pod)¶
Quadlet is the recommended way to run Podman containers as persistent systemd services without root.
Cang uses a pod to share the network namespace between the two containers and optionally a Tailscale sidecar. Pod-level volumes are inherited by every container.
cang.pod¶
[Pod]
PodName=cang-pod
Volume=/home/NAS/cang/cang.toml:/config/cang.toml:ro
Volume=/home/NAS/cang/clips:/data
ExitPolicy=stop
cangcang.container¶
[Container]
Pod=cang.pod
ContainerName=cangcang
Image=registry.marvin8.zone/marvin8/cang:latest
Environment=TZ=Australia/Brisbane
Volume=/mnt/nvr/ABC123456:/cameras/ABC123456:ro
Exec=cangcang /config/cang.toml
UserNS=keep-id
[Service]
Restart=on-failure
TimeoutStopSec=70
cangjian.container¶
[Container]
Pod=cang.pod
ContainerName=cangjian
Image=registry.marvin8.zone/marvin8/cang:latest
Environment=TZ=Australia/Brisbane
Exec=cangjian /config/cang.toml
UserNS=keep-id
[Service]
Restart=on-failure
TimeoutStopSec=70
Place the files in ~/.config/containers/systemd/, then activate:
To start automatically at boot without a logged-in session:
The ,z SELinux relabel suffix on volume mounts is required on SELinux-enforcing systems
(Fedora, RHEL, etc.); omit it on systems without SELinux.
Building locally¶
Run the ingest daemon:
podman run --rm \
-v ./cang.toml:/config/cang.toml:ro \
-v /tmp/cang-data:/data \
-v /mnt/nvr/ABC123456:/cameras/ABC123456:ro \
cang cangcang /config/cang.toml
Run the web server in a separate terminal: