I started using Docker through a web-based setup, and now more than half of my services run in containers. They currently live under paths such as /srv/docker/jellyfin, but I suspect my organization could be better. What directory layout do you recommend for Compose files, environment variables, bind-mounted configuration, application data, secrets, and backups?
4 Answers
The exact top-level path matters less than being consistent. I keep Compose configuration, persistent application data, environment files, and backups as distinct categories. Bind mounts are convenient because the files are easy to inspect and migrate, but make sure each mount points to a dedicated subdirectory and check ownership and permissions. A reverse proxy can be configured through Compose labels if you want centralized routing and automatic certificate renewal.
I use a simple structure like /containers/{immich,nextcloud,jellyfin}. Each application gets its own Compose file and subdirectories for its bind mounts. This keeps every stack self-contained, makes it easy to version-control the deployment files without exposing secrets, and avoids putting unrelated volumes in one large directory. On some machines, /containers is on a separate NVMe drive, which also makes migration to another operating-system disk easier.
I give each service or Compose stack its own directory. A typical layout might be /opt/apps/media-stack/ with compose/compose.yml, a local .env file, env/ for container-specific settings and secrets, data/ or bind-mounted service directories, and backups/. Keep sensitive files out of version control with .gitignore, and back up the configuration and persistent data that would be needed to restore the service. I also prefer pinning images to a version or digest instead of relying on :latest, since a tag can change over time.
Another reasonable layout is /opt/compose//, with the Compose file and any service-specific bind-mount directories underneath it. For example, Jellyfin might have its Compose file, configuration directory, cache directory, and media mounts kept clearly separate. You can also use a systemd template unit that points to the relevant application directory, so starting a stack is consistent and each service can be enabled independently.

That separation sounds useful, especially for moving services or restoring them on another machine.