Where things live on a Debian system
Every directory at the root of a Debian system has an owner, and it is not always you. Knowing which of them are yours to write in answers the two questions people actually arrive with: where do I put this script, and why is the configuration for one program in three different places.
Three rules cover nearly all of it.
/usr belongs to the package manager. Everything in it arrived in a .deb and will be
replaced by the next upgrade.
/etc is yours. Packages put their defaults there and then leave your edits alone.
/var is what the machine accumulates while it runs. Logs, caches, queues, databases.
The layout is smaller than it looks
/bin, /sbin and /lib are not directories:
stat -c '%N' /bin /sbin /lib
'/bin' -> 'usr/bin'
'/sbin' -> 'usr/sbin'
'/lib' -> 'usr/lib'
Debian merged them into /usr over several releases, finishing in bookworm. The old paths remain
as symlinks and will keep working, so #!/bin/sh is still correct and every script that uses it
still runs. There is one directory of programs, one of libraries, and three names apiece.
Historically the split meant something: /bin held what was needed to bring the system up far
enough to mount /usr, which might be on another disk or another machine. An initramfs does that
job now. The distinction had been decorative for years before it was removed.
/usr belongs to the package manager
Ask what a package installed and every path is under /usr, except its configuration:
dpkg -L cron | grep -E '/(cron|crontab)$' | sort
/etc/default/cron
/etc/init.d/cron
/etc/pam.d/cron
/usr/bin/crontab
/usr/sbin/cron
/usr/share/bug/cron
/usr/share/doc/cron
/usr/bin for programs anyone runs, /usr/sbin for ones that only make sense as root,
/usr/share for anything that does not depend on the machine's architecture: documentation, icons,
default templates, translations. /usr/lib holds the shared libraries and the helper programs a
package runs but you do not.
Asked in reverse, it explains a file you did not expect to find:
dpkg -S /usr/games/cowsay
cowsay: /usr/games/cowsay
Which package provides a file covers that lookup properly, including the case where the file is not installed yet.
/etc is yours, and Debian records that you changed it
A package's files in /etc are declared as conffiles, which is a promise about upgrades: your
version is kept, and you are asked before anything replaces it.
dpkg-query -W -f='${Conffiles}' cron | awk 'NF {print $1}'
/etc/default/cron
/etc/init.d/cron
/etc/pam.d/cron
/etc/supercat/spcrc-crontab
/etc/supercat/spcrc-crontab-light
Each one was shipped with a checksum, so the package manager can tell an edited file from an untouched one:
echo '# local change' >> /etc/default/cron
dpkg -V cron
??5?????? c /etc/default/cron
c marks it a conffile and 5 says the checksum no longer matches. dpkg -V with no package
name audits every installed package the same way. On a machine somebody else has been
administering, that is the fastest thing to run first.
This is why configuration is spread across several files rather than one. /etc/default/cron
holds Debian's own settings for the service, /etc/init.d/cron starts it, /etc/pam.d/cron
decides how it authenticates, and a *.d directory usually sits beside the main file so a package
or an administrator can drop in a fragment without editing anything shared. /etc/apt/sources.list.d/
and /etc/sudoers.d/ are the two you will meet first.
/var is what accumulates
Nothing in /var arrives with a package in any useful sense: it is what the machine writes while
it runs. It is also the directory that fills up.
/var/logholds logs, whether written by a program directly or by the journal under/var/log/journal./var/cacheholds things that can be regenerated./var/cache/apt/archivesis every.debapt has downloaded;apt cleanempties it./var/libholds state a program cannot regenerate./var/lib/dpkg/statusis the database of what is installed on this system. Lose it and no package manager knows what the machine has./var/tmpis for temporary files that should survive a reboot, where/tmpis for ones that should not.
The distinction between cache and lib is worth keeping straight when disk space runs out.
Deleting /var/cache costs you a download; deleting /var/lib costs you the system.
/usr/local and /opt are the two apt will never touch
Put something in /usr/bin yourself and the next upgrade of the package that owns that path will
overwrite it. /usr/local exists so that cannot happen. It mirrors the layout of /usr beneath it
(/usr/local/bin, /usr/local/share) and no Debian package writes there:
dpkg -S /usr/local/bin/deploy
dpkg-query: no path found matching pattern /usr/local/bin/deploy
That file exists and is executable. dpkg reports no owner because nothing in the package database
claims it. That absence is the guarantee: /usr/local sits outside what an upgrade considers.
/opt differs in shape rather than in ownership. /usr/local is a merged tree, so a program's
binary, its manual page and its data go to three separate directories. /opt gives a program one
directory of its own, /opt/something, laid out however its vendor likes. Software that ships as a tarball and expects to live in one place belongs there; something
you compiled from source belongs in /usr/local, which is where make install puts it by default.
/srv is the least used of the three. It is for data a machine serves to the outside world:
/srv/www, /srv/ftp. Debian creates it empty and has no opinion about what goes inside.
Not everything under / is on a disk
stat -f -c '%n is %T' /proc /sys
/proc is proc
/sys is sysfs
Neither exists on any disk. /proc is the kernel presenting process and system information as
files, and it is where ps and free get their answers. /sys does the same for devices and
drivers. /run holds runtime state like PID files and sockets in memory, so it empties on every
boot by never having been written down.
Writing to a file under /proc or /sys changes a kernel setting until the next reboot. Making
the change permanent means a file in /etc.
Common misconceptions
"/usr stands for Unix System Resources." That expansion was invented afterwards to fit the
letters. It stood for user, because home directories were kept there in the 1970s. They moved to
/home when the disk filled up, and the name stayed.
"I should install my script in /bin because that is where commands live." /bin is a symlink
to /usr/bin, which apt owns. Use /usr/local/bin, which is on PATH for exactly this reason, or
~/bin, which Debian's default ~/.profile adds to PATH when it exists.
"/etc is where all configuration goes." System-wide configuration. A program's per-user
settings go under ~/.config, and the two are read in that order, so your dotfile wins over the
machine's default.
"lost+found is a problem." Every ext4 filesystem has one at its root. It is where fsck puts
fragments it recovers after a bad shutdown, so an empty one is a filesystem working normally.
Go deeper
The layout is specified rather than conventional. hier(7) is the short version and is worth
reading once, though it comes from the manpages package and a minimal Debian does not have it:
apt install manpages, then man 7 hier. The long version is the Filesystem Hierarchy Standard,
and Debian Policy chapter 9 records where Debian departs from it.
dpkg is the tool for asking which package owns a path, and
apt for the rest. File permissions
covers who may write where, which this page has taken for granted throughout.