The filesystem hierarchy

What lives in /etc, /usr, /var, /run and /tmp.

Beginner12 min · lesson 3 of 29

Every Linux server arranges its files the same way, so once you know the layout you can find your way around a machine you have never logged into. This lesson walks through that tree on a fresh Ubuntu 26.04 install: where programs, configuration, logs, service data and temporary files live, which directories belong to packages and which to you, and which ones exist only in memory. That knowledge tells you where to look when something breaks, and whether a change you make will survive the next upgrade or reboot.

One tree, and the usr merge

Linux has a single directory tree that starts at /, the root directory. There are no drive letters: extra disks and partitions are attached as directories inside the tree (the storage lesson shows how). The layout follows a published standard, and man file-hierarchy describes it on your own server. Here is the top of the tree on a fresh install:

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -l /
total 60 lrwxrwxrwx 1 root root 7 Apr 20 08:46 bin -> usr/bin drwxr-xr-x 5 root root 4096 Sep 26 20:05 boot drwxr-xr-x 16 root root 4040 Sep 26 20:07 dev drwxr-xr-x 107 root root 4096 Sep 27 10:56 etc drwxr-xr-x 4 root root 4096 Sep 27 10:24 home lrwxrwxrwx 1 root root 7 Apr 20 08:46 lib -> usr/lib drwx------ 2 root root 16384 Sep 18 16:38 lost+found drwxr-xr-x 2 root root 4096 Sep 18 16:30 media drwxr-xr-x 3 root root 4096 Sep 26 20:02 mnt drwxr-xr-x 2 root root 4096 Sep 18 16:30 opt dr-xr-xr-x 170 root root 0 Sep 26 20:07 proc drwx------ 4 root root 4096 Sep 26 20:03 root drwxr-xr-x 34 root root 1020 Sep 27 06:36 run lrwxrwxrwx 1 root root 8 Apr 20 08:46 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Sep 26 20:00 snap drwxr-xr-x 2 root root 4096 Sep 27 10:24 srv dr-xr-xr-x 13 root root 0 Sep 27 04:14 sys drwxrwxrwt 12 root root 320 Sep 27 10:56 tmp drwxr-xr-x 11 root root 4096 Sep 18 16:30 usr drwxr-xr-x 13 root root 4096 Sep 26 20:00 var

The first letter of each line is the type: d for a directory, l for a symbolic link, a pointer to another path. bin, lib and sbin are links into /usr. This is the usr merge: all programs and libraries live under /usr, and the old top-level paths remain as links so that a script calling /bin/bash still works. Ubuntu 26.04 and RHEL 10 are both merged. RHEL keeps 64-bit libraries in /usr/lib64 on every 64-bit processor, so it also has lib64 -> usr/lib64; Ubuntu has that link only on x86_64, for the program loader.

/usr holds what packages install and is best treated as read-only: /usr/bin and /usr/sbin for commands, /usr/lib for libraries and packaged default settings, /usr/share for documentation, manual pages and other data. A package upgrade may replace any file there, so never edit one. Software you build or install by hand goes in /usr/local, which the package manager leaves alone, and self-contained third-party products often use /opt. /srv is for data a server publishes, such as a website, and /boot holds the kernel and the files that start it.

/dev holds devices presented as files: disks such as /dev/vda, terminals, and /dev/null, which discards whatever is written to it. The kernel creates them, and ordinary programs read and write them like files. /mnt and /media are the usual places to attach extra filesystems by hand or, for removable media, automatically.

proc and sys show a size of 0 because the kernel generates their contents on demand, and tmp ends in t instead of x; both come up later in this lesson.

What lives where on Ubuntu 26.04
Installed by packages
/usr/bin
commands
/usr/lib
libraries and packaged default settings
/usr/share
documentation, manual pages, data
Yours, kept across reboots
/etc
configuration and local overrides
/var/lib
service state and databases
/var/log
log files
In memory, gone at reboot
/run
PID files, sockets, runtime state
/tmp
scratch space (tmpfs on Ubuntu 26.04)
/proc and /sys
the kernel's live view
On RHEL 10 /tmp is a directory on the root filesystem, so it survives a reboot.

Configuration in /etc, defaults in /usr/lib

/etc holds the configuration of this particular machine, almost all of it plain text you can read with cat or less. More and more programs split their configuration: the package's defaults go under /usr/lib, and /etc holds only what the administrator, the installer or the cloud image changed. Older programs such as the SSH server still ship their main file in /etc and take changes as drop-in files beside it. Kernel settings loaded at boot show the split (-1 lists one name per line):

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -1 /usr/lib/sysctl.d /etc/sysctl.d
/etc/sysctl.d: 99-cloudimg-ipv6.conf 99-lima.conf README.sysctl /usr/lib/sysctl.d: 10-apparmor.conf 10-coredump-debian.conf 50-default.conf 50-pid-max.conf 55-bufferbloat.conf 55-console-messages.conf 55-ipv6-privacy.conf 55-kernel-hardening.conf 55-magic-sysrq.conf 55-map-count.conf 55-network-security.conf 55-ptrace.conf 55-zeropage.conf

