Symlinks vs. Hardlinks: Unterschiede und Einsatzgebiete
$
/etc
Linux · Dateisysteme · Inodes · DevOps
Symlinks vs. Hardlinks
Unterschiede und Einsatzgebiete

Symlinks und Hardlinks lösen scheinbar dasselbe Problem, funktionieren aber auf völlig unterschiedlichen Ebenen des Dateisystems. Wer den Unterschied auf Inode-Ebene versteht, vermeidet defekte Verweise, baut zuverlässige atomare Deployments und spart mit rsync-Backups erheblichen Speicherplatz, ohne Datenintegrität zu riskieren.

14 Min. Lesezeit ln · ln -s · Inodes · rsync --link-dest ext4 · XFS · Btrfs · Linux

1. Was Symlinks und Hardlinks grundsätzlich unterscheidet

In Linux-Dateisystemen wie ext4, XFS oder Btrfs ist eine Datei technisch nicht identisch mit ihrem Namen im Verzeichnis. Der eigentliche Inhalt und seine Metadaten wie Größe, Berechtigungen, Zeitstempel und Blockzeiger leben in einer Struktur namens Inode. Ein Verzeichniseintrag ist nur ein Name, der auf eine Inode-Nummer verweist. Genau an dieser Trennung setzen sowohl Symlinks als auch Hardlinks an, aber auf fundamental unterschiedliche Weise.

Ein Hardlink ist ein zweiter Verzeichniseintrag, der auf dieselbe Inode zeigt wie das Original. Es gibt dabei keine Unterscheidung zwischen Original und Link, beide sind gleichberechtigte Namen für denselben Inhalt. Ein Symlink dagegen ist eine eigene, winzige Datei mit eigener Inode, deren Inhalt lediglich ein Pfad-String zum Ziel ist. Wer diesen Unterschied verinnerlicht, versteht sofort, warum Hardlinks bestimmte Einschränkungen haben, die Symlinks nicht kennen, und umgekehrt.

Der Befehl ln quelle.txt link.txt erzeugt ohne die Option -s einen neuen Verzeichniseintrag, der exakt auf dieselbe Inode-Nummer zeigt wie quelle.txt. Beide Namen sind danach gleichwertig, keiner ist das "eigentliche" Original. Jede Inode führt intern einen Link-Zähler, der bei jedem neuen Hardlink erhöht wird. Mit stat -c '%i %h' datei sieht man Inode-Nummer und Link-Anzahl direkt, mit ls -li erscheint die Inode-Nummer als erste Spalte in der Ausgabe.

Löscht man einen der beiden Namen mit rm, wird intern nicht der Inhalt gelöscht, sondern nur der Link-Zähler dekrementiert. Erst wenn der Zähler auf null fällt, gibt der Kernel die Datenblöcke tatsächlich frei. Das bedeutet auch: Eine Änderung über einen der Namen ist sofort über alle anderen Namen sichtbar, weil es sich um exakt dieselben Datenblöcke handelt, nicht um eine Kopie.


# Inspect inode number and link count before and after a hardlink
$ ls -li notes.txt
1284712 -rw-r--r-- 1 deploy deploy 512 Jul 12 09:14 notes.txt

$ stat -c 'inode=%i links=%h' notes.txt
inode=1284712 links=1

# Create a hardlink, new directory entry, same inode
$ ln notes.txt notes-backup.txt

$ ls -li notes.txt notes-backup.txt
1284712 -rw-r--r-- 1 deploy deploy 512 Jul 12 09:14 notes-backup.txt
1284712 -rw-r--r-- 1 deploy deploy 512 Jul 12 09:14 notes.txt

$ stat -c 'inode=%i links=%h' notes.txt
inode=1284712 links=2

# Deleting one name only decrements the link counter
$ rm notes.txt
$ stat -c 'inode=%i links=%h' notes-backup.txt
inode=1284712 links=1

Der Befehl ln -s ziel.txt link.txt erzeugt dagegen eine völlig neue Datei mit eigener Inode-Nummer und eigenem Dateityp l. Der Inhalt dieser Datei ist ausschließlich der Pfad-String zum Ziel, nichts weiter. Beim Zugriff auf den Symlink löst der Kernel diesen Pfad erst zur Laufzeit auf, ähnlich einer Weiterleitung. Der Pfad kann relativ oder absolut sein, beides hat unterschiedliche Konsequenzen, wenn Verzeichnisstrukturen verschoben werden.

