<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Bind-Mount – Serverküche</title><link>https://serverkueche.de/tags/bind-mount/</link><description>Bind-Mount – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>de-DE</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Thu, 06 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/tags/bind-mount/index.xml" rel="self" type="application/rss+xml"/><item><title>Docker-Volumes vs. Bind-Mounts: Wo deine Daten wirklich liegen</title><link>https://serverkueche.de/tutorials/docker-volumes-vs-bind-mounts/</link><pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/tutorials/docker-volumes-vs-bind-mounts/</guid><description>Named Volumes oder Bind-Mount? Dieser Grundlagen-Guide erklärt den Unterschied, zeigt beide an echten Beispielen und wann du welches nimmst.</description><content:encoded><![CDATA[<p>Ein Container ist vergänglich: Löschst du ihn, sind seine Daten weg. Damit deine Datenbank, deine Nextcloud-Dateien oder deine Konfiguration ein <code>docker compose down</code> überleben, brauchst du Volumes. Dieser Guide klärt den oft verwirrenden Unterschied zwischen <strong>Named Volumes</strong> und <strong>Bind-Mounts</strong>.</p>
<h2 id="was-bauen-wir">Was bauen wir?</h2>
<p>Kein neuer Dienst diesmal, sondern ein solides Fundament: Am Ende verstehst du, warum Container-Daten normalerweise verschwinden, kennst die zwei Wege, sie dauerhaft zu speichern, und weißt für jeden Dienst, welchen du nimmst. Alle Beispiele sind mit <strong>Docker 29</strong> auf Debian 13 getestet und funktionieren mit jeder aktuellen Docker-Version. Dieses Wissen brauchst du für jedes App-Tutorial – dort taucht in fast jeder <code>compose.yaml</code> ein <code>volumes:</code>-Block auf.</p>
<h2 id="voraussetzungen">Voraussetzungen</h2>
<ul>
<li>Ein Server mit <a href="/tutorials/docker-installieren/">installiertem Docker</a></li>
<li>Grundverständnis von <a href="/tutorials/docker-compose-grundlagen/">Docker Compose</a> (Services, <code>compose.yaml</code>)</li>
<li>Ein Terminal-Zugang zum Server – reine Kommandozeilenübung, keine Web-Oberfläche</li>
</ul>
<h2 id="schritt-für-schritt">Schritt für Schritt</h2>
<h3 id="schritt-1-warum-container-daten-verschwinden">Schritt 1: Warum Container-Daten verschwinden</h3>
<p>Alles, was ein Container in sein eigenes Dateisystem schreibt, lebt nur so lange wie der Container. Das ist gewollt – Container sollen austauschbar sein. Für alles, was bleiben soll (Datenbanken, Uploads, Konfiguration), musst du Docker explizit sagen, wo es <em>außerhalb</em> des Containers landet. Genau dafür gibt es zwei Werkzeuge: <strong>Named Volumes</strong> und <strong>Bind-Mounts</strong>.</p>
<h3 id="schritt-2-named-volumes--von-docker-verwaltet">Schritt 2: Named Volumes – von Docker verwaltet</h3>
<p>Ein Named Volume ist ein Speicherbereich, den <strong>Docker selbst</strong> verwaltet. Du gibst ihm nur einen Namen, den Ablageort bestimmt Docker. Leg eines an:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker volume create sk-demo-vol</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sk-demo-vol</span></span></code></pre></div>
</div>
<p>Jetzt hängen wir das Volume in einen Wegwerf-Container (<code>--rm</code> löscht ihn danach) unter <code>/data</code> ein und schreiben eine Datei hinein:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -v sk-demo-vol:/data alpine:3 sh -c <span class="s2">&#34;echo hallo-von-serverkueche &gt; /data/notiz.txt &amp;&amp; ls -l /data&#34;</span></span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">total 4
</span></span><span class="line"><span class="cl">-rw-r--r--    1 root     root            23 Jul 20 22:31 notiz.txt</span></span></code></pre></div>
</div>
<p>Der Container ist längst weg – die Daten nicht. Wo liegen sie? Frag Docker:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker volume inspect sk-demo-vol --format <span class="s2">&#34;{{ .Mountpoint }}&#34;</span></span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">/var/lib/docker/volumes/sk-demo-vol/_data</span></span></code></pre></div>
</div>
<p>Dieser Pfad gehört Docker. Du <em>kannst</em> ihn als root einsehen, solltest ihn aber nicht direkt bearbeiten:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /var/lib/docker/volumes/sk-demo-vol/_data/notiz.txt</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">hallo-von-serverkueche</span></span></code></pre></div>
</div>
<p>Der Beweis für Persistenz: Ein völlig neuer Container sieht dieselben Daten:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -v sk-demo-vol:/data alpine:3 cat /data/notiz.txt</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">hallo-von-serverkueche</span></span></code></pre></div>
</div>
<p><strong>Merke:</strong> Named Volumes sind der Standard für Anwendungsdaten – Datenbanken, Uploads, alles, was die App selbst verwaltet. Docker kümmert sich um Ort und Rechte, und das Volume überlebt <code>docker compose down</code> (nur <code>down -v</code> löscht es mit).</p>
<h3 id="schritt-3-bind-mounts--ein-ordner-vom-host">Schritt 3: Bind-Mounts – ein Ordner vom Host</h3>
<p>Bei einem Bind-Mount hängst du einen <strong>konkreten Ordner deines Servers</strong> in den Container. Du bestimmst den Pfad, und Änderungen sind sofort auf beiden Seiten sichtbar:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /opt/sk-demo-bind
</span></span><span class="line"><span class="cl">docker run --rm -v /opt/sk-demo-bind:/data alpine:3 sh -c <span class="s2">&#34;echo aus-dem-container &gt; /data/host.txt&#34;</span>
</span></span><span class="line"><span class="cl">ls -l /opt/sk-demo-bind</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">total 4
</span></span><span class="line"><span class="cl">-rw-r--r-- 1 root root 18 Jul 21 00:31 host.txt</span></span></code></pre></div>
</div>
<p>Der Container hat die Datei geschrieben, und sie liegt direkt in deinem Host-Ordner – ohne Umweg über <code>/var/lib/docker</code>. Das ist der Sinn von Bind-Mounts: <strong>Dateien, die du selbst bearbeiten willst.</strong> Klassische Fälle sind Konfigurationsdateien (<code>traefik.yml</code>, <code>nginx.conf</code>) oder eine <code>compose.yaml</code>, die eine Config einliest.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Tipp
  </p>
  <div class="prose-kitchen text-sm">Faustregel: <strong>Named Volume für Daten, die die App verwaltet</strong> (Datenbank, Uploads). <strong>Bind-Mount für Dateien, die du verwaltest</strong> (Konfiguration). Im Zweifel Named Volume – es macht die wenigsten Rechte-Probleme.</div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Achtung
  </p>
  <div class="prose-kitchen text-sm">Häng niemals sensible Host-Pfade blind in einen Container: nicht <code>/</code>, nicht <code>/etc</code>, keine Home-Verzeichnisse – und ganz besonders nicht <code>/var/run/docker.sock</code>. Wer den Docker-Socket eingehängt bekommt, kann beliebige Container starten und ist damit faktisch root auf dem ganzen Host. Mounte immer nur den einen Ordner, den der Dienst wirklich braucht.</div>
