docker-compose.nix

docker-compose.nix enables nix-defined or imported docker-compose.yml
services with secrets (e.g., sops-nix) integration and optional systemd service.
Nixos has decent support for containers (see oci-containers), and ideally you package the app and write a nixos module to go full native, but sometimes a project's preferred distribution and installation method is by docker-compose. docker-compose.nix is like a halfway point; in its most basic usage, you provide a docker-compose.yml
and it gets copied to /var/lib/[service-name]
. You can either start it yourself with docker-compose up -d
, or you can enable a systemd service to do it for you.
I used to do this via home-manager's home.file
directive, then I wrote this for my systems that don't really need home-manager.
Secrets
Docker itself has support for secrets provided by environment variables or interpolation; this module provides some additional wiring to that effect.
If envSubstFile
is provided, then any VAR=VALUE
definition found therein will be used to replace $VAR
found in docker-compose.yml
with VALUE
. The same substitution is done for files provided by additionalFiles
; the use case here is where a docker-compose definition mounts a separate config file as a volume, and that config format does not allow for environment variable usage for secrets.
Example: frigate
An example for a combined frigate and frigate-notify service definition, both of which actually do allow for environment variables for passwords, but for purposes of demonstration:
# frigate.nix
{ config, ... }:
{
sops.secrets.frigate-env = {};
services.docker-compose = {
enable = true;
services = {
frigate = {
composeFile = ./docker-compose.yml;
envSubstFile = config.sops.secrets.frigate-env.path;
additionalFiles = [
./config-frigate.yml
./config-notify.yml
];
};
};
};
}
sops.secrets.frigate-env
is a multi-line yaml definition:
|
FRIGATE_MQTT_PASSWORD=asdfasdfasdfasdf
FRIGATE_NOTIFY_MQTT_PASSWORD=asdfasdfasdfasdf
FRIGATE_NOTIFY_NTFY_TOKEN=asdfasdfasdfasdf
In docker-compose.yml
, note volume mappings of config-frigate.yml
and config-notify.yml
, which are included in the nix config up above. The relevant lines in docker-compose:
# docker-compose.yml
services:
frigate:
image: ghcr.io/blakeblackshear/frigate:stable
volumes:
- ./config-frigate.yml:/config/config.yml
frigate-notify:
image: ghcr.io/0x2142/frigate-notify:latest
volumes:
- ./config-notify.yml:/app/config.yml
Relevant parts of the config files:
# config-frigate.yml
...
mqtt:
user: frigate
password: $FRIGATE_MQTT_PASSWORD
...
# config-notify.yml
...
mqtt:
username: frigate-notify
password: $FRIGATE_NOTIFY_MQTT_PASSWORD
...
You can specify a secrets file in env_file attribute of docker-compose -- the documentation says the path is relative but in my experience it can also be absolute. If I had gone that route, then I'd probably do
# docker-compose.yml
services:
frigate:
env_file: /run/secrets/frigate-env
frigate-notify:
env_file: /run/secrets/frigate-env
with the appropriate adjustments to the env var names.
Good luck!