Ein Symlink besitzt zwar formal eigene Berechtigungen wie lrwxrwxrwx, diese werden vom Kernel für den eigentlichen Dateizugriff jedoch ignoriert, entscheidend sind die Berechtigungen des Ziels. Anders als ein Hardlink kann ein Symlink auf ein nicht existierendes Ziel zeigen, ohne dass ln -s selbst einen Fehler wirft. Das ist gleichzeitig praktisch, weil man Verweise vorbereiten kann bevor das Ziel existiert, und riskant, weil solche Symlinks unbemerkt zu toten Verweisen werden können.


# Create a symlink and inspect its own inode
$ ln -s /var/www/shared/config/env.php current-release/env.php

$ ls -li current-release/env.php
1299981 lrwxrwxrwx 1 deploy deploy 33 Jul 12 09:20 current-release/env.php -> /var/www/shared/config/env.php

# The symlink has its own inode, separate from the target
$ stat -c 'inode=%i type=%F' current-release/env.php
inode=1299981 type=symbolic link

# Resolve the final target path, following the chain if nested
$ readlink -f current-release/env.php
/var/www/shared/config/env.php

$ file current-release/env.php
current-release/env.php: symbolic link to /var/www/shared/config/env.php

4. Warum Hardlinks keine Dateisystemgrenzen überschreiten können

Inode-Nummern sind nur innerhalb einer einzigen Dateisysteminstanz eindeutig. Jedes gemountete Dateisystem, jede Partition, jedes Netzlaufwerk und jedes tmpfs führt seine eigene, unabhängige Inode-Tabelle. Ein Hardlink ist im Kern nichts anderes als die Anweisung "zeige diesen Verzeichniseintrag auf Inode X" innerhalb derselben Tabelle. Liegt Inode X auf einem anderen Gerät, ist diese Referenz bedeutungslos, weil dieselbe Nummer dort etwas völlig anderes bezeichnen kann. Der Kernel verweigert den Versuch mit einem klaren Fehler.

Ein Symlink hat dieses Problem grundsätzlich nicht, weil er lediglich einen Pfad-String speichert und diesen bei jedem Zugriff frisch auflöst. Er kümmert sich nicht um Geräte- oder Mountpoint-Grenzen und funktioniert problemlos über Partitionen, Netzwerkfreigaben und sogar über Container-Grenzen hinweg, solange der Pfad zur Laufzeit auflösbar ist. Für Setups mit separaten Partitionen für /var, /home oder gemounteten Netzwerkspeichern ist das ein entscheidendes Auswahlkriterium.

In der Praxis sieht der fehlgeschlagene Versuch so aus: ln /mnt/backup/archiv.tar.gz /srv/data/archiv.tar.gz quittiert der Kernel mit ln: failed to create hard link: Invalid cross-device link, sofern /mnt/backup und /srv/data auf unterschiedlichen Dateisystemen liegen. Derselbe Befehl mit -s funktioniert dagegen ohne Einschränkung, weil kein Inode-Bezug über die Geräteschranke hinweg nötig ist.

Das klassische Muster für atomare Deployments, wie es Capistrano, Deployer oder eigene Deploy-Skripte umsetzen, basiert vollständig auf Symlinks. Jeder Release landet in einem eigenen Verzeichnis releases/<timestamp>, während ein einzelner Symlink namens current auf den jeweils aktiven Release zeigt. Konfigurationsdateien und persistente Daten wie .env, hochgeladene Medien oder Logs liegen zentral in shared/ und werden in jedem neuen Release per Symlink eingebunden, statt bei jedem Deploy kopiert zu werden.

Der eigentliche Deploy-Wechsel geschieht mit ln -sfn releases/20260712-1200 current. Weil das Umbiegen eines Symlinks intern über einen einzigen rename()-Systemaufruf läuft, ist dieser Schritt atomar: Es gibt keinen Zwischenzustand, in dem current auf gar nichts oder nur teilweise auf den neuen Release zeigt. Nginx oder PHP-FPM sehen entweder komplett den alten oder komplett den neuen Release, nie eine Mischung. Ein Rollback ist ebenso trivial, der Symlink wird einfach wieder auf den vorherigen Release-Ordner zurückgesetzt.


# deploy-pipeline.yaml: atomic release switch via symlink
steps:
  - name: Upload new release
    run: rsync -az --delete build/ deploy@host:/var/www/releases/${RELEASE_ID}/

  - name: Link shared resources into the new release
    run: |
      ssh deploy@host '
        ln -sfn /var/www/shared/.env /var/www/releases/${RELEASE_ID}/.env
        ln -sfn /var/www/shared/media /var/www/releases/${RELEASE_ID}/pub/media
        ln -sfn /var/www/shared/var/log /var/www/releases/${RELEASE_ID}/var/log
      '

  - name: Atomic switch, single rename() syscall, zero downtime
    run: ssh deploy@host 'ln -sfn /var/www/releases/${RELEASE_ID} /var/www/current'

  - name: Reload PHP-FPM
    run: ssh deploy@host 'sudo systemctl reload php8.4-fpm'

Für inkrementelle Backups sind Hardlinks das Werkzeug der Wahl. Mit rsync --link-dest=vorheriges-backup/ kopiert rsync nur Dateien, die sich seit dem letzten Lauf tatsächlich geändert haben, alle unveränderten Dateien werden stattdessen als Hardlink auf die Kopie im vorherigen Backup-Verzeichnis angelegt. Das Ergebnis ist ein vollständiger, eigenständig durchsuchbarer Verzeichnisbaum pro Backup, obwohl auf der Festplatte nur die tatsächlich geänderten Dateien zusätzlichen Speicherplatz belegen.

Eine lokale Alternative ohne Netzwerktransfer ist cp -al, das ein komplettes Verzeichnis als Hardlink-Kopie dupliziert, ideal für schnelle Snapshots vor riskanten Änderungen. Wichtig ist dabei eine Regel ohne Ausnahme: Da alle Backup-Generationen dieselbe Inode und damit dieselben Datenblöcke teilen, verändert jede In-Place-Bearbeitung einer Datei in einem Snapshot automatisch auch alle anderen Snapshots. Tools wie rsync umgehen das, indem sie bei Änderungen konsequent neue Dateien statt In-Place-Schreibvorgänge erzeugen.


#!/usr/bin/env bash
set -euo pipefail

BACKUP_ROOT="/srv/backups/webshop"
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
LATEST_LINK="${BACKUP_ROOT}/latest"

mkdir -p "${BACKUP_ROOT}/${TIMESTAMP}"

# Unchanged files become hardlinks to the previous backup,
# only genuinely changed files consume new disk space
rsync -a --delete \
  --link-dest="${LATEST_LINK}" \
  /var/www/current/ \
  "${BACKUP_ROOT}/${TIMESTAMP}/"

# Point "latest" at the newest backup for the next incremental run
ln -sfn "${BACKUP_ROOT}/${TIMESTAMP}" "${LATEST_LINK}"

echo "[OK] Backup ${TIMESTAMP} complete"
du -sh "${BACKUP_ROOT}/${TIMESTAMP}"

Ein broken Symlink (auch dangling reference genannt) entsteht, sobald das Ziel gelöscht, umbenannt oder auf ein anderes Dateisystem verschoben wird, während der Symlink selbst unverändert bestehen bleibt. Besonders häufig passiert das bei Magento-Setups mit symlink-basiertem pub/media, bei Docker-Volume-Mounts, die noch nicht eingehängt sind, oder bei atomaren Deployments, wenn das Shared-Verzeichnis in falscher Reihenfolge angelegt wird. Relative Symlinks brechen zusätzlich, wenn sie aus einem anderen Arbeitsverzeichnis heraus aufgelöst werden als ursprünglich beabsichtigt.

Zur Diagnose eignet sich find /var/www -xtype l, das gezielt Symlinks findet, deren Ziel nicht mehr existiert. In den meisten Terminals mit aktivierten ls-Farben erscheinen broken Symlinks zusätzlich blinkend oder in Rot. Verwirrend für viele Admins: ls -l auf den Symlink selbst funktioniert immer, weil der Verzeichniseintrag ja existiert, erst ein tatsächlicher Zugriff über den Link liefert No such file or directory. Ein regelmäßiger Cronjob mit find -xtype l und Alarmierung verhindert, dass solche Verweise unbemerkt in Produktion landen.


{
  "scan_root": "/var/www/current",
  "scanned_at": "2026-07-12T06:15:03+02:00",
  "broken_symlinks_found": 2,
  "entries": [
    {
      "path": "pub/media/catalog/product/placeholder.jpg",
      "target": "/var/www/shared/media/catalog/product/placeholder.jpg",
      "reason": "target_missing"
    },
    {
      "path": "var/log/exception.log",
      "target": "../shared/var/log/exception.log",
      "reason": "relative_path_resolved_from_wrong_cwd"
    }
  ],
  "recommended_action": "run deploy-shared-init.sh before switching current symlink"
}

8. Berechtigungen, Ownership und Sicherheit bei Links

Die formal am Symlink sichtbaren Berechtigungen lrwxrwxrwx sind für den Kernel bei Dateizugriffen bedeutungslos, entscheidend sind ausschließlich die Berechtigungen des Ziels. Ein chmod auf einen Symlink wirkt in der Standardeinstellung sogar auf das Ziel durch, nicht auf den Link selbst, weshalb explizite Tools mit der Option -h beziehungsweise --no-dereference notwendig sind, um wirklich den Link zu verändern statt versehentlich sein Ziel. Die Ownership des Symlink-Eintrags selbst bestimmt lediglich, wer ihn löschen oder ersetzen darf.

Sicherheitsrelevant sind vor allem sogenannte Symlink-Angriffe in world-writable Verzeichnissen wie /tmp: Ein Angreifer ersetzt in einem Race-Condition-Fenster zwischen Prüfung und Zugriff eine erwartete Datei durch einen Symlink auf ein sensibles Ziel. mktemp statt fester Pfade sowie das Öffnen mit O_NOFOLLOW verhindern das zuverlässig. Bei Hardlinks gibt es ein anderes Risiko: Da ein Hardlink dieselben Daten unter neuem Namen zugänglich macht, kann er theoretisch genutzt werden, um Zugriff auf Dateien zu behalten, deren ursprünglicher Pfad entfernt wurde. Der Kernel-Schutz fs.protected_hardlinks verhindert seit Linux 3.6, dass Nutzer Hardlinks auf Dateien anlegen, die ihnen nicht gehören.

9. Symlinks vs. Hardlinks im direkten Vergleich

Die Wahl zwischen Symlink und Hardlink ist selten Geschmackssache, sondern ergibt sich fast immer zwingend aus den technischen Eigenschaften beider Verweisarten. Die folgende Tabelle fasst die entscheidenden Unterschiede für den Praxiseinsatz zusammen.

Merkmal Hardlink Symlink Praxis-Auswirkung
Über Dateisystemgrenzen hinweg Nicht möglich (Invalid cross-device link) Problemlos, auch über Mountpoints hinweg Bei separaten Partitionen bleibt nur der Symlink
Verzeichnisse verlinken Nicht erlaubt (verhindert Loops im Baum) Uneingeschränkt möglich shared/media als Verzeichnis nur per Symlink
Speicherplatz bei Duplikaten Kein zusätzlicher Speicherplatz (ein Inode) Zusätzlicher kleiner Verweis-Datenblock Backups mit rsync --link-dest sparen massiv
Atomarer Editor-Save (z. B. vim) Verweis bricht, Editor erzeugt neue Inode Bleibt erhalten, Pfad ändert sich nicht Config-Symlinks überleben Editor-Saves zuverlässig
Ziel wird gelöscht Daten bleiben, solange Link-Zähler > 0 Wird zum broken Symlink (dangling) Symlinks brauchen aktives Monitoring auf Reihenfolge

In der Praxis ergänzen sich beide Mechanismen, statt in direkter Konkurrenz zu stehen. Symlinks lösen Verweisprobleme über Verzeichnis- und Dateisystemgrenzen hinweg, etwa bei geteilter Konfiguration in Deploy-Pipelines. Hardlinks lösen Speicherplatzprobleme innerhalb eines Dateisystems, etwa bei generationsbasierten Backups. Wer beide Mechanismen kennt, wählt bewusst statt aus Gewohnheit immer ln -s zu verwenden, nur weil es der bekanntere Befehl ist.

Mironsoft

Deployment-Infrastruktur, Backup-Strategien und Server-Automatisierung

Zuverlässige Deployments und Backups für euren Magento-Stack?

Wir bauen atomare Deploy-Pipelines mit sauberer Symlink-Struktur und richten platzsparende, revisionssichere Backup-Routinen mit rsync und Hardlinks für eure Infrastruktur ein.

Deploy-Pipelines

Atomare Releases mit releases/current-Symlink-Struktur und shared config

Backup-Strategie

Hardlink-basierte Backups mit rsync --link-dest, revisionssicher aufgesetzt

Monitoring

Automatisierte Prüfung auf broken Symlinks vor jedem Produktionswechsel

10. Zusammenfassung

Symlinks vs. Hardlinks ist letztlich kein Wettbewerb, sondern eine Frage der richtigen Zuordnung zum jeweiligen Problem. Hardlinks teilen sich eine Inode und damit dieselben Datenblöcke, funktionieren deshalb nur innerhalb eines Dateisystems, kennen keine defekten Verweise und sparen bei Backups massiv Speicherplatz. Symlinks sind eigenständige Dateien mit einem Pfad-String als Inhalt, funktionieren über Dateisystem- und sogar Netzwerkgrenzen hinweg, können Verzeichnisse referenzieren und sind das Rückgrat jedes atomaren Deploy-Mechanismus mit current-Symlink.

Der entscheidende Praxis-Hebel ist, beide Mechanismen bewusst und nicht aus Gewohnheit einzusetzen: ln -s für geteilte Konfiguration und atomare Release-Wechsel, klassischer ln beziehungsweise rsync --link-dest für platzsparende Backup-Generationen. Wer zusätzlich regelmäßig auf broken Symlinks prüft, bevor ein neuer Release live geschaltet wird, vermeidet die häufigste Fehlerquelle in symlink-basierten Deploy-Pipelines.

Symlinks vs. Hardlinks: Das Wichtigste auf einen Blick

Inode-Grundprinzip

Hardlink = zweiter Name für dieselbe Inode. Symlink = eigene Inode mit einem Pfad-String als Inhalt.

Dateisystemgrenzen

Hardlinks scheitern mit Invalid cross-device link außerhalb des eigenen Dateisystems. Symlinks funktionieren überall.

Atomare Deployments

ln -sfn releases/<id> current ist ein einziger rename()-Syscall, komplett atomar, sofortiges Rollback möglich.

Backups mit Hardlinks

rsync --link-dest spart Speicherplatz, indem unveränderte Dateien als Hardlink auf das Vorgänger-Backup gelegt werden.

11. FAQ: Symlinks vs. Hardlinks

1Was ist der Unterschied zwischen Symlink und Hardlink?
Hardlink = zweiter gleichberechtigter Name für dieselbe Inode. Symlink = eigene Datei mit eigener Inode, deren Inhalt nur ein Pfad-String zum Ziel ist.
2Warum keine Hardlinks über Partitionsgrenzen?
Inode-Nummern sind nur innerhalb eines Dateisystems eindeutig. Auf einem anderen Gerät ist dieselbe Nummer bedeutungslos, der Kernel meldet Invalid cross-device link.
3Warum kein Hardlink auf ein Verzeichnis?
Verzeichnis-Hardlinks würden Zyklen im Baum ermöglichen und viele Tools in Endlosschleifen laufen lassen. Für Verzeichnisse gibt es deshalb nur Symlinks.
4Zieldatei eines Hardlinks gelöscht, was passiert?
Nur der Link-Zähler der Inode wird dekrementiert. Solange ein Name übrig bleibt, sind die Daten vollständig erhalten.
5Zieldatei eines Symlinks gelöscht, was passiert?
Der Symlink bleibt als Datei bestehen, zeigt aber ins Leere (broken Symlink). Zugriff liefert No such file or directory.
6Wie erkenne ich broken Symlinks?
find /pfad -xtype l findet gezielt Symlinks mit fehlendem Ziel. Farbige ls-Konfigurationen markieren sie zusätzlich visuell.
7Warum Hardlinks für Backups?
rsync --link-dest legt unveränderte Dateien als Hardlink auf das Vorgänger-Backup, spart massiv Speicherplatz bei voll durchsuchbaren Backup-Generationen.
8Wie funktioniert der current-Symlink-Deploy?
ln -sfn releases/ current ist ein einziger rename()-Syscall, damit atomar. Kein Zwischenzustand, sofortiges Rollback durch Zurücksetzen des Symlinks möglich.
9Hardlink auf ein Verzeichnis möglich?
Für normale Nutzer nein, der Kernel verweigert das grundsätzlich. Nur . und .. sind intern verwaltete Ausnahmen.
10Wie viele Hardlinks hat eine Datei?
stat -c '%h' datei oder die zweite Spalte von ls -l zeigt die Anzahl der Verzeichniseinträge, die auf dieselbe Inode verweisen.