Linux filesystem hierarchy notes

2026-01-15 — linux, filesystem

I know /etc and /var but get fuzzy on /usr/local vs /opt vs /usr, or on where a given application actually puts its runtime files. This is my cheat sheet for that, plus notes on how modern Debian differs from the FHS spec in a few places.

/etc — system-wide configuration

Configuration files for system software. These are text files, meant to be edited by admins. The name historically stands for "et cetera" but is better remembered as "everything to configure."

  • Package installs drop their default configs here
  • Local changes go in .d/ subdirectories where supported (e.g. /etc/ssh/sshd_config.d/, /etc/apt/sources.list.d/)
  • Use drop-ins rather than editing package files directly — upgrades won't clobber your changes
  • Worth putting under version control: etckeeper does this automatically with git

/var — variable data

Data that changes during normal operation. Key subdirectories:

  • /var/log/ — log files. journalctl covers systemd services; traditional syslog writes here too.
  • /var/lib/ — persistent application state. Database files, package manager state (/var/lib/dpkg/), etc.
  • /var/cache/ — cached data that can be regenerated. APT's downloaded .deb files live in /var/cache/apt/archives/ and can be safely cleared with apt clean.
  • /var/spool/ — queued data: print jobs, mail, cron jobs.
  • /var/tmp/ — temporary files that should persist across reboots. Unlike /tmp, not cleared on boot.

/tmp — ephemeral temporary files

On modern Debian, /tmp is usually a tmpfs mount — lives in RAM, cleared on reboot. Size is typically half of RAM. Good for short-lived working files; use /var/tmp/ if you need something to survive a reboot.

# Check if /tmp is tmpfs
mount | grep /tmp
# or
findmnt /tmp

/usr — installed programs and data

The bulk of installed software. Originally "user" but now effectively "Unix System Resources." Should be read-only after install.

  • /usr/bin/ — user-facing executables
  • /usr/sbin/ — system/admin executables
  • /usr/lib/ — libraries and internal executables
  • /usr/share/ — architecture-independent data: docs, icons, locale files
  • /usr/include/ — C/C++ header files for development

On Debian 12+, /bin, /sbin, and /lib at the root are now symlinks into /usr/. The merged-usr layout simplifies things but can surprise older scripts that assume they're separate.

/usr/local — locally installed software

For software installed outside the package manager — compiled from source, manual installs, scripts you wrote. Has the same structure as /usr/: bin/, lib/, share/, etc.

Package-managed software should not touch /usr/local/, so it's a clean separation. When I install something manually, it goes here.

/opt — self-contained third-party packages

For software that bundles all its own dependencies and doesn't integrate with the system package layout. Each package gets its own subdirectory: /opt/myapp/ with its own bin, lib, etc. inside.

In practice: vendor-supplied software that ships as a tarball with its own directory structure. Also common for things installed by snap or flatpak on desktop systems (though those have their own locations).

/run — runtime data

Replaces the old /var/run/ (which is now a symlink). PID files, sockets, and other runtime state that should be cleared on boot. It's a tmpfs so it's always in RAM.

# Common things in /run
ls /run/
# sshd.pid, systemd/, nginx/, fail2ban/, etc.

/proc and /sys — kernel interfaces

Both are virtual filesystems — no actual data on disk.

/proc/ exposes kernel and process information. Each running process has a directory at /proc/<pid>/ with its file descriptors, memory maps, etc. Also the home of /proc/sys/ for kernel tunables (adjustable via sysctl).

/sys/ (sysfs) exposes the kernel's view of hardware and drivers. More structured than /proc. Most useful for hardware info and driver parameters.

# Common /proc lookups
cat /proc/cpuinfo
cat /proc/meminfo
cat /proc/net/dev     # network stats

# sysctl tunables
sysctl -a | grep net.ipv4.tcp
sysctl net.ipv4.ip_forward   # check if IP forwarding is on
sysctl -w net.ipv4.ip_forward=1   # set live

Finding where things live

# Which package owns a file
dpkg -S /usr/sbin/nginx

# All files installed by a package
dpkg -L nginx

# Find a command's actual location
which nginx
command -v nginx    # better in scripts

# Find files by name under a path
find /etc -name "nginx.conf"

# Find recently modified files (last 24h)
find /var/log -mtime -1 -type f