When I first started using Docker, it felt like magic. I could spin up apps in isolated containers and tear them down just as easily. But then I hit a wall: how do I make a container see files from my host machine? I wanted to share media with Jellyfin, access configs from outside the container, and persist important data. That’s when I learned about file mapping — and everything changed.
In this article, I’ll walk you through the real power of file mapping in Docker, especially using bind mounts. We’ll look at how this works under the hood, when to use it, and walk through a real use case with Jellyfin to make it stick.
What is File Mapping in Docker?
At its core, file mapping is how you connect files and directories from your host machine (your real server) into your Docker containers (your isolated apps). Docker supports two main ways to do this:
- Volumes: Managed by Docker, stored in
/var/lib/docker/volumes/
. Great for data persistence. - Bind mounts: You specify the exact path on your host to expose to the container. These are great for accessing specific directories, configs, or media.
For more advanced setups — like making your media library available to a Jellyfin container — bind mounts are the tool you want.
Basic Syntax for Bind Mounts
You define bind mounts using the -v
or --mount
flag when running a container.
Using -v
:
docker run -v /host/path:/container/path my-image
Using --mount
(more explicit, either will work, –mount gives you more options):
docker run --mount type=bind,source=/host/path,target=/container/path my-image
Both do the same thing: they make the host directory (/host/path
) available inside the container at /container/path
. This allows you to share resources that are normally not available to a self-contained docker image. In our example… all of your media. When you set up Jellyfin it asks where you store the media, without a mount point into the container there is no way for Jellyfin to see it. So, you say that the files in your /movies/80sCheese/Horror folder should appear inside the container as /media/CheesyStuff. It’s kind of link a desktop shortcut but without your intervention the container would not know about it. Just think through it. Do you want all of your movies inside the container? Maybe binding /movies on your main machine to /media in the container is easier that doing each subfolder (ie /movies/90sImGonnaCry and /movies/IMBATMAN individually).
Real Example: Sharing Media with Jellyfin
Before we move on I want to stress that while it might be a few more steps the media (in this case) doesn’t have to ultimately live on the server, just be accessible to the host computer running the docker containers. You can say have a file server and then mount the media folder to the docker host and from there bind that location to the docker container. It might sound a little scary, and beyond the scope of this post, but it is to say that you want to take something that is available on the docker host and let the docker container use it. There is a way to do whatever you are thinking just don’t get discouraged now because this does not exactly fit the system and network you’re dealing with. It’s just a couple more steps (and more flexible).
Moving right along, for example, say I have all my movies stored at /mnt/media/movies
on my server. I want my Jellyfin container to access them. Here’s how I do it with out using docker compose (Though I always recommend using docker compose).
***Note: Generally when you see some shell command with a ‘\’ it means that the command is to be continued of the next line. Ultimately it’s one long command but written this way for readability. So what you see below is actually docker run -d --name jellyfin
-p 8096:8096
-v /mnt/media/movies:/media/movies
jellyfin/jellyfin
as single line as far as the shell is concerned but you can copy and paste it as is. The shell knows all about the ‘\’ syntax.
docker run -d \
--name jellyfin \
-p 8096:8096 \
-v /mnt/media/movies:/media/movies \
jellyfin/jellyfin
Now, inside the container, Jellyfin can access /media/movies
inside of the container, which is really /mnt/media/movies
on the host machine. In the Jellyfin UI, you just add a new library pointing to /media/movies
and Bob is your Uncle!
Want to mount more folders? No problem just keep adding them to the original command:
-v /mnt/media/music:/media/music \
-v /mnt/media/tv:/media/tv \
You can even bind config files or directories, so you don’t lose your settings when the container is destroyed:
-v /docker/jellyfin/config:/config
This keeps all your Jellyfin settings persistent on the host machine.
Putting it all together, adding the addition mount points, we would end up with:
docker run -d \
--name jellyfin \
-p 8096:8096 \
-v /mnt/media/movies:/media/movies \
-v /mnt/media/music:/media/music \
-v /mnt/media/tv:/media/tv \
-v /docker/jellyfin/config:/config \ jellyfin/jellyfin
Look at you being all Matthew Broderick in /movies/80sAwesomeness/WarGames!
Why Use Bind Mounts?
Here are some common reasons I use bind mounts:
- Media access: Sharing a large media library with media servers like Jellyfin.
- Editable config files: Mapping a config file from your host into the container for easy editing. If you spend time setting up a service you want that service to have the same configuration every time it starts. Remember, docker does not persist data between runs so you want to keep that all important config data outside of the container.
- Log access: Mapping container logs into a directory on your host so you can monitor them with other tools when something goes wrong. Having the logs keeps the dogs at bay (and helps them figure out) when you are on a forum asking for help.
Things to Watch Out For
Bind mounts are powerful, but here are a few things to keep in mind:
- Permissions matter: Your container needs the right permissions to access the host files. Sometimes you’ll need to
chown
orchmod
the host directory. - Paths must exist: Unlike volumes, bind mounts won’t create the directory on the host if it’s missing. Make sure it exists before running the container. If you want to mount that /movies/80sCheese/Horror folder, it has to be there before you spin up the container.
- Portability: Using absolute host paths makes your setup less portable. Docker Compose helps with this (more on that later, if you’re interested).
Using Bind Mounts in Docker Compose (Tip: Use Docker Compose)
If you’re managing multiple services, Docker Compose is the way to go. Here’s a snippet of a docker-compose.yml
for Jellyfin with media directories:
version: "3.9"
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
ports:
- "8096:8096"
volumes:
- /mnt/media/movies:/media/movies
- /mnt/media/music:/media/music- /mnt/media/tv:/media/tv
- ./config:/config
The important bit, for what we are talking about, in the above code is the ‘volumes’ section. This is where we are doing the same thing as before but using a docker compose file to wrap the whole thing up nicely.
***Note: Yaml files, are very sensitive to spacing so make sure it follows to standards.
Now you can just run docker compose up -d
and everything is wired up.
Once you get comfortable with bind mounts, containers stop feeling like isolated black boxes and start acting like true parts of your system. You can blend the flexibility of Docker with the permanence of your host; like pointing Jellyfin at your existing media or editing a config file without rebuilding an image.
It’s one of those things that feels small at first, but opens up massive potential. If you’re already running containers and haven’t used bind mounts yet, now’s the time to start.