Every file in /usr/lib/sysctl.d came with a package. The files in /etc/sysctl.d are local: 99-cloudimg-ipv6.conf was written when the Ubuntu cloud image was built, and 99-lima.conf by the virtualisation tool that runs this lab machine. To change a setting you add your own file to /etc/sysctl.d, and a file there with the same name as a packaged one replaces it completely. The same split appears across the system: unit files in /usr/lib/systemd/system against /etc/systemd/system, and .d directories such as /etc/ssh/sshd_config.d and /etc/sudoers.d for drop-in files that add to a main file.

The split is what makes upgrades safe. A package upgrade replaces its own files under /usr/lib and leaves yours in /etc alone, and you can see at a glance what was changed on this machine. The price is that no single file tells the whole story: the effective configuration is the defaults plus every override, and the rules for combining them differ by program. The lessons on editing configuration and on systemd show the commands that print the combined result.

/etc also holds files that must stay private, such as /etc/shadow with the password hashes, which only privileged programs can read; "Users, groups and the account files" shows its permissions on Ubuntu and RHEL and what it contains.

Data that changes: /var, /home and /root

/var holds data that grows and changes while the system runs.

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -l /var
total 44 drwxr-xr-x 2 root root 4096 Sep 27 06:01 backups drwxr-xr-x 15 root root 4096 Sep 27 04:18 cache drwxrwxrwt 2 root root 4096 Sep 18 16:37 crash drwxr-xr-x 44 root root 4096 Sep 27 04:18 lib drwxr-xr-x 2 root root 4096 Apr 20 08:46 local lrwxrwxrwx 1 root root 9 Sep 18 16:30 lock -> /run/lock drwxrwxr-x 10 root syslog 4096 Sep 26 20:07 log drwxrwsr-x 2 root mail 4096 Sep 18 16:30 mail drwxr-xr-x 2 root root 4096 Sep 18 16:30 opt lrwxrwxrwx 1 root root 4 Sep 18 16:30 run -> /run drwxr-xr-x 2 root root 4096 Jul 7 08:06 snap drwxr-xr-x 4 root root 4096 Sep 18 16:31 spool drwxrwxrwt 8 root root 4096 Sep 27 10:40 tmp

/var/log holds log files; its group is syslog because the logging daemon writes there, and the lesson on logs covers what is inside. /var/lib holds the persistent state of programs: the package database, systemd's records and, on a real server, a database's data files. That makes it the directory to back up. /var/cache holds data that can be deleted and rebuilt, /var/spool queues of work such as scheduled jobs and outgoing mail, and /var/tmp temporary files that must survive a reboot. lock and run are links to /run, kept for old programs.

People's files live in /home, one directory per user. The administrator's home is /root, outside /home, so root can still log in and repair the machine when /home is on a disk that failed to mount.

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -ld /home/deploy /root
drwxr-x--- 3 deploy deploy 4096 Sep 27 10:24 /home/deploy drwx------ 4 root root 4096 Sep 26 20:03 /root
deploy@rocky10 · Rocky Linux 10.2
$ ls -ld /home/deploy /root
drwx------. 2 deploy deploy 83 Sep 27 10:53 /home/deploy dr-xr-x---. 6 root root 153 Sep 27 10:34 /root

Ubuntu 26.04 creates home directories with mode 0750 (drwxr-x---), RHEL 10 with 0700, so on both, other users cannot look inside yours. /root is closed to ordinary users on both. The trailing dot after the RHEL permissions means the file also carries an SELinux label, RHEL's extra access-control layer.

In memory only: /run, /tmp, /proc and /sys

Some directories are not stored on disk at all. /run is a tmpfs, a filesystem kept in RAM, where services write runtime state such as their process ID files and sockets; it starts empty at every boot. On Ubuntu 26.04 /tmp is a tmpfs too, a change from earlier Ubuntu LTS releases. findmnt -T shows which filesystem holds a path:

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ findmnt -T /tmp
TARGET SOURCE FSTYPE OPTIONS /tmp tmpfs tmpfs rw,nosuid,nodev,nr_inodes=1048576,inode64,usrquota
$ df -h /tmp
Filesystem Size Used Avail Use% Mounted on tmpfs 1.5G 16K 1.5G 1% /tmp
$ findmnt -T /var/tmp
TARGET SOURCE FSTYPE OPTIONS / /dev/vda1 ext4 rw,relatime,discard,errors=remount-ro,commit=30

/tmp is its own tmpfs mount, limited to half of the RAM and emptied at every reboot, while /var/tmp is an ordinary directory on the root filesystem (ext4 on this server). The options leave the size out because the kernel lists a tmpfs size only when it differs from its own default of half the memory, and on this fresh install the two are equal; df -h shows the limit, 1.5G on this machine. The terminals in later lessons come from a second lab server with more memory, whose /tmp line reads size=1994676k: the same half-of-RAM rule, but that machine's memory total has changed by a few KiB since the limit was set at boot, so the kernel no longer sees it as its default and prints it.