</div>
<h3 id="schritt-4-beides-in-der-composeyaml">Schritt 4: Beides in der <code>compose.yaml</code></h3>
<p>In Compose sieht der Unterschied so aus. Ein Named Volume wird unten unter <code>volumes:</code> deklariert und oben per Name referenziert; ein Bind-Mount ist einfach ein Host-Pfad:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">app</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">beispiel/app:1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">app-daten:/var/lib/app               </span><span class="w"> </span><span class="c"># Named Volume (Docker-verwaltet)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./config.yml:/etc/app/config.yml:ro  </span><span class="w"> </span><span class="c"># Bind-Mount (deine Datei, read-only)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">app-daten:</span></span></span></code></pre></div>
</div>
<p>Das <code>:ro</code> am Ende macht den Bind-Mount <strong>read-only</strong> – der Container kann die Konfiguration lesen, aber nicht verändern. Für eingehängte Configs ist das eine gute Angewohnheit.</p>
<h3 id="schritt-5-die-falle--anonyme-volumes">Schritt 5: Die Falle – anonyme Volumes</h3>
<p>Lässt du bei <code>-v</code> den Namen weg (<code>-v /data</code> statt <code>-v name:/data</code>) oder bringt ein Image in seinem Dockerfile eine <code>VOLUME</code>-Anweisung mit, entsteht ein <strong>anonymes Volume</strong> mit einer zufälligen ID. So sieht der erste Fall aus:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --name demo -v /data alpine:3 sh -c <span class="s2">&#34;echo test &gt; /data/x.txt&#34;</span></span></span></code></pre></div>
</div>
<p>Wir lassen den Container hier bewusst ohne <code>--rm</code> laufen – sonst würde Docker das anonyme Volume beim Beenden sofort mitlöschen. Das Problem im Alltag: Solche Volumes bleiben liegen, sammeln sich unbemerkt an, und du findest später nicht mehr heraus, welche Daten wohin gehören:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker volume ls</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">DRIVER    VOLUME NAME
</span></span><span class="line"><span class="cl">local     sk-demo-vol
</span></span><span class="line"><span class="cl">local     9f8c1a2b3c4d5e6f70819a0b1c2d3e4f5061a2b3c4d5e6f70819a0b1c2d3e4f50</span></span></code></pre></div>
</div>
<p>Die kryptische Zeile ist ein anonymes Volume. Den Wegwerf-Container kannst du jetzt entfernen – das anonyme Volume <strong>bleibt</strong> trotzdem liegen:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker rm demo</span></span></code></pre></div>
</div>
<p><strong>Gib deinen Volumes immer einen Namen</strong> – dann bleibt überschaubar, was wozu gehört.</p>
<h3 id="schritt-6-volumes-verwalten">Schritt 6: Volumes verwalten</h3>
<p>Die wichtigsten Befehle im Alltag:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker volume ls           <span class="c1"># alle Volumes auflisten</span>
</span></span><span class="line"><span class="cl">docker volume inspect NAME <span class="c1"># Details, u. a. Mountpoint</span>
</span></span><span class="line"><span class="cl">docker volume rm NAME      <span class="c1"># ein Volume löschen (Daten weg!)</span></span></span></code></pre></div>
</div>
<p>Das Aufräumen unserer Demo heben wir uns bis nach der Backup-Sektion auf – dort brauchen wir <code>sk-demo-vol</code> nämlich noch.</p>
<h2 id="wenn-es-nicht-funktioniert">Wenn es nicht funktioniert</h2>
<div class="troubleshoot not-prose">
<p><strong>Der Container schreibt, aber der Bind-Mount-Ordner auf dem Host bleibt leer.</strong> Du hast einen
relativen Pfad benutzt, der woanders zeigt als gedacht, oder Docker hat den Pfad neu als leeren
Ordner angelegt. Bei <code>docker run</code> Bind-Mounts immer mit <strong>absolutem Pfad</strong> angeben
(<code>/opt/app/config</code>, nicht <code>config</code>). Existiert dieser Host-Pfad noch nicht, legt Docker ihn
stillschweigend als leeren Ordner an – prüfe also mit <code>ls</code>, dass du wirklich den richtigen erwischt
hast. In der <code>compose.yaml</code> sind <code>./</code>-Pfade dagegen völlig in Ordnung – sie sind relativ zur
<code>compose.yaml</code> und damit eindeutig. Achtung außerdem: <code>docker run -v config:/data</code> (ohne <code>/</code> oder
<code>./</code> davor) ist <strong>kein</strong> Bind-Mount, sondern legt ein Named Volume namens <code>config</code> an.</p>
<p><strong><code>Permission denied</code>, sobald der Container in den Mount schreiben will.</strong> Der Prozess im Container
läuft unter einer anderen UID als der Besitzer des Host-Ordners – typisch bei Bind-Mounts. Bei Named
Volumes tritt das selten auf (Docker setzt die Rechte). Bei Bind-Mounts den Ordner dem passenden
Benutzer geben (<code>chown -R 1000:1000 /opt/app/data</code>) oder im Image die <code>user:</code>-Angabe der Compose
nutzen.</p>
<p><strong>Nach <code>docker compose down</code> sind alle Daten weg.</strong> Du hast <code>docker compose down -v</code> benutzt – das
<code>-v</code> löscht die Named Volumes mit. Für einen normalen Neustart <strong>ohne</strong> <code>-v</code> arbeiten. <code>-v</code> bewusst
nur einsetzen, wenn du wirklich bei null anfangen willst.</p>
<p><strong><code>docker system prune</code> hat Daten gelöscht.</strong> <code>docker volume prune</code> bzw. <code>docker system prune --volumes</code> entfernt Volumes, an denen gerade kein Container hängt. Bei <code>docker volume prune</code> sind
<strong>benannte</strong> Volumes standardmäßig geschützt – gelöscht werden nur <strong>anonyme</strong> Volumes; benannte
fallen erst mit <code>--all</code>/<code>-a</code> weg. (Bei <code>docker system prune</code> steuert <code>-a</code>/<code>--all</code> dagegen die
Images, nicht die benannten Volumes.) Ein weiteres starkes Argument fürs Benennen – ein
<code>sk-demo-vol</code> übersteht ein versehentliches <code>docker volume prune</code>, ein anonymes Volume nicht.
Trotzdem <code>prune</code> mit Volumes nur laufen lassen, wenn alle wichtigen Stacks aktiv sind, oder gezielt
mit <code>docker volume rm</code> entfernen.</p>

