Linux Filesystem Basics: What Every Directory Is For
Every Linux system arranges its files in the same basic structure, defined by the Filesystem Hierarchy Standard (FHS). This is not arbitrary: each directory exists for a reason rooted in how Unix was designed in the 1970s and how those design decisions have evolved into modern Linux. Understanding the layout means understanding where to find things, where to put things, and why the system behaves the way it does.
The single tree
On Windows, each storage device gets a drive letter: C:, D:, E:. On Linux, there is one tree, and it starts at / (called “root” or “slash”). Every file on every device on the system lives somewhere under /.
# The root of everything
ls /
# bin boot dev etc home lib lib64 lost+found
# media mnt opt proc root run sbin srv sys tmp usr var
# On modern systems, several of these are symlinks
ls -la / | grep '\->'
# lrwxrwxrwx bin -> usr/bin
# lrwxrwxrwx lib -> usr/lib
# lrwxrwxrwx lib64 -> usr/lib64
# lrwxrwxrwx sbin -> usr/sbin
# See the full tree (first two levels)
find / -maxdepth 2 -type d 2>/dev/null | head -40
When you plug in a USB drive or mount a second hard disk, it appears as a directory inside this tree, not as a new root. The directory it appears at is called its mount point.
# See what is mounted where
mount | column -t
df -h
# Example: USB drive mounted at /media/colton/USB-DRIVE
ls /media/colton/USB-DRIVE/
/ (root)
The root directory is the starting point for all paths. It has no parent — cd / takes you to the top and .. from / stays at /.
# Absolute path: starts from /
/etc/ssh/sshd_config
# Relative path: starts from current directory
# (if you are in /etc)
ssh/sshd_config
# / is not the home directory of the root user
# The root user's home is /root
echo ~root
# /root
# Who owns /?
ls -la / | head -2
# total 72
# dr-xr-xr-x. 17 root root 4096 Jun 28 12:00 .
The root directory itself contains only subdirectories. Ordinary files do not live directly in /.
/home — user data
/home contains a subdirectory for each regular user account on the system. Your personal files, configuration, and everything that belongs to you as a user lives under ~/ (which expands to /home/yourusername).
# List home directories
ls /home/
# colton alice bob
# Your home directory
echo $HOME
# /home/colton
ls ~/
# Desktop Documents Downloads Music Pictures Videos
# .bashrc .bash_history .config .local .ssh
# Hidden directories in your home (dot-prefixed)
ls -la ~ | grep '^\.'
# .bashrc -- bash shell configuration
# .bash_profile -- login shell configuration
# .config/ -- application configs (XDG standard)
# .local/ -- local application data and binaries
# .ssh/ -- SSH keys and known_hosts
# .gitconfig -- git user configuration
Why /home exists separately
/home is almost always on its own partition or at least treated as logically separate from the OS. This matters because:
- You can reinstall Linux (wiping
/) without touching/home, keeping all your files and application settings - Disk quotas can be applied per-user in
/home - On multi-user systems,
/homecan be a network share (NFS) that follows users across machines
The root user is the exception: the root account’s home is /root, not /home/root. This means /root is always on the root partition and cannot accidentally be on a network share that becomes unavailable during boot.
# Root user's home
ls /root/
# (contents of root's home directory -- requires sudo to list)
sudo ls /root/
# The /home for root is deliberately separate from /home
# because /home might not be available at early boot
/etc — system configuration
/etc holds system-wide configuration files. Every service, daemon, and system component that needs configuration stores its config files here. All the files are plain text.
# What is in /etc
ls /etc/
# apt/ cron.d/ hosts network/ resolv.conf
# bash.bashrc default/ hostname nginx/ shadow
# crontab environment locale.conf passwd ssh/
# ...
# Key files to know
cat /etc/hostname # this machine's hostname
cat /etc/hosts # static hostname-to-IP mappings
cat /etc/resolv.conf # DNS resolver configuration
cat /etc/fstab # filesystem mount table
cat /etc/passwd # user account information (not passwords)
sudo cat /etc/shadow # hashed passwords (root only)
cat /etc/group # group definitions
cat /etc/os-release # distribution identity
cat /etc/locale.conf # system locale setting
cat /etc/timezone # timezone (or: timedatectl show)
Important /etc subdirectories
ls /etc/ssh/ # SSH daemon and client config
# ssh_config sshd_config ssh_host_*_key
ls /etc/apt/ # APT package manager config (Debian/Ubuntu)
# sources.list sources.list.d/ apt.conf.d/
ls /etc/nginx/ # Nginx web server config (if installed)
# nginx.conf sites-available/ sites-enabled/ conf.d/
ls /etc/systemd/ # systemd configuration
# system/ user/ network/ resolved.conf logind.conf
ls /etc/cron.d/ # system cron jobs
ls /etc/sudoers.d/ # sudo access rules (fragments)
ls /etc/profile.d/ # shell environment scripts run at login
Why /etc exists
Unix designers needed one place for configuration files that were system-wide (as opposed to per-user config in ~/.config). The naming is historical (“et cetera”), but the function is precise: /etc is where the OS and all its services read their configuration. The convention that everything here is plain text makes the entire system configuration auditable, diffable, and versionable with git.
# Many sysadmins track /etc with git
sudo git -C /etc init
sudo git -C /etc add .
sudo git -C /etc commit -m "initial state"
# Then commit after every significant change
/var — variable data
/var holds data that changes during normal system operation. Logs grow here. Package manager databases live here. Mail spools, print queues, database files, and application state all live under /var.
ls /var/
# backups cache lib lock log mail opt run spool tmp
# Log files
ls /var/log/
# auth.log syslog kern.log
# dpkg.log apt/ nginx/
# journal/ (systemd journal)
# Read system logs
sudo tail -f /var/log/syslog # Debian/Ubuntu
sudo journalctl -f # systemd (all distributions)
sudo tail -f /var/log/auth.log # authentication events
# Package manager databases
ls /var/lib/dpkg/ # APT/dpkg state (Ubuntu/Debian)
ls /var/lib/rpm/ # RPM state (Fedora/RHEL)
ls /var/lib/pacman/ # pacman state (Arch)
# These track which packages are installed and at what version
# Package cache (downloaded .deb or .rpm files)
ls /var/cache/apt/archives/ # Ubuntu/Debian: cached .deb files
sudo du -sh /var/cache/apt/archives/ # how much space the cache uses
sudo apt clean # remove cached packages
# Application state and data
ls /var/lib/
# apt/ dpkg/ mysql/ postgresql/ docker/ systemd/
# databases, application state, etc.
Why /var is separate from /usr
/usr contains files that do not change during normal operation — programs, libraries, documentation. /var contains files that do change. This distinction matters for a few reasons:
/usrcan be mounted read-only (common in some embedded or high-security setups)/varcan be on a separate partition, preventing runaway log growth from filling the root filesystem- Backups of
/usrneed not happen often; backups of/var(especially/var/lib) should happen frequently because it contains application state
# Check /var disk usage by subdirectory
sudo du -sh /var/* 2>/dev/null | sort -hr | head -10
# Find what is eating /var disk space
# Clean up old systemd journal logs
sudo journalctl --vacuum-size=500M # keep last 500MB of logs
sudo journalctl --vacuum-time=7d # keep last 7 days of logs
/usr — programs and libraries
/usr (Unix System Resources, or historically “user”) is the largest directory on most systems. It holds the majority of installed software: executables, libraries, header files, documentation, and shared data.
ls /usr/
# bin include lib lib64 local sbin share
# /usr/bin: executable programs for all users
ls /usr/bin/ | head -20
# bash cat chmod cp curl date dd df dig du
# echo find git grep gzip htop ls man mv ...
which python3
# /usr/bin/python3
# /usr/lib: libraries (.so files) used by programs
ls /usr/lib/ | head -10
# gcc python3 systemd x86_64-linux-gnu ...
# /usr/share: architecture-independent data (docs, icons, locale data)
ls /usr/share/ | head -10
# applications bash-completion doc fonts icons locale man ...
# /usr/include: C/C++ header files
ls /usr/include/ | head -5
# stdio.h stdlib.h string.h unistd.h ...
# /usr/local: software installed manually (not by the package manager)
ls /usr/local/
# bin etc include lib sbin share src
/usr/local: manually installed software
/usr/local is the conventional location for software you compile and install yourself, outside the package manager. When you run ./configure && make && sudo make install, the files go to /usr/local/bin, /usr/local/lib, and so on.
This keeps manually installed software separate from package-manager-installed software, so apt remove or dnf remove never accidentally removes something you compiled yourself.
# Example: manually installed software
ls /usr/local/bin/
# node npm hugo custom-tool
# vs package manager installed software
ls /usr/bin/
# bash python3 git curl ...
# /usr/local takes priority in PATH on most systems
echo $PATH
# /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
The /usr merge
On modern distributions, /bin, /sbin, /lib, and /lib64 are all symbolic links into /usr:
ls -la / | grep usr
# lrwxrwxrwx bin -> usr/bin
# lrwxrwxrwx lib -> usr/lib
# lrwxrwxrwx lib64 -> usr/lib64
# lrwxrwxrwx sbin -> usr/sbin
This “UsrMerge” happened on Fedora in 2012 and spread to Debian, Ubuntu, and Arch. The historical split between /bin (essential binaries for early boot) and /usr/bin (the rest) became meaningless on systems where /usr is on the same partition as /. With all binaries in /usr/bin, there is one canonical location for executables.
/opt — optional/third-party software
/opt is for self-contained software packages that are not distributed through the system package manager. Software that installs here keeps all its files together under one subdirectory rather than scattering them across /usr/bin, /usr/lib, and /etc.
ls /opt/
# google/ jetbrains/ cisco/ containerd/
ls /opt/google/
# chrome/
ls /opt/google/chrome/
# chrome chrome-sandbox libffmpeg.so locales/ resources/
# (all Chrome files in one place)
# Compare to how apt-installed software is spread out:
dpkg -L firefox | head -10
# /usr/bin/firefox
# /usr/lib/firefox/firefox
# /usr/lib/firefox/libxul.so
# /usr/share/applications/firefox.desktop
# /usr/share/pixmaps/firefox.png
# (spread across /usr/bin, /usr/lib, /usr/share)
Why /opt exists
The FHS says /opt is for “add-on application software packages.” The intent is that a package in /opt is entirely self-contained: you can install it by extracting an archive to /opt/pkgname/ and uninstall it by deleting that directory. No files outside /opt/pkgname/ are touched.
This is the convention used by:
- Proprietary software that ships a tarball (JetBrains IDEs, some database vendors)
- Software installed by enterprise configuration management tools (Ansible, Chef, Puppet)
- Some container runtimes and cloud agents that want isolation from system packages
# Typical /opt layout for a third-party app
/opt/myapp/
bin/myapp <- executable
lib/ <- libraries
conf/ <- configuration files
data/ <- application data
logs/ <- application logs
# Add to PATH so the executable is findable
echo 'export PATH="/opt/myapp/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
/tmp — temporary files
/tmp is for temporary files that are needed only during the current session or a short period. On most modern systems it is a tmpfs (a RAM-based virtual filesystem), making it very fast but clearing it on every reboot.
# Check if /tmp is tmpfs (RAM-backed)
df -hT /tmp
# Filesystem Type Size Used Avail Use% Mounted on
# tmpfs tmpfs 3.9G 1.2M 3.9G 1% /tmp
# (tmpfs = in RAM; size is usually half of system RAM)
# Or on systems without tmpfs:
# /dev/sda3 ext4 50G ... /tmp
# (disk-backed /tmp persists across reboots but is usually cleared by the OS)
# Create a temporary file
tmpfile=$(mktemp)
echo "scratch data" > "$tmpfile"
echo "$tmpfile"
# /tmp/tmp.XkLm3n9Q
# mktemp for directories
tmpdir=$(mktemp -d)
echo "$tmpdir"
# /tmp/tmp.aB7cDe2F
# Cleanup: either delete manually or let the system handle it
rm -f "$tmpfile"
rm -rf "$tmpdir"
/tmp vs /var/tmp
# /tmp: cleared on reboot (or after a few days on some distros)
# /var/tmp: persists across reboots, cleared after ~30 days
# systemd-tmpfiles handles the cleanup rules
cat /usr/lib/tmpfiles.d/tmp.conf
# d /tmp 1777 root root 10d
# d /var/tmp 1777 root root 30d
# In scripts: use /tmp for short-lived scratch files
# Use /var/tmp when you need the file to survive a service restart
/tmp permissions
/tmp uses the sticky bit (1777), which means anyone can create files and directories in it, but only the owner of a file can delete it. This prevents users from deleting each other’s temporary files.
ls -la / | grep tmp
# drwxrwxrwt ... tmp
# The 't' at the end = sticky bit set
# Create a file in /tmp
touch /tmp/myfile
ls -la /tmp/myfile
# -rw-r--r-- 1 colton colton 0 Jun 28 10:00 /tmp/myfile
# Another user cannot delete it (only you or root can)
sudo -u alice rm /tmp/myfile
# rm: cannot remove '/tmp/myfile': Operation not permitted
Other important directories
A complete picture of the Linux filesystem includes several other directories worth knowing:
# /boot -- kernel, initramfs, and bootloader
ls /boot/
# vmlinuz-6.8.0-45-generic <- Linux kernel
# initrd.img-6.8.0-45-generic <- initial RAM disk
# grub/ <- GRUB bootloader files
# efi/ <- EFI bootloader (on UEFI systems)
# /dev -- device files
ls /dev/ | head -10
# sda sda1 sda2 <- SATA/NVMe drives and partitions
# nvme0 nvme0n1 <- NVMe drives
# tty0 tty1 pts/ <- terminals
# null zero random <- special devices
# /dev/null: discard output (> /dev/null)
# /dev/zero: source of zero bytes
# /dev/random: source of random bytes
# /proc -- virtual filesystem: kernel and process info (not on disk)
cat /proc/cpuinfo | head -10 # CPU information
cat /proc/meminfo | head -5 # memory information
cat /proc/version # kernel version
ls /proc/ | head -5 # numbered dirs = running process IDs
# /sys -- virtual filesystem: hardware and driver info (not on disk)
cat /sys/class/net/eth0/speed # network interface speed
cat /sys/block/sda/queue/rotational # 0=SSD, 1=HDD
# /run -- runtime data (tmpfs, cleared each boot)
ls /run/
# lock/ user/ systemd/ NetworkManager/ ...
# PID files, sockets, and runtime state live here
# /media -- auto-mount point for removable media
ls /media/
# colton/ <- subdirectory per user
ls /media/colton/
# USB-DRIVE MyDisk <- auto-mounted USB drives and optical discs
# /mnt -- manual temporary mounts
# Convention: use /mnt for mounts you manage manually
sudo mount /dev/sdb1 /mnt
ls /mnt/
# /srv -- data served by this system
# Web server files: /srv/www/ or /var/www/ (varies by distro)
# FTP files: /srv/ftp/
# /root -- home directory of the root user
sudo ls /root/
Finding where things live
# Find an executable
which python3
# /usr/bin/python3
whereis nginx
# nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/doc/nginx
# Find all files belonging to a package (Debian/Ubuntu)
dpkg -L nginx | head -10
# /etc/nginx
# /etc/nginx/nginx.conf
# /usr/sbin/nginx
# /usr/share/doc/nginx
# Find which package a file belongs to
dpkg -S /usr/bin/python3
# python3-minimal: /usr/bin/python3
# Fedora equivalent
rpm -qf /usr/bin/python3
# python3-3.12.4-1.fc40.x86_64
# Search for a file anywhere on the system
sudo find / -name "sshd_config" 2>/dev/null
# /etc/ssh/sshd_config
# Use locate for fast searching (if mlocate is installed)
locate sshd_config
Quick reference
| Directory | Purpose | Changes during operation? |
|---|---|---|
/ | Root of the filesystem tree | No |
/home | User files and personal config | Yes (user data) |
/etc | System-wide configuration | On admin changes |
/var | Variable data: logs, caches, databases | Constantly |
/usr | Programs, libraries, documentation | On package changes |
/usr/local | Manually installed software | On manual installs |
/opt | Self-contained third-party software | On manual installs |
/tmp | Short-lived temporary files | Constantly, cleared at boot |
/var/tmp | Temporary files that survive reboots | Frequently, cleared after 30 days |
/boot | Kernel and bootloader | On kernel updates |
/dev | Device files (virtual) | Dynamically by kernel |
/proc | Process and kernel info (virtual) | Real-time |
/sys | Hardware and driver info (virtual) | Real-time |
/run | Runtime data (cleared at boot) | During operation |
/root | Root user’s home directory | On root user activity |
Frequently Asked Questions
Why does Linux use a single directory tree instead of drive letters like Windows?
Linux (and Unix before it) was designed around the idea that everything is a file. Physical drives, network shares, virtual filesystems, hardware devices, and running processes are all represented as files somewhere in the directory tree. Rather than assigning separate root namespaces per device (C:, D:, E:), Linux mounts all storage under a single tree rooted at /. A second hard drive or USB stick is mounted at a directory like /mnt/usb or /media/username/drive, and it appears as a folder inside the same tree. This design makes scripting and system administration more consistent: a path is always a path, regardless of which physical device it lives on.
What is the Filesystem Hierarchy Standard?
The Filesystem Hierarchy Standard (FHS) is a document maintained by the Linux Foundation that specifies what should go in each directory of a Linux system. It defines the purpose of /, /usr, /var, /etc, /home, /tmp, /opt, /srv, /proc, /sys, and others. Following the FHS means that a system administrator familiar with one Linux distribution can navigate another distribution’s filesystem predictably. Most major distributions (Debian, Fedora, Arch, and their derivatives) follow the FHS with minor variations. The FHS exists because Linux inherited a filesystem layout from Unix in the 1970s, and standardizing it makes software that expects files in specific locations work across distributions.
What is the difference between /usr/bin and /bin?
Historically, /bin contained binaries needed for basic system operation during early boot (before /usr was mounted), while /usr/bin contained the majority of user programs. This distinction dates from when /usr could live on a separate disk partition from /. On modern Linux systems, this separation is obsolete: almost all distributions now make /bin a symbolic link to /usr/bin, and /sbin a symbolic link to /usr/sbin. Everything is in /usr. You can verify this with ls -la /bin — on Ubuntu, Fedora, Arch, and Debian, it shows /bin -> usr/bin. The FHS still documents both directories for compatibility, but in practice they are unified on all current distributions.
Why is /etc called “etc” and what goes in it?
The name /etc comes from early Unix where it was literally the “et cetera” directory for files that did not fit elsewhere. Over time it became specifically the directory for system-wide configuration files. Today /etc contains: network configuration (/etc/hosts, /etc/resolv.conf, /etc/network/), user and group databases (/etc/passwd, /etc/shadow, /etc/group), service configuration (/etc/ssh/sshd_config, /etc/nginx/, /etc/mysql/), system settings (/etc/fstab, /etc/locale.conf, /etc/timezone), and package manager configuration (/etc/apt/, /etc/dnf/). Configuration in /etc is plain text, which makes it version-controllable with git and human-readable. The rule is: if a daemon or system service needs a configuration file, it goes in /etc.
What is the difference between /tmp and /var/tmp?
/tmp is for temporary files that do not need to survive a reboot. On most modern Linux systems, /tmp is a tmpfs (a RAM-backed filesystem), so it is fast but limited in size and cleared on every reboot. /var/tmp is for temporary files that should persist across reboots — files that need to survive a system restart but are not permanent enough to belong in a permanent location. In practice: use /tmp for scratch space in scripts and applications where the data is only needed during the current session; use /var/tmp for files that need to persist but will eventually be cleaned up. The systemd-tmpfiles service manages cleanup of both: /tmp files are removed after a short time (10 days by default on some distributions), /var/tmp files are removed after 30 days.
What should go in /opt and who uses it?
/opt is for “optional” or third-party software packages that are self-contained and not distributed through the system package manager. Software installed in /opt typically stores all its files under its own subdirectory: /opt/appname/bin/, /opt/appname/lib/, /opt/appname/etc/. This keeps the software isolated from the system directories and makes it easy to remove (just delete /opt/appname). Examples of software that commonly installs to /opt: Google Chrome (/opt/google/chrome/), JetBrains IDEs (/opt/jetbrains/), some proprietary software (Cisco AnyConnect, some gaming clients). Contrast this with software installed via apt or dnf, which distributes its files across /usr/bin, /usr/lib, /etc, and other standard locations following the FHS.