Files in /tmp are kept in memory, so they compete with your programs for RAM. A job that stages a multi-gigabyte dump or archive in /tmp fails when the limit is reached, or pushes a server without swap towards running out of memory. Large or long-lived temporary files belong in /var/tmp. An administrator who needs /tmp back on disk can run sudo systemctl mask tmp.mount and reboot.

Two of the tmpfs options matter for security: nosuid makes the kernel ignore the set-user-ID bit on programs stored there, and nodev ignores device files there. The lesson on special permission bits explains why that matters. On both platforms, files in /tmp that have not been used for 10 days are also deleted, and in /var/tmp after 30 days. RHEL 10 does not mount a tmpfs on /tmp:

deploy@rocky10 · Rocky Linux 10.2
$ findmnt -T /tmp
TARGET SOURCE FSTYPE OPTIONS / /dev/vda3 xfs rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -ld /tmp /var/tmp
drwxrwxrwt 12 root root 320 Sep 27 10:56 /tmp drwxrwxrwt 8 root root 4096 Sep 27 10:40 /var/tmp

Both temporary directories are writable by everyone, and the final t, the sticky bit, stops users from deleting or renaming each other's files there.

Shared temporary directories
Every user and service writes to /tmp and /var/tmp, so never use a fixed, guessable name there such as /tmp/backup.tar: another user can create that path first. Let mktemp or mktemp -d choose a random name with private permissions, and keep anything you need tomorrow in your home directory or /var/tmp, not in /tmp. The lesson on files, directories and links shows the symbolic-link trick this protects against.

/proc and /sys are the kernel's live view of itself, presented as files. Nothing in them is stored anywhere; the kernel builds the content at the moment you read it, which is why their files show a size of 0.

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ ls -l /proc/sys/kernel/hostname cat /proc/sys/kernel/hostname
-rw-r--r-- 1 root root 0 Sep 26 20:07 /proc/sys/kernel/hostname web01
$ ls -1 /sys/class/net
eth0 lo

/proc/sys holds the kernel's tunable settings (the ones the sysctl.d files set at boot), and /proc also has a directory for every running process, which the processes lesson explores. /sys describes devices: here the network interfaces, eth0 and the loopback interface lo.

Try this

Take the SSH server as an example and find its packaged unit file and its configuration: ls -l /usr/lib/systemd/system/ssh.service /etc/ssh/sshd_config. Which of the two could a package upgrade replace? Then create two empty files with touch /tmp/fhs-test /var/tmp/fhs-test, run findmnt -T on each, and decide which one would still exist after a reboot on Ubuntu 26.04 (the one on the root filesystem) and which on RHEL 10 (both). Remove them with rm when you are done.

Takeaway

Change configuration in /etc, never in /usr, and put data where its lifetime fits: /var/lib for state, /var/tmp for temporary files that must survive a reboot, /tmp for scratch that may vanish at any boot.

Quick check
01You edited /usr/lib/sysctl.d/50-default.conf on an Ubuntu server to change a kernel setting. After the next package upgrade your change is gone. What should you have done?
Incorrect — Package upgrades leave files in /etc that the administrator changed. That is the whole point of keeping local changes there.
Incorrect — A file in /etc with the name of a packaged file replaces it completely, so every other setting in 50-default.conf would stop being applied. Use a new name.
Correct — Files under /usr/lib belong to packages; /etc/sysctl.d is where local settings go, and upgrades leave it alone.
Incorrect — The package manager runs as root, and a new version of the file replaces the old one whatever its mode.
02A job on an Ubuntu 26.04 server writes temporary work files that must still be there if the machine reboots halfway through. Where should it keep them?
Incorrect — On Ubuntu 26.04 /tmp is a tmpfs in RAM and starts empty after every reboot.
Correct — /var/tmp is meant for temporary files that must survive a reboot; unused files are removed after 30 days.
Incorrect — /run is also a tmpfs. It is emptied at every boot and is reserved for runtime state.
Incorrect — /proc is generated by the kernel on demand. Nothing written by a program is stored there.
03A nightly job on an Ubuntu 26.04 server with 4 GiB of RAM writes a 3 GB database dump to /tmp and fails with "No space left on device", although df -h / shows 30 GB free. Why?
Correct — On Ubuntu 26.04 /tmp is its own tmpfs mount, limited to half of the memory by default, so the root filesystem's free space does not apply to it.
Incorrect — Nothing in the lesson sets a quota, and the free space of / is irrelevant anyway: /tmp is not on the root filesystem here.
Incorrect — The age-based cleanup removes unused files, but a tmpfs of about 2 GiB cannot hold a 3 GB file however empty it is.
Incorrect — The sticky bit only stops users from deleting or renaming each other's files. It sets no size limit.

Related