The beauty of containers is that you can delete and recreate them in seconds. The flip side is that anything not saved outside the container disappears with it. When a home service loses its configuration after an update, the cause is almost always the same: the data was not where you thought it was. Organising folders, volumes and permissions properly from day one makes every service easy to update, move and back up.
The principle: the container is disposable, the data is not
A container should be destroyable at any moment without losing anything. To achieve that, you need to separate three things:
- The image: the program, pulled from the registry and always rebuildable.
- The configuration: the compose file, environment variables and any settings files.
- The data: databases, files uploaded by users, important caches, keys generated on first start.
Only the last two need to be saved and kept. If the compose file and the data folder are enough to rebuild a service from scratch, the organisation is right.
Bind mounts or managed volumes
There are two main ways to give a container persistent storage.
| Feature | Bind mount | Managed volume |
|---|---|---|
| Where the data lives | In a folder you choose | In an area managed by the container engine |
| Visibility | Browsable as normal files | Needs a command or the internal path |
| Backup | Just include the folder | Needs careful handling |
| Permissions | Fixed by hand | Handled automatically |
For a home server I almost always prefer bind mounts: everything that matters sits in a folder tree I can see, copy and include in a backup with a single line. Managed volumes remain useful for genuinely temporary data.
A predictable folder layout
A simple convention applied to every service saves you from having to remember where everything is:
/srv/services/
immich/
compose.yaml
.env
data/
db/
freshrss/
compose.yaml
data/
Each service has its own folder containing the compose file, the variables file and the data subfolders. Moving a service to another machine becomes mechanical: stop it, copy the folder, start it on the other side. If the media files are large (photos, films) it is normal to keep them on a different disk, but the reference must be written out clearly in the compose file.
Users and permissions
The most common problem with bind mounts is permissions. The process inside the container runs with a certain user ID (UID) and group ID (GID); if the folder on the host belongs to another user, the service cannot write and often fails with unhelpful errors.
Some practical solutions:
- Read the image documentation: many images accept variables such as
PUIDandPGIDto choose the user they run as. - Create a dedicated user on the host for services and give it ownership of the data folders.
- Avoid running everything as root: it works, but a bug or vulnerability in the service would have full access to the mounted files.
- Mount read-only whatever the service only needs to read, by adding
:roto the path. A media server, for example, has no need to modify the films.
Databases: always on a local disk
Many services use SQLite or PostgreSQL. Databases are sensitive to how the file system handles locking and writes to disk. Putting the database folder on a network share (NFS or SMB) is a classic source of corruption that is hard to diagnose, especially with SQLite.
The rule I follow is simple: databases on a local disk, preferably an SSD; large, less critical files can also live on a NAS. If the service allows it, it is useful to split the two into separate folders precisely so you can place them in different locations.
Think about backups from the start
A good layout makes backups almost automatic. With everything under /srv/services, there is only one path to include. Two precautions remain:
- Databases should not be copied while they are writing: stop the service during the copy or export a dump before the backup.
- The
.envfile often contains passwords and keys: it must be saved, but in an encrypted backup, and never published in a repository.
A test to run right away
To check that everything is in order, you can simulate a disaster on an unimportant service: stop it, remove the container and the image, then recreate it from its folder alone. If it comes back with users, settings and data intact, the layout works. If something is missing, better to find out now than during a real failure.
In short
- The container can be thrown away; configuration and data must live outside it.
- Bind mounts in a predictable folder layout simplify backups and migrations.
- UID, GID and read-only mounts solve most permission problems.
- Databases belong on a local disk, not on network shares.
- Recreating a service from scratch is the best test of whether your data is safe.