Linux Filesystem Hierarchy
Part of Essentials
This article assumes you're comfortable navigating the command line. If you haven't already, read Command Line Fundamentals first.
Inherit a new server. SSH in. Where's the config file? Where are the logs? Where did the team install that custom application?
On Windows, the answer depends on the vendor, the installer, and sometimes the mood of whoever set it up. On Linux, you already know — because the filesystem hierarchy is standardized. Once you have the map in your head, you'll know exactly where to look on any Linux system, any distribution, any server you'll ever touch.
That mental map is what this article builds.
Where You've Seen This
If you've administered Windows servers, this maps directly: /etc is where service configuration lives (the Linux equivalent of the registry and C:\ProgramData\ combined), /home is C:\Users\, /var/log is the Event Log data on disk, and /opt is C:\Program Files\ for third-party software. The key difference: Linux makes the organizational boundary explicit and consistent by spec — the same layout on RHEL, Ubuntu, and Debian.
If you've worked with Docker or containers, you've already been inside this structure hundreds of times. Every container image uses the same FHS layout — which is why nginx config always lands at /etc/nginx/nginx.conf regardless of the base image.
If you've used any cloud provider's Linux instances (AWS, GCP, Azure), you've been here too. The first thing you do after SSH-ing in is ls /etc/ and cat /etc/os-release. Now you'll know why.
Why Everything Is in the Same Place
Linux distributions look different on the surface — different package managers, init systems, default software. But open a shell on RHEL, Ubuntu, Debian, or Arch and you'll find the same top-level directories in the same places.
That's not coincidence. It's the Filesystem Hierarchy Standard (FHS), maintained by the Linux Foundation. Distributions that comply with FHS follow the same layout conventions, which means the skills you build on one system transfer directly to another.
The Organizing Principle
Every directory in the Linux filesystem has a purpose category, and that category is consistent:
- Configuration that controls behavior →
/etc - Data that changes during operation (logs, state, cache) →
/var - Installed software (binaries, libraries, docs) →
/usr - User-specific files →
/home - Third-party, self-contained apps →
/opt - Runtime data (PIDs, sockets, disappears on reboot) →
/run
The practical implication: when something isn't working, you check /etc for misconfiguration and /var/log for the error. When you need to find a binary, you check /usr/bin, /usr/sbin, or /usr/local/bin. You don't search — you know.
Why This Matters in Production
When production is down, you don't have time to search. An engineer who has this layout internalized goes straight to /var/log/nginx/error.log or journalctl -u myapp. Someone without it finds blindly and burns minutes they don't have. Knowing the hierarchy cold is the difference between a 5-minute diagnosis and a 30-minute one.
The Map
Here's the top-level structure and what each section of the tree is for:
graph LR
ROOT["/\nFilesystem Root"] --> CONFIG["⚙️ /etc\nSystem Configuration"]
ROOT --> VAR["📊 /var\nVariable Data"]
ROOT --> USR["📦 /usr\nInstalled Software"]
ROOT --> HOME["🏠 /home\nUser Home Directories"]
ROOT --> OPT["🔧 /opt\nThird-Party Applications"]
ROOT --> BOOT["🚀 /boot\nBoot Loader & Kernel"]
ROOT --> VIRTUAL["👻 Virtual Filesystems\n/proc /sys /run /dev"]
ROOT --> OTHER["📁 Other\n/tmp /srv /mnt /root"]
VAR --> LOGS["/var/log\nLog Files"]
VAR --> LIB["/var/lib\nApplication State"]
VAR --> CACHE["/var/cache\nCached Data"]
USR --> BIN["/usr/bin\nUser Binaries"]
USR --> SBIN["/usr/sbin\nSystem Binaries"]
USR --> LOCAL["/usr/local\nLocally Installed"]
style ROOT fill:#d69e2e,stroke:#cbd5e0,stroke-width:2px,color:#000
style CONFIG fill:#2d3748,stroke:#68d391,stroke-width:2px,color:#fff
style VAR fill:#2d3748,stroke:#63b3ed,stroke-width:2px,color:#fff
style USR fill:#2d3748,stroke:#fc8181,stroke-width:2px,color:#fff
style HOME fill:#2d3748,stroke:#cbd5e0,stroke-width:2px,color:#fff
style OPT fill:#2d3748,stroke:#d69e2e,stroke-width:2px,color:#fff
style BOOT fill:#2d3748,stroke:#cbd5e0,stroke-width:2px,color:#fff
style VIRTUAL fill:#1a202c,stroke:#718096,stroke-width:2px,color:#9ca3af
style OTHER fill:#1a202c,stroke:#718096,stroke-width:2px,color:#fff
style LOGS fill:#374151,stroke:#63b3ed,stroke-width:1px,color:#fff
style LIB fill:#374151,stroke:#63b3ed,stroke-width:1px,color:#fff
style CACHE fill:#374151,stroke:#63b3ed,stroke-width:1px,color:#fff
style BIN fill:#374151,stroke:#fc8181,stroke-width:1px,color:#fff
style SBIN fill:#374151,stroke:#fc8181,stroke-width:1px,color:#fff
style LOCAL fill:#374151,stroke:#fc8181,stroke-width:1px,color:#fff
ls /
# bin boot dev etc home lib lib64 media mnt opt
# proc root run sbin srv sys tmp usr var
The Directories That Matter Most
-
/etc — System Configuration
Why it matters: This is where you make changes. Every service's configuration file lives here. Edit something in
/etc/and it survives reboots — this is persistent, on-disk configuration.What Lives in /etcls /etc/nginx/ # nginx configuration ls /etc/ssh/ # SSH server configuration cat /etc/hosts # hostname to IP mappings cat /etc/fstab # filesystem mount configuration cat /etc/os-release # distribution identityKey insight: When something isn't working,
/etc/is where you look for misconfiguration. When you need to change behavior,/etc/is where you make the change. -
/var — Variable Data
Why it matters: Anything that changes during normal operation lives here. Logs, application state, package manager databases, mail spools. It's designed to grow over time.
What Lives in /varls /var/log/ # system and application logs ls /var/lib/ # application state databases ls /var/cache/ # cached package data ls /var/spool/ # queued jobs (mail, print, cron)Key insight:
/var/log/is your first stop when diagnosing problems. Disk space issues are almost always caused by/vargrowing unchecked — logs or databases. -
/usr — Installed Software
Why it matters: The vast majority of executables, libraries, and documentation for installed packages lives here. It's meant to be read-only during normal operation — software goes in, the system reads it.
What Lives in /usrls /usr/bin/ # executables for all users (ls, grep, cat...) ls /usr/sbin/ # system admin executables (sshd, nginx, iptables...) ls /usr/lib/ # shared libraries ls /usr/local/bin/ # locally installed executables (your scripts, custom tools) ls /usr/share/ # architecture-independent data, man pagesKey insight: If you install a tool from the package manager, its binary goes in
/usr/bin/. If you compile something yourself or install it manually, put it in/usr/local/bin/— that directory won't be touched by system updates. -
/home and /root — User Directories
Why it matters: Every user gets a home directory. It's where personal files, shell configuration (
.bashrc,.ssh/), and user-specific data live.User Home Directoriesls /home/ # one directory per regular user ls /home/jsmith/ # jsmith's files ls /root/ # root user's home (separate from /home) echo $HOME # your home directory cd ~ # shortcut to go homeKey insight:
/rootis the root user's home, not/home/root. It's intentionally separate. SSH keys live at~/.ssh/authorized_keys— finding these matters when you're debugging auth issues.
-
/opt — Third-Party Applications
Why it matters: Applications that don't follow the FHS layout — vendor software, self-contained apps, things not installed via the package manager — typically land here.
Key insight:
/optis self-contained. Each application gets its own subdirectory with everything it needs. This makes it easy to install, upgrade, and remove without touching the rest of the system. -
/boot — Boot Loader and Kernel
Why it matters: The kernel image, initial RAM disk, and boot loader configuration live here. You rarely touch it directly, but you need to know it exists.
What Lives in /bootls /boot/ # config-5.14.0-284.11.1.el9_2.x86_64 # grub2/ # initramfs-5.14.0-284.11.1.el9_2.x86_64.img # vmlinuz-5.14.0-284.11.1.el9_2.x86_64Key insight: Disk space issues in
/boothappen on systems with many kernel versions installed.rpm -q kernelordpkg --list linux-image*shows what's there;dnf removeorapt autoremovecleans old ones. -
/srv — Service Data
Why it matters: Data served by the system — web server document roots, FTP content. Not every distribution uses this consistently, but it's worth knowing.
Key insight: Some web servers default to
/var/www/html/instead. Check the web server config in/etc/nginx/or/etc/httpd/to find where the document root actually is. -
/mnt and /media — Mount Points
Why it matters: Temporary and removable filesystems get mounted here.
/mntis for manually mounted filesystems (NFS shares, extra disks)./mediais typically for auto-mounted removable media.
Virtual Filesystems: The Exceptions
Not everything under / is on your hard drive. Several directories are virtual filesystems — they exist only in memory and are generated by the kernel at boot. They disappear when the system powers off.
Don't Write to Virtual Filesystems
Writing to /proc or /sys can change kernel behavior immediately — some changes are used intentionally (tuning kernel parameters via /proc/sys/), but doing so incorrectly can destabilize a running system. Never write to these directories unless you know exactly what you're doing.
| Directory | Type | What It Is |
|---|---|---|
/proc |
Virtual (procfs) | Running processes, kernel state, hardware info — everything as files |
/sys |
Virtual (sysfs) | Kernel's view of hardware devices and drivers |
/run |
Virtual (tmpfs) | Runtime data: PID files, sockets, lock files — reset at boot |
/dev |
Virtual (devtmpfs) | Device files — your disks, terminals, random number generators |
/tmp |
Usually tmpfs | Temporary files — cleared on reboot (sometimes cleared on each boot) |
cat /proc/cpuinfo # CPU model, cores, flags
cat /proc/meminfo # detailed memory statistics
cat /proc/version # kernel version string
ls /proc/1234/ # everything about process with PID 1234
cat /proc/1234/cmdline # what command started that process
ls /sys/class/net/ # network interfaces
The /proc trick: Every running process has a directory at /proc/PID/. If you know a process's PID, you can read its open files (/proc/PID/fd/), environment variables (/proc/PID/environ), and more — all without any special tools.
The Modern Symlink Consolidation
On modern systems (RHEL 7+, Ubuntu 20.04+, Debian 10+), you'll notice that several top-level directories are symlinks:
ls -la / | grep "\->"
# lrwxrwxrwx. 1 root root 7 bin -> usr/bin
# lrwxrwxrwx. 1 root root 7 lib -> usr/lib
# lrwxrwxrwx. 1 root root 9 lib64 -> usr/lib64
# lrwxrwxrwx. 1 root root 8 sbin -> usr/sbin
/bin, /sbin, /lib, and /lib64 are now symlinks pointing into /usr/. This is called UsrMerge — a consolidation that simplifies package management and makes systems easier to snapshot and maintain.
What this means practically: /bin/bash and /usr/bin/bash point to the same file. You'll see both paths in documentation — they're interchangeable on modern systems.
"Where Do I Find...?" Scenarios
The answer is almost always /etc.
# Service configuration
ls /etc/nginx/ # nginx
ls /etc/ssh/ # SSH server
ls /etc/systemd/system/ # systemd unit overrides
# System-wide configuration
cat /etc/hosts # hostname resolution
cat /etc/fstab # disk mounts
cat /etc/environment # system-wide environment variables
cat /etc/profile # login shell profile (all users)
# Find a config file when you don't know the name
find /etc -name "*.conf" -type f | grep nginx
Pattern: Start with ls /etc/ and look for a directory named after the service you're investigating.
Always check /var/log first.
ls /var/log/ # everything logs
ls /var/log/nginx/ # nginx access and error logs
ls /var/log/postgresql/ # PostgreSQL logs
# Most important logs
tail -f /var/log/messages # general system messages (RHEL/CentOS)
tail -f /var/log/syslog # general system messages (Debian/Ubuntu)
journalctl -f # systemd journal (all modern systems)
journalctl -u nginx.service # logs for a specific service
Pattern: If you know the service name, look in /var/log/<servicename>/. If nothing's there, use journalctl -u <servicename>.
Depends on how it was installed.
# Find where a binary lives
which nginx # /usr/sbin/nginx
which python3 # /usr/bin/python3
# Show all locations on PATH (catches duplicates)
type -a python3
# python3 is /usr/bin/python3
# python3 is /usr/local/bin/python3
# Find by name if 'which' doesn't find it
find /usr /opt -name "myapp" -type f 2>/dev/null
| Installed via | Binary lives in |
|---|---|
Package manager (dnf, apt) |
/usr/bin/ or /usr/sbin/ |
Manual compilation / make install |
/usr/local/bin/ |
| Third-party installer | /opt/<appname>/bin/ |
| Your own scripts | /usr/local/bin/ (recommended) |
Check /var/lib, /opt, or /srv depending on the app.
# Package-managed services store state here
ls /var/lib/postgresql/ # PostgreSQL data directory
ls /var/lib/docker/ # Docker container storage
ls /var/lib/rpm/ # RPM package database
# Vendor/self-installed applications
ls /opt/myapp/ # self-contained third-party app
# Check the service's config for where it stores data
grep -i "data.dir\|datadir\|data_directory" /etc/postgresql/*/main/postgresql.conf
Pattern: For package-manager-installed services, start with /var/lib/<servicename>/. For everything else, check /opt/ and look at the service's config in /etc/ to find the data directory setting.
Quick Reference
| Directory | Purpose | Persistent? | When to Look Here |
|---|---|---|---|
/etc |
System configuration | ✅ Yes | Misconfiguration, changing service behavior |
/var/log |
Log files | ✅ Yes | Troubleshooting, auditing |
/var/lib |
Application state | ✅ Yes | Database files, package databases |
/var/cache |
Cached data | ✅ Yes | Package cache, disk space issues |
/usr/bin |
User executables | ✅ Yes | Finding binaries installed by packages |
/usr/local/bin |
Local executables | ✅ Yes | Custom scripts, manually installed tools |
/opt |
Third-party software | ✅ Yes | Vendor apps, self-contained tools |
/home |
User home dirs | ✅ Yes | User files, SSH keys, shell config |
/boot |
Kernel and boot loader | ✅ Yes | Boot issues, kernel updates |
/tmp |
Temporary files | ❌ Cleared on reboot | Scratch space, never put important data here |
/proc |
Kernel process info | ❌ Virtual | Live process inspection, kernel tuning |
/sys |
Kernel device info | ❌ Virtual | Hardware introspection, driver tuning |
/run |
Runtime data | ❌ Cleared on reboot | PID files, sockets, lock files |
Practice Exercises
Exercise 1: Build the Mental Map
Without using any commands, answer these questions from memory:
- Where would nginx's configuration file be?
- Where would nginx's access logs be?
- Where would the nginx binary itself be?
- Where would nginx store its runtime PID file?
Then verify your answers using find and ls.
Exercise 2: Trace an Unknown Service
A service called myapp is running on the server. Using only the filesystem hierarchy knowledge from this article, find:
- Its configuration
- Its logs
- Its binary or startup script
- Where it stores data
Hint: Start broad and narrow down.
Solution
# Configuration — start with /etc
ls /etc/ | grep -i myapp
find /etc -name "*myapp*" 2>/dev/null
# Logs — check /var/log and systemd journal
ls /var/log/ | grep -i myapp
journalctl -u myapp --no-pager | tail -20
# Binary — check common locations
which myapp 2>/dev/null
find /usr /opt -name "myapp" -type f 2>/dev/null
# Data — check /var/lib and /opt
ls /var/lib/ | grep -i myapp
ls /opt/ | grep -i myapp
Pattern: When tracing an unknown service, go /etc → /var/log → which → /var/lib and /opt. Systemd can also tell you: systemctl cat myapp.service shows the unit file, which often reveals paths to config, data, and the binary directly.
Exercise 3: Disk Space Investigation
The server's disk is 85% full and growing. Using only filesystem knowledge from this article, identify where to look for the cause.
Solution
# Start: which filesystem is almost full?
df -h
# If it's the root filesystem (/), drill down
du -sh /var/log/* | sort -hr | head -10 # (1)!
du -sh /var/lib/* | sort -hr | head -10
du -sh /opt/* | sort -hr | head -10
# If /var is a separate mount, check inside it
du -sh /var/* | sort -hr | head -10
du -shgives a human-readable summary per directory.sort -hrsorts in human-readable descending order (largest first).head -10limits to the top 10.
Most common culprits (in order):
/var/log/— unchecked logs from a verbose application/var/lib/docker/— container images and layers accumulating/var/lib/postgresql/or other database directories growing/opt/— an application dumping files without cleanup/tmp/— rarely, but possible if it's on the root filesystem
Quick Recap
The Linux filesystem is organized by purpose, not by application:
- /etc — configuration (persistent, edit here to change behavior)
- /var — variable data (logs in
/var/log, state in/var/lib) - /usr — installed software (
/usr/binfor packages,/usr/local/binfor custom) - /opt — self-contained third-party applications
- /proc, /sys, /run — virtual filesystems (kernel-generated, ephemeral)
- /tmp — temporary files, cleared on reboot
When something isn't working: check /etc/ for misconfiguration, /var/log/ for error messages. When you can't find a binary: which it or check /usr/bin/, /usr/sbin/, /usr/local/bin/, and /opt/. When disk is full: du -sh /var/* is your first move.
Further Reading
Command References
man hier— the filesystem hierarchy manual page (built into every Linux system)man find— finding files by path, name, size, and modification timeman df— disk space reportingman du— directory size reporting
Deep Dives
- Filesystem Hierarchy Standard 3.0 — the official specification
- The Linux Documentation Project: Filesystem — detailed explanations of every directory
- UsrMerge on Fedora Wiki — background on why
/bin→/usr/binhappened
Official Documentation
- Red Hat: Linux Filesystem Hierarchy — RHEL filesystem management
- Debian Policy Manual: Filesystem — Debian's filesystem conventions
- The Linux Documentation Project — HOWTOs and guides
What's Next?
You know where things live. Now you need to find specific things efficiently — when you know what you're looking for but not the exact path.
Head to Finding Files to learn find, locate, and which — and the practical patterns for locating any file, config, log, or binary on a system you've never touched before.