The multi-staged nature and repetitive commands for setting up complex compositions
(e.g., containers with files owned by host user's UID:GID,
shared external networks across compositions, etc.)
is the raison d'être for comp.
Some of the key considerations are highlighted below.
For running non-root containers with the host user's UID:GID
(e.g., to avoid permission issues with mounted volumes),
one must grab these from the host, and pass them as env variables,
for docker compose to pick them up.
The same applies to TZ and other host-side configs as well.
Not all of these configs are absolute constants
that maybe added to a .env and never be updated again.
In such cases, we ideally want a "hook" that runs before docker compose is run,
and updates / generates the .env as necessary.
Similar hooks are also desirable to set up external networks
that are shared across multiple compositions.
In such cases, the hook would execute a docker network command
before running docker compose.
comp automatically grabs all external networks in YAML files,
and has a hook to create them if they do not already exist.
comp also has several safeguards that docker compose doesn't provide.
For instance, any non-existent host directories that are mounted to containers
are automatically created by Docker and are owned by root,
even when the --user flag is set!
comp errors out in such cases, requesting the user for explicit action.
Seemed like overkill, when I initially wrote comp.
Why not?
Typical workflows:
-
(Re)start compositions:
./comp down,up tang pihole -
Update repo & restart a composition:
git pull && ./comp pdu piholeNote how we specify verbs
pull,down,upusing just their first characters.
This sequence of verbs also has another shorthand:rorrecreate. -
Checking the status of compositions:
./comp status tang pihole
See comp#L373 for all supported supported flags and options.
Also see Structure & Conventions for optionally customizing compositions via overrides.
| ╭── Compositions \ Supported Archs ─── | amd 64 | arm 64 | arm v7 | risc v64 | |||
|---|---|---|---|---|---|---|---|
|
AirDC++
:443/airdcpp/ |
B | airdcpp |
2.13.2
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Beszel Agent
:45876 |
B | agent |
0.17.0
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Beszel Hub
:24432/beszel/ |
B | beszel |
0.17.0
|
✔️ | ✔️ | ✔️ | ✖️ |
|
bitmagnet
:4433/ |
B C |
postgres
bitmagnet |
17.5...ne
v0.10.0
|
✔️ | ✔️ | ✔️ | ✔️ |
|
Certbot
:80/ |
B | certbot |
v5.2.2
|
✔️ | ✔️ | ✖️ | ✖️ |
|
docker_sock
:44432/docker_sock/ |
A | docker.sock‑proxy |
3.0.7
|
✔️ | ✔️ | ✔️ | ✖️ |
|
ESPHome
:44433/ |
B | esphome |
2025.12.4
|
✔️ | ✔️ | ✖️ | ✖️ |
|
Frigate
:4433/ |
B | frigate |
0.16.3
|
✔️ | ✔️ | ✖️ | ✖️ |
|
Gitea
:443/gitea/ |
B | gitea |
1.25.3-r...s
|
✔️ | ✔️ | ✖️ | ✖️ |
|
HAss
:8123/ |
B | hass |
2025.12.5_2.0.5
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Indexarr
:4432/jackett/ |
B B |
solvarr
jackett |
v3.4.6
0.24.436
|
✔️ | ✔️ | ✔️ |
✖️
✖️ |
|
Jellyfin
:443/jellyfin/ |
B | jellyfin |
10.11.5
|
✔️ | ✔️ | ✖️ | ✖️ |
|
Monitarr
:4432/{lid,rad,son}arr/ |
B B B |
lidarr
radarr sonarr |
3.1.0.4875
6.0.4.10291
4.0.16.2944
|
✔️ | ✔️ | ✔️ |
✖️
✖️ ✖️ |
|
Mosquitto
|
B | mosquitto |
2.0.22
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Navidrome
:443/navidrome/ |
B | navidrome |
0.59.0
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Nextcloud
:443/nextcloud/ |
B B C C B B |
mariadb
valkey fulltextsearch imaginary nextcloud cron |
12.1.2
9.0.1...ne
20251210...59
20251210...59
32.0.3
32.0.3
|
✔️ | ✔️ |
✖️
✔️ ✖️ ✖️ ✔️ ✔️ |
✖️
✔️ ✖️ ✖️ ✖️ ✖️ |
|
ntfy
:25, :44431/, :44433/ |
A | ntfy |
v2.15.0
|
✔️ | ✔️ | ✔️ | ✖️ |
|
OpenVPN
:5432 |
A | vpn |
2.6.16
|
✔️ | ✔️ | ✔️ | ✔️ |
|
Pi‑hole
:53, :44433/pihole/ |
A B |
dnscrypt‑proxy
pihole |
2.1.15
2025.11.1
|
✔️ | ✔️ | ✔️ |
✖️
✔️ |
|
qBittorrent
:443/qbittorrent/ |
A | qbittorrent‑nox |
5.1.3
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Tang
:802/tang/ |
A | tang |
git.02...c8
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Teslamate
:24432/teslamate/ |
B B |
db
teslamate |
18.1...ne
2.2.0
|
✔️ | ✔️ | ✔️ |
✔️
✖️ |
|
Tiny HTTPD
:443/ |
A | tiny-httpd |
2.29-r5
|
✔️ | ✔️ | ✔️ | ✖️ |
|
Traefik
:443, :802, :803, :2443, :4431, :4432 :4433, :4443, :24431, :24432, :24433 :44431, :44432, :44433 :24432/traefik |
B | traefik |
3.6.6
|
✔️ | ✔️ | ✖️ | ✔️ |
|
Unifi
:3478, :8080, :8843/, :10001 |
B X |
mongodb
unifi |
4.4.18
10.0.162
|
✔️ | ✔️ |
✖️
✔️ |
✖️
✖️ |
|
Zigbee2MQTT
:4432/zigbee2mqtt/ |
A | tiny-httpd |
2.7.2
|
✔️ | ✔️ | ✔️ | ✔️ |
Below, we say that a container is a non-root container,
if it allows running the target service as a non-root user,
e.g. using --user with docker run.
Note that this is different from (less secure compared to) running a root-less container, i.e., with a root-less docker daemon.
| A | Trustworthy: Non-root containers with binaries compiled during build, or from OS repos |
|---|---|
| B | Secure: Non-root containers with open-source binaries only |
| C | Open: Root-ed containers with open-source binaries only |
| X | Untrusted: Containers with closed-source binaries |
| (Default Ports) | HTTP (?80?) | HTTPS (?443?) | |||
| Service (80?) |
Internal (4443?) |
Monitor (2443?) |
Service (443?) |
||
| WAN | Shared (*) |
✖️ | 2443 | 443 | |
| Exclusive (*1) |
24431 | 4431 | |||
| LAN | Shared (*2) |
802 | 44432 | 24432 | 4432 |
| Exclusive (*3) |
803 | 44433 | 24433 | 4433 | |
- Shared: Ports for applications that support serving under subpaths
- Exclusive: Ports for containers that do not support subpaths
- Service: Ports for end-user UI
- Monitor: Ports for monitoring applications
- Internal: Ports for other internal applications
All local tweaks should be added to *.override.* files.
-
at the repo root:
versions.global.override.envmay store global version numbers- these are exposed as-is to docker compose
- see
versions.global.envfor the default
static.global.override.envmay store global constants- e.g. ACME configs, ports to be open etc.
- these are exposed as-is to docker compose
- see
static.global.envfor the default
dynamic.global.override.env.shmay generate additional dynamic variables- e.g. as public IP, UID of calling user etc.
- these are (re)computed just before running each a composition
- see
dynamic.global.env.shfor the default
-
within each composition:
versions.global.override.envmay store additional composition-specific version numbers- similar idea as its global counterpart
versions.global.env - see
unifi/versions.envfor an example
- similar idea as its global counterpart
static.override.envmay store additional composition-specific constants- similar idea as its global counterpart
static.global.env - see
gitea/static.envfor an example
- similar idea as its global counterpart
dynamic.override.env.shmay generate additional composition-specific environment variables- similar idea as its global counterpart
dynamic.global.env.sh - see
pihole/dynamic.env.shfor an example
- similar idea as its global counterpart
meta.override.ymlmay:- specify other compositions as prerequisites
- see
airdcpp/meta.ymlfor an example - these are started and validated before starting the composition
- see
- specify other compositions as related
- see
tang/meta.ymlfor an example - these are optionally started and validated after starting the composition
- see
- contain overrides for the
{devices|labels|logging|ports}fragments
(flags used on the command-line will further override this)- see
.github/workflows/config/meta.override.ymlfor an example
- see
- specify messages to be displayed after verb executions
- see
traefik/meta.ymlfor an example
- see
- specify other compositions as prerequisites
compose.override.{yml|yaml}may contain overrides for docker compose- modular overrides may also be specified for individual YAML fragment files:
compose.{devices|labels|logging|ports}.override.{yml|yaml}
- modular overrides may also be specified for individual YAML fragment files:
compose.{pre,post}_hook.override.*.shmay define additional hooks to be run beforedocker compose- see
nextcloud/compose.pre_hook.shfor an example
- see
compose.{up,down,clean}.{pre,post}_hook.override.*.shmay define additional verb-specific hooks to be run- see
monitarr/compose.up.pre_hook.shfor an example
- see
- immediate subdirectories under
config/,data/,extra/, andgenerated/must match the service names withincompose.yml - the directory structure at each of
config/X/Y/...,data/X/Y/...,extra/X/Y/..., andgenerated/X/Y/...must match the absolute path hierarchy/Y/...in the container for serviceX
| Mount mode | Git commit | Comments | |
|---|---|---|---|
| config/ | :ro or - |
✔️ | |
| data/ | :rw |
✖️ | |
| env/ | - | ✔️ | May contain env_files |
| extra/ | - | ✔️ | Only indirect access, e.g. via generated/ |
| generated/ | :ro |
✖️ |