</div>

<h2 id="wartung--backups">Wartung &amp; Backups</h2>
<p>Volumes sind kein Backup – sie liegen auf <strong>derselben</strong> Festplatte wie dein Server. Fällt die aus, sind Container <em>und</em> Volume weg. Ein Named Volume sicherst du, indem du seinen Inhalt durch einen Wegwerf-Container in ein Archiv packst:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /opt/backups
</span></span><span class="line"><span class="cl">docker run --rm -v sk-demo-vol:/data -v /opt/backups:/backup alpine:3 <span class="se">\
</span></span></span><span class="line"><span class="cl">  tar czf /backup/sk-demo-vol.tar.gz -C /data .</span></span></code></pre></div>
</div>
<p>Zurückspielen geht genauso herum – Archiv rein, ins Volume entpacken. Leg das Ziel-Volume vorher an (<code>docker volume create sk-demo-vol</code>) und stopp den zugehörigen Container, damit dir nichts ins offene Volume schreibt:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -v sk-demo-vol:/data -v /opt/backups:/backup alpine:3 <span class="se">\
</span></span></span><span class="line"><span class="cl">  tar xzf /backup/sk-demo-vol.tar.gz -C /data</span></span></code></pre></div>
</div>
<p>Dieses Archiv – und alle Bind-Mount-Ordner unter <code>/opt</code> – gehören in dein <a href="/tutorials/backups-mit-restic/">verschlüsseltes Off-Site-Backup mit Restic</a>. Damit überlebt deine Datenbank auch einen Totalausfall des Servers.</p>
<p><strong>Im Alltag</strong> lohnt sich Ordnung: Benenne Volumes sprechend (<code>nextcloud-db</code>, nicht <code>db</code>), räume anonyme Volumes gelegentlich auf und prüfe mit <code>docker system df</code>, wie viel Platz deine Volumes belegen – gerade bei Datenbanken und Mediendiensten wächst das über die Zeit spürbar.</p>
<p>Zum Schluss räumst du die Demo wieder ab – jetzt, wo Backup und alle Beispiele durch sind:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker volume rm sk-demo-vol <span class="o">&amp;&amp;</span> rm -rf /opt/sk-demo-bind /opt/backups</span></span></code></pre></div>
</div>
]]></content:encoded></item></channel></rss>