A link lets one file or directory be reached through another path. Linux has two kinds, and ln creates both. Symlinks in particular are everywhere on servers: Nginx’s sites-enabled, versioned releases, shared config files.
Symbolic links (symlinks)
ln -s TARGET LINK_NAME
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
ln -s /var/www/releases/2026-11-04 /var/www/current
A symlink is a small file that contains a path. Opening the link opens the target. ls -l shows where it points:
lrwxrwxrwx 1 root root 39 Nov 4 10:00 example.com -> /etc/nginx/sites-available/example.com
Remember the order: target first, link second — the same order as cp.
Relative vs absolute targets
cd /var/www
ln -s releases/2026-11-04 current # relative: resolved from the link's own directory
ln -s /var/www/releases/2026-11-04 current # absolute
Relative symlinks keep working if you move the whole directory tree (or mount it elsewhere, e.g. in a container). Absolute ones are clearer when the link and target live far apart.
Hard links
ln TARGET LINK_NAME
A hard link is a second name for the same file (the same inode). Both names are equal; there’s no “original”. Data is freed only when the last name is removed.
ln report.txt report-copy.txt
ls -li report* # same inode number, link count 2
Symlink vs hard link
| Symbolic link | Hard link | |
|---|---|---|
| Points to | A path | The same inode (data) |
| Directories | Yes | No |
| Across filesystems | Yes | No |
| If the target is deleted | Link breaks (“dangling”) | Data remains reachable |
Shows in ls -l |
link -> target |
Looks like a normal file |
| Typical use | Configs, releases, shortcuts | Backups with deduplication (rsync --link-dest) |
In day-to-day server work you’ll almost always want symlinks.
Replace an existing link
ln -s fails if the link already exists. Use -f (force) — and for links to directories, -n so ln replaces the link instead of creating a new link inside the target directory:
ln -sfn /var/www/releases/2026-11-05 /var/www/current
This one-liner is the heart of zero-downtime deployments: build the new release in its own directory, then switch the current symlink atomically. Rolling back is the same command with the previous release.
Inspect links
ls -l link
readlink link # the stored target
readlink -f link # fully resolved absolute path
realpath link
stat link
Find broken links
find /etc/nginx/sites-enabled -xtype l
find / -xdev -xtype l 2>/dev/null
-xtype l matches symlinks whose target doesn’t exist. Delete them with -delete after reviewing the list.
Remove a link
rm link
unlink link
Careful with trailing slashes on directory symlinks: rm link removes the link; rm -r link/ may follow it and delete the contents of the target. Never add a trailing slash when removing a symlink.
Permissions and ownership
Symlinks always show lrwxrwxrwx; access is decided by the target’s permissions. Change the owner of the link itself (rarely needed) with chown -h. Some services restrict following symlinks for security — Nginx’s disable_symlinks, Apache’s Options FollowSymLinks/SymLinksIfOwnerMatch.
Common uses on servers
- Enable sites/modules:
sites-enabled→sites-available(Nginx, Apache). - Releases:
/var/www/current→ the active release directory. - Shared data across releases:
releases/X/storage→/var/www/shared/storage. - Version switching:
/usr/local/bin/node→ a specific Node version. - Moving data to another disk: move
/var/lib/appto/srv/app, thenln -s /srv/app /var/lib/app(stop the service first).
Quick reference
| Task | Command |
|---|---|
| Symlink | ln -s target link |
| Replace a symlink | ln -sfn target link |
| Hard link | ln target link |
| Where does it point? | readlink -f link |
| Broken links | find DIR -xtype l |
| Remove | rm link (no trailing slash) |
Related: Linux file permissions and Nginx server blocks.