Exclude local secrets and mutable data from image builds, restore Go checksum verification, remove runtime capability tooling and setuid/setgid permissions, and preserve non-root media and demo startup behavior. Add native image smoke checks and document runtime constraints. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Deployment with Docker
The easiest, and let's say most natural, deployment is done by utilising docker. Docker can run a stand-alone, single, Kerberos Agent (or container) and a bigger set of Kerberos Agents (or containers) through docker compose.
1. Running a single container
We are creating Docker images as part of our CI/CD process. You'll find our Docker images on Docker hub. Pick a specific tag of choice, or use latest. Once done run below command, this will open the web interface of your Kerberos agent on port 80.
docker run -p 80:80 --name mycamera -d kerberos/agent:latest
Or for a develop build:
docker run -p 80:80 --name mycamera -d kerberos/agent-dev:latest
Feel free to use another port if your host system already has a workload running on 80. For example 8082.
docker run -p 8082:80 --name mycamera -d kerberos/agent:latest
Container permissions and hardening
The production image runs as agent (UID 999, primary GID 999), with the
supplementary video group retained. The binary and home directory are owned by
root; within /home/agent, only data/ and www/ are writable by the Agent. www/ must remain writable
because demo mode replaces env.js at startup. Existing /home/agent/data/...
mount paths, the default port 80, and the startup command are unchanged.
FFmpeg is required for AAC-to-PCMU audio transcoding, curl for the health check,
and /bin/sh for remote-access sessions. They are intentionally retained. The
capability-management tools and setuid/setgid permissions on bundled utilities
are removed. The Agent binary retains only the file capability
NET_BIND_SERVICE, needed for port 80 on hosts with privileged low ports.
For an RTSP-only deployment, you can drop the other container capabilities:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
-p 80:80 --name mycamera -d kerberos/agent:latest
Do not use --privileged for ordinary IP cameras. Local cameras still use the
separate RTSP sidecar; any device access belongs to that sidecar. Host networking
remains supported. no-new-privileges prevents gaining the binary's file
capability: if enabling it, use an unprivileged internal port (AGENT_PORT=8082)
and ensure the container's net.ipv4.ip_unprivileged_port_start permits that
port. Do not assume port 80 works with that option on every host.
Bind mounts must be writable by the image's UID/GID; the container does not
change host ownership at startup. Before migrating an older volume, check the
user of the exact old and new image with docker run --rm --entrypoint id IMAGE
and adjust only the mounted directories as necessary. For example:
sudo chown -R 999:999 agent/config agent/recordings
A read-only root filesystem is not enabled by default: both data/ and www/
need writable storage (and FFmpeg or shell sessions may need /tmp).
Change the default application credentials before exposing the service.
Building and checking the image
Build from a clean checkout: the default configuration files under
machinery/data/config/ are included in the image, so do not replace them with
production credentials before building. .dockerignore excludes local .env
files, recordings, upload checkpoints, dependency directories, and unrelated
repository files from the build context. Go module downloads use Go's default
checksum database verification.
docker build --pull -t kerberos/agent:local .
sh deployments/docker/test-image.sh kerberos/agent:local
The smoke check uses temporary containers and a Docker volume, cleans them up,
and checks permissions, FFmpeg transcoding, volume initialization/writes,
default and custom HTTP ports, health probes, and demo-mode startup. It enforces
privileged low ports to check the file capability rather than relying on
Docker's usual low-port exemption, and checks no-new-privileges on port 8082. PR builds
run it on native AMD64 and ARM64 runners. It does not replace testing against a
real camera or checking all supported ARM variants. Base image tags remain
updateable; use reviewed digest-pinned base-image arguments (GO_IMAGE and
RUNTIME_IMAGE) when a reproducible build is required, and rebuild regularly
for security updates.
Architecture selections and base image tags are unchanged by this hardening.
The current upstream golang:1.25-trixie manifest has no linux/arm/v6 variant,
so the existing ARMv6 nightly target cannot be validated with that default base.
ARMv6 needs a separately reviewed compatible builder/runtime combination; do
not assume an ARMv7 image runs on ARMv6 hardware.
Attach a volume
By default your Kerberos agent will store all its configuration and recordings inside the container. It might be interesting to store both configuration and your recordings outside the container, on your local disk. This helps persisting your storage even after you decide to wipe out your Kerberos agent.
You attach a volume to your container by leveraging the -v option. To mount your own configuration file, execute as following:
-
Decide where you would like to store your configuration and recordings; create a new directory for the config file and recordings folder accordingly.
mkdir agent mkdir agent/config mkdir agent/recordings -
Once you have located your desired directory, copy the latest
config.jsonfile into your config directory.wget https://raw.githubusercontent.com/kerberos-io/agent/master/machinery/data/config/config.json -O agent/config/config.json -
Run the docker command as following to attach your config directory and recording directory.
docker run -p 80:80 --name mycamera \ -v $(pwd)/agent/config:/home/agent/data/config \ -v $(pwd)/agent/recordings:/home/agent/data/recordings \ -d --restart=always kerberos/agent:latest
Override with environment variables
Next to attaching the configuration file, it is also possible to override the configuration with environment variables. This makes deployments when leveraging docker compose or kubernetes much easier and more scalable. Using this approach we simplify automation through ansible and terraform. You'll find the full list of environment variables on the main README.md file.
2. Running multiple containers with Docker compose
When running multiple containers, you could execute the above process multiple times, or a better way is to run a docker compose with predefined configuration file, a docker-compose.yaml.
You'll find an example docker-compose.yaml file here. This configuration file includes a definition for running 3 Kerberos Agents (or containers). By specifying environment variables you can override the internal configuration. To add more Kerberos Agents to your deployment, just copy-paste a service block and modify the name, exposed port, and settings accordingly.
kerberos-agent2:
image: "kerberos/agent:latest"
ports:
- "8082:80"
environment:
- AGENT_NAME=agent2
- AGENT_CAPTURE_IPCAMERA_RTSP=rtsp://x.x.x.x:554/Streaming/Channels/101
- AGENT_HUB_KEY=yyy
- AGENT_HUB_PRIVATE_KEY=yyy
Attaching volumes
As described in 1. Running a single container you can also assign volumes to your docker compose services. A volume can be added to persist the recordings of your Kerberos Agents on the host machine, or to provide more accurate configurations.
When attaching a volume for persisting recordings or mounting configuration files from the host system. the docker-compose.yaml would look like this.
Let's start by creating some directories on your host system. We'll consider 3 Kerberos Agents in this example.
mkdir -p agent1/config agent1/recordings
mkdir -p agent2/config agent2/recordings
mkdir -p agent3/config agent3/recordings
Download the configuration file in each Kerberos Agent configuration directory.
wget https://raw.githubusercontent.com/kerberos-io/agent/master/machinery/data/config/config.json -O agent1/config/config.json
wget https://raw.githubusercontent.com/kerberos-io/agent/master/machinery/data/config/config.json -O agent2/config/config.json
wget https://raw.githubusercontent.com/kerberos-io/agent/master/machinery/data/config/config.json -O agent3/config/config.json
Next we'll add a volumes: section to each Kerberos Agent (service) in the docker-compose-with-volumes.yaml file.
volumes:
- ./agent1/config:/home/agent/data/config
- ./agent1/recordings:/home/agent/data/recordings
We'll repeat that for the other Kerberos Agents as well. You can review the final result over here.
Run the docker compose command by providing a different configuration file name.
docker compose -f docker-compose-with-volumes.yaml up
Please note that you can use a combination of using a configuration file and environment variables at the same time. However environment variables will always override the setting in your configuration file.