I'm still getting familiar with Docker and manage my containers through a graphical interface. I'm trying to deploy Maintainerr with this configuration, where the application is supposed to store its data in /opt/data inside the container:
services:
maintainerr:
image: ghcr.io/maintainerr/maintainerr:latest
user: 1000:1000
volumes:
- type: bind
source: /mnt/maintainerr
target: /opt/data
environment:
- TZ=Europe/Brussels
ports:
- 6246:6246
restart: unless-stopped
However, the container logs show `mkdir: can't create directory '/opt/data/ui': Permission denied`. I tried changing the mount to `/mnt/maintainerr:/data`, and the container starts, but no files appear in `/mnt/maintainerr`. After restarting or recreating the stack, my settings are gone. How should I configure the persistent storage correctly, and what does the permission error mean?
3 Answers
The path on the left is the host path, while the path on the right is where the application expects to find its data inside the container. Maintainerr is writing to `/opt/data`, so mapping your host folder to `/data` does not help unless the application is configured to use `/data` instead. Keep the target as `/opt/data` and fix the permissions on the host directory. Since the container runs as UID 1000 and GID 1000, create the directory if needed and make that user its owner, for example: `sudo mkdir -p /mnt/maintainerr && sudo chown -R 1000:1000 /mnt/maintainerr`. Then redeploy the container.
You can also use a named Docker volume if you do not need the files directly under `/mnt/maintainerr`, for example `- maintainerr_data:/opt/data` and then declare `volumes: maintainerr_data:` at the bottom of the compose file. Docker will preserve that volume across container restarts and redeployments. For easier backups and direct access, though, the bind mount is usually more convenient—just correct the host-directory ownership first.
What you currently have is a bind mount, not an automatically managed named volume. That is perfectly fine for persistence, but the application must write to the container path that is mounted. With `/mnt/maintainerr:/data`, `/data` may remain empty because Maintainerr is still using `/opt/data`; any files written to `/opt/data` then disappear when the container is replaced. Use `- /mnt/maintainerr:/opt/data` and ensure the host directory is writable by UID 1000.
The fact that the container starts with the `/data` mapping only means that path itself is writable or unused. It does not confirm that the application is storing its database and settings there.

That explains it—the target path is inside the container, not another host location. I’ll update the ownership of `/mnt/maintainerr` and keep the mount pointed at `/opt/data`.