---
tags: [linux, tooling]
verified: 2026-09-02
---

# Linux — файловая иерархия и FHS

## Обзор

Файловая иерархия Linux — это результат 50 лет эволюции UNIX, зафиксированный (с оговорками) в стандарте FHS. В отличие от FreeBSD, где иерархия определяется одним проектом и обслуживает чёткое разделение «base system vs. порты», в Linux FHS — это компромисс между десятками дистрибутивов с разной философией. Стандарт описывает то, что *уже сложилось*, а не то, что *должно быть* — FHS явно позиционирует себя как «trailing standard».

Практический смысл понимания иерархии: она определяет, где искать конфиги, куда ставить софт, какие пути жёстко закодированы в скриптах и unit-файлах, и что произойдёт при обновлении системы. Дополнительно Linux активно использует виртуальные файловые системы (/proc, /sys, cgroup fs) как основной интерфейс между userspace и ядром — это принципиальное архитектурное отличие от FreeBSD, где ту же роль выполняют sysctl и ioctl.

## Архитектура

### FHS 3.0: что стандартизировано и что нет

FHS 3.0 (оригинально опубликован Linux Foundation в июне 2015, переиздан FreeDesktop.org в ноябре 2025 — они взяли на себя поддержку спецификации) определяет два ортогональных измерения для классификации данных:

**Shareable vs. unshareable** — можно ли разделять между хостами (пример: /usr — shareable, /etc — unshareable). **Static vs. variable** — изменяются ли данные без вмешательства администратора (пример: /usr — static, /var — variable).

Эта матрица задаёт логику разделения:

```text
                 shareable      unshareable
    static       /usr           /etc, /boot
    variable     /var/mail      /var/run, /var/lock
```

На практике это означает: /usr можно теоретически монтировать по NFS и шарить между машинами (static + shareable), а /var/run содержит PID-файлы конкретного хоста (variable + unshareable). Сегодня NFS-шаринг /usr — редкость, но принцип разделения по-прежнему определяет, почему конфиги живут в /etc, а бинарники — в /usr.

FHS стандартизирует корневые каталоги и их назначение, но *не* стандартизирует: внутреннюю структуру /etc (каждый дистрибутив организует это по-своему), содержимое /srv (FHS говорит «site-specific data», но не уточняет), конкретные имена файлов внутри каталогов.

### Ключевые каталоги и их логика

**/etc** — host-specific конфигурация. Только конфиги, никаких бинарников. В Linux здесь живёт всё: от /etc/fstab до /etc/systemd/, от /etc/network/ до /etc/apt/. Нет разделения на «base system config» и «ports config» как в FreeBSD (/etc vs. /usr/local/etc) — в Linux пакетный менеджер ставит конфиги в /etc/ независимо от происхождения пакета.

**/usr** — основная масса установленного ПО: бинарники (/usr/bin, /usr/sbin), библиотеки (/usr/lib), хедеры (/usr/include), архитектурно-независимые данные (/usr/share). Предполагается read-only после установки. /usr/local — для софта, установленного вручную (make install), а не через пакетный менеджер. На практике в Linux /usr/local используется реже, чем в FreeBSD, потому что большинство софта ставится через пакетные менеджеры напрямую в /usr.

**/var** — variable data: логи (/var/log), кеши (/var/cache), спулы (/var/spool), данные приложений (/var/lib). Ключевая особенность: /var/lib/<package> — каноническое место для persistent state пакетов. Например, /var/lib/docker, /var/lib/postgresql, /var/lib/dpkg.

**/opt** — для стороннего софта, который хочет жить в своём собственном поддереве: /opt/<vendor>/<package>. Типичные обитатели: проприетарные продукты (Google Chrome ставится в /opt/google/chrome), крупные standalone-приложения. Конфиги для /opt-софта идут в /etc/opt/<package>.

**/srv** — данные, обслуживаемые системой: web-контент (/srv/www или /srv/http), FTP (/srv/ftp). На практике используется непоследовательно — многие ставят web root в /var/www (Debian/Ubuntu) или вообще в /home.

**/run** — tmpfs, монтируется в самом начале загрузки. Volatile runtime data: PID-файлы, сокеты, lock-файлы. Появился как замена /var/run, который мог быть недоступен на ранних этапах boot (когда /var — отдельный раздел). FHS 3.0 определяет /run как стандарт, /var/run — как симлинк на /run для обратной совместимости.

**/tmp** — временные файлы. Может быть tmpfs (и часто является — systemd монтирует tmpfs на /tmp по умолчанию). Программы не должны рассчитывать на сохранение файлов между перезагрузками. Для файлов, которые должны пережить ребут, есть /var/tmp.

**/boot** — ядро (vmlinuz), initramfs, конфигурация загрузчика. На EFI-системах /boot/efi или /efi содержит EFI System Partition.

### UsrMerge: слияние / и /usr

Исторически бинарники жили в двух местах: «необходимые для загрузки» в /bin, /sbin, /lib (на корневом разделе) и «остальные» в /usr/bin, /usr/sbin, /usr/lib (на отдельном разделе, который мог монтироваться позже). С появлением initramfs необходимость в этом разделении отпала — initrd берёт на себя роль минимальной rescue-среды.

UsrMerge превращает /bin, /sbin, /lib, /lib64 в символические ссылки на соответствующие каталоги в /usr:

```text
/bin   → /usr/bin
/sbin  → /usr/sbin
/lib   → /usr/lib
/lib64 → /usr/lib64
```

Хронология по дистрибутивам: Fedora реализовала UsrMerge в версии 17 (2012), первой среди крупных дистрибутивов. Arch Linux последовал в 2013 году. openSUSE и Mageia — примерно в то же время. Debian шёл к этому мучительно долго: Technical Committee принял решение о mandatory merged-usr для Bookworm (Debian 12) в 2021, но финализация (перенос файлов из / в /usr внутри пакетов) завершена только в Debian 13 Trixie (вышел в августе 2025). При обновлении до Trixie dpkg может выдавать предупреждения о невозможности удалить старые директории — это ожидаемо и безопасно. Ubuntu следовала за Debian, но с меньшими трениями. Слияние bin и sbin — отдельный, второй шаг: Arch сделал его сразу, ещё в июне 2013-го, сведя /bin, /sbin и /usr/sbin в один /usr/bin, а Fedora дошла до этого только в 42-й версии, где /usr/sbin стал симлинком на /usr/bin и исчез из PATH по умолчанию.

Причина сложности в Debian: в отличие от Fedora и Arch, которые сделали «flag day» (до — не merged, после — обязательно merged), Debian пытался поддерживать оба варианта одновременно, что вызвало проблемы с пакетами, собранными на merged-системе и установленными на не-merged.

Результат: на современной (2025+) системе разделение /bin vs /usr/bin не существует. Все бинарники физически в /usr/bin, а /bin — симлинк. Это важно учитывать в скриптах: `#!/bin/bash` продолжает работать (через симлинк), но канонический путь теперь /usr/bin/bash.

## Виртуальные файловые системы

Linux использует виртуальные файловые системы как основной API для взаимодействия userspace и ядра. Это не данные на диске — это проекция состояния ядра в файловую иерархию, доступная через обычные read()/write().

### procfs (/proc)

Старейшая виртуальная ФС Linux (унаследована от Plan 9). Монтируется на /proc и содержит два класса информации:

**Per-process информация:** каждый процесс представлен каталогом /proc/<pid>/. Ключевые файлы: cmdline (аргументы командной строки), environ (переменные окружения), fd/ (симлинки на открытые файл-дескрипторы), maps (карта памяти процесса), status (состояние: UID, GID, память, потоки), cgroup (принадлежность к контрольным группам — см. статью 6), ns/ (привязка к namespaces — см. статью 6).

/proc/self — магический симлинк на каталог текущего процесса. /proc/thread-self — аналог для текущего треда (с ядра 3.17).

**Общесистемная информация:** /proc/meminfo (состояние памяти), /proc/cpuinfo (информация о CPU), /proc/loadavg (загрузка системы), /proc/mounts (смонтированные ФС), /proc/filesystems (поддерживаемые ядром типы ФС), /proc/interrupts (статистика прерываний).

**/proc/sys/** — дерево runtime-параметров ядра, доступных через sysctl(8). Например, /proc/sys/net/ipv4/ip_forward управляет форвардингом пакетов. Чтение и запись в эти файлы эквивалентны вызовам `sysctl <параметр>` и `sysctl -w` (`-r` у sysctl(8) — это фильтр по регулярному выражению, а не чтение). Подробнее о sysctl — в статье 5 (Ядро).

Ключевой нюанс: procfs — часть stable ABI ядра, хотя документация ядра явно этого не утверждает. На практике утилиты (ps, top, free, cat /proc/meminfo) полагаются на конкретный формат файлов в /proc, и ядро поддерживает обратную совместимость. Однако точный набор полей может расширяться между версиями.

### sysfs (/sys)

Введена в ядре 2.6 (2003) для решения конкретной проблемы: procfs стал свалкой для информации, не имеющей отношения к процессам. sysfs предоставляет структурированное представление device model ядра — kobjects, устройства, драйверы, шины.

Принцип организации: каждый файл в /sys содержит ровно одно значение (число или строку). Это принципиальное отличие от /proc, где файлы часто содержат таблицы с множеством полей.

Ключевые поддеревья: /sys/class/ — устройства, сгруппированные по классам (net, block, tty), /sys/block/ — блочные устройства, /sys/bus/ — шины (pci, usb, scsi), /sys/devices/ — физическая топология устройств, /sys/module/ — загруженные модули ядра и их параметры, /sys/fs/ — информация о файловых системах (включая точку монтирования cgroup2 — /sys/fs/cgroup), /sys/kernel/ — параметры ядра (mm, debug, security).

Пример: изменение яркости экрана ноутбука — запись в файл `/sys/class/backlight/<device>/brightness`. Определение того, является ли диск SSD — чтение `/sys/block/sda/queue/rotational` (0 = SSD).

sysfs — часть stable ABI ядра: документация явно гарантирует, что интерфейс не будет сломан. Однако ABI ограничивает *что может появиться*, а не *что присутствует в данный момент* — набор файлов динамически зависит от обнаруженного оборудования.

### tmpfs

Файловая система полностью в оперативной памяти (и swap, если доступен). В отличие от ramfs (её предшественника), tmpfs имеет ограничение размера (по умолчанию 50% RAM) и поддерживает swapping — неиспользуемые страницы могут быть выгружены в swap.

Типичные точки монтирования: /tmp (если включён tmp.mount в systemd), /run (volatile runtime data), /dev/shm (POSIX shared memory — glibc ожидает tmpfs здесь), /sys/fs/cgroup (корень иерархии cgroup на системах с cgroups v1; при v2 — cgroup2 fs напрямую).

Потребление памяти tmpfs отображается как «Shmem» в /proc/meminfo и «Shared» в выводе free(1). Это часто сбивает с толку: tmpfs потребляет реальную память только под фактически записанные данные, а не под заявленный размер.

### devtmpfs (/dev)

Автоматически создаётся ядром при загрузке и заполняется device nodes. udev (часть systemd) затем дополняет /dev: создаёт симлинки (/dev/disk/by-uuid/, /dev/disk/by-label/), устанавливает права, запускает правила. devtmpfs существует для решения chicken-and-egg проблемы: udev нуждается в /dev для работы, но /dev раньше создавался udev.

### cgroup fs

Виртуальная ФС для управления control groups. В cgroups v1 каждый контроллер (cpu, memory, blkio, pids и т.д.) монтировался как отдельная ФС типа `cgroup` — десятки точек монтирования под /sys/fs/cgroup/. В cgroups v2 всё упростилось: единая ФС типа `cgroup2` на /sys/fs/cgroup. Современные дистрибутивы (Fedora 31+, Debian 11 Bullseye+, Ubuntu 21.10+, Arch) используют cgroups v2 по умолчанию, а systemd 258 удалил поддержку v1 («legacy» и «hybrid» иерархии) целиком — cgroup2 монтируется всегда. Подробный разбор cgroups — в статье 6 (Контейнеризация).

### Другие виртуальные ФС

**debugfs** (/sys/kernel/debug) — отладочный интерфейс ядра, не является частью stable ABI. Используется для трассировки (ftrace), eBPF, и отладки драйверов. Доступ требует CAP_SYS_ADMIN. **tracefs** (/sys/kernel/tracing, ранее внутри debugfs) — выделена из debugfs для разделения отладочных и трассировочных интерфейсов. **securityfs** (/sys/kernel/security) — интерфейс LSM (SELinux, AppArmor, Landlock — см. статью 7). **pstore** (/sys/fs/pstore) — persistent storage для kernel panic logs, сохраняющий данные между ребутами через NVRAM или выделенный раздел. **efivarfs** (/sys/firmware/efi/efivars) — доступ к переменным UEFI. Осторожно: запись может повредить прошивку некоторых систем. **bpf** (/sys/fs/bpf) — pinning eBPF-объектов (программ и map'ов) для персистентности между вызовами (см. статью 10).

## Практика

Просмотр всех смонтированных виртуальных ФС:

```bash
mount -t proc,sysfs,tmpfs,devtmpfs,cgroup2,securityfs
# или для полного списка с параметрами
findmnt -t proc,sysfs,tmpfs,cgroup2
```

Быстрая диагностика системы через /proc:

```bash
# Сколько памяти доступно (MemAvailable точнее чем MemFree)
awk '/MemAvailable/ {printf "%.1f GB\n", $2/1024/1024}' /proc/meminfo

# Количество открытых файл-дескрипторов в системе vs лимит
cat /proc/sys/fs/file-nr  # <allocated> <free> <max>

# Какие ФС поддерживает ядро (nodev = не требует блочного устройства)
cat /proc/filesystems
```

Работа с sysfs:

```bash
# Все сетевые интерфейсы и их состояние (operstate)
for iface in /sys/class/net/*/; do
    echo "$(basename $iface): $(cat $iface/operstate 2>/dev/null)"
done

# Информация о блочном устройстве
cat /sys/block/sda/queue/scheduler   # текущий I/O scheduler
cat /sys/block/sda/queue/rotational  # 0=SSD, 1=HDD
```

sysctl — удобная обёртка над /proc/sys/:

```bash
# Эквивалентные операции
cat /proc/sys/net/ipv4/ip_forward
sysctl net.ipv4.ip_forward

# Временное изменение (до ребута)
sysctl -w net.ipv4.ip_forward=1
# или
echo 1 > /proc/sys/net/ipv4/ip_forward

# Постоянное — через /etc/sysctl.d/*.conf
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-forwarding.conf
sysctl --system  # перечитать все файлы конфигурации
```

Проверка UsrMerge:

```bash
# Проверить, что система merged
ls -la /bin /sbin /lib
# Ожидаемый результат на современной системе:
# /bin -> usr/bin
# /sbin -> usr/sbin
# /lib -> usr/lib

# Канонический путь к бинарнику
readlink -f /bin/bash  # /usr/bin/bash
```

Где живут данные tmpfs и сколько они потребляют:

```bash
df -h --type=tmpfs
# Типичный вывод:
# tmpfs    3.9G  1.2M  3.9G   1% /run
# tmpfs    3.9G     0  3.9G   0% /dev/shm
# tmpfs    3.9G   12K  3.9G   1% /tmp
```

## Нюансы и trade-off'ы

**FHS — рекомендация, не закон.** Gentoo явно заявляет о несоблюдении FHS, NixOS принципиально использует другую иерархию (/nix/store/...), GoboLinux экспериментировал с альтернативной структурой. Даже «FHS-compliant» дистрибутивы расходятся в деталях: Debian кладёт web root по умолчанию в /var/www, Red Hat — в /var/www/html, FHS рекомендует /srv.

**/opt vs /usr/local** — вечный спор. FHS определяет /opt для add-on software packages (каждый пакет в своём поддереве) и /usr/local для locally-installed software (дублирует структуру /usr). На практике выбор часто определяется привычкой и тем, как сконфигурирован `./configure` (по умолчанию --prefix=/usr/local). Крупный enterprise-софт (Oracle, IBM) предпочитает /opt, а pip install --user кладёт в ~/.local/, cargo install — в ~/.cargo/bin (installation root по умолчанию — $HOME/.cargo): третий вариант, не описанный в FHS.

**tmpfs на /tmp — палка о двух концах.** systemd включает tmp.mount (tmpfs на /tmp) по умолчанию. Плюс: быстрее, автоочистка при ребуте, нет фрагментации на диске. Минус: потребляет RAM/swap. Если приложение создаёт большие временные файлы (сборка пакетов, обработка видео), может неожиданно заполнить память. Решение: или отключить tmp.mount (`systemctl mask tmp.mount`), или установить ограничение размера через `Options=size=2G` в mount unit.

**/proc/sys/ vs /sys/** — пересечение зон ответственности. Параметры ядра (sysctl) живут в /proc/sys/, параметры устройств и модулей — в /sys/. Но граница нечёткая: например, параметры подсистемы vm (Virtual Memory) в /proc/sys/vm/, а Transparent Huge Pages — в /sys/kernel/mm/transparent_hugepage/. Эмпирическое правило: /proc/sys/ — для networking и system-wide tunables, /sys/ — для всего, связанного с устройствами и модулями.

**Безопасность виртуальных ФС.** /proc раскрывает информацию обо всех процессах системы. Параметр ядра `hidepid=2` (mount option для /proc) скрывает чужие /proc/<pid>/ каталоги от непривилегированных пользователей — полезно для shared-хостинга и контейнерных хостов. hidepid=invisible — символьный синоним той же двойки, а исключения задаются отдельной опцией монтирования `gid=`. С ядра 5.8 procfs понимает эти символьные имена и добавляет ещё два инструмента: hidepid=ptraceable (оно же 4) оставляет видимыми только те процессы, которые вызывающий может трассировать, а subset=pid прячет из /proc всё, что не относится к задачам. /sys/kernel/debug (debugfs) предоставляет прямой доступ к внутренним структурам ядра — на production-системах стоит ограничивать доступ или не монтировать.

**efivarfs и brick-risk.** Запись в /sys/firmware/efi/efivars/ может в редких случаях повредить прошивку (зафиксированы случаи с Samsung и MSI). `rm -rf /` с `--no-preserve-root` на системе с efivarfs может превратить сервер в кирпич. Вопреки распространённому мнению, systemd монтирует efivarfs на запись (добавляя лишь nosuid, noexec и nodev) — страховка живёт в ядре: все переменные, кроме списка стандартных, создаются с флагом immutable, так что снести их без `chattr -i` не выйдет.

## Сравнение с FreeBSD

Главное архитектурное различие — в Linux нет концепции «base system». FreeBSD чётко отделяет базовую систему (/bin, /sbin, /usr/bin, /usr/sbin — собственный код FreeBSD) от стороннего ПО (/usr/local/ — всё, что из портов и пакетов, включая серверные компоненты вроде BIND и nginx). Конфиги разделены соответственно: /etc для base, /usr/local/etc для портов. В Linux такого разделения нет — пакетный менеджер ставит бинарники в /usr/bin и конфиги в /etc вне зависимости от «происхождения» пакета.

Виртуальные ФС: FreeBSD исторически минимизировала использование procfs (он опционален и deprecated с FreeBSD 7+), предпочитая sysctl(8) как основной интерфейс к ядру. В Linux procfs и sysfs — primary API, а sysctl — обёртка над /proc/sys/. Это фундаментальное различие: FreeBSD оперирует структурированными MIB-деревьями через специализированный syscall (sysctl(2)), Linux проецирует всё в файловую систему, следуя принципу «everything is a file» до логического предела.

/sys в FreeBSD — симлинк на исходники ядра (/usr/src/sys). В Linux — это sysfs, совершенно другая сущность. /run в FreeBSD отсутствует — volatile runtime data живёт в /var/run без каких-либо проблем, потому что /var обычно на том же разделе, что и /. FHS, в свою очередь, позволяет /var на отдельном разделе, что и создало потребность в /run.

UsrMerge не имеет аналога в FreeBSD, потому что FreeBSD никогда не разносила бинарники одного уровня по разным каталогам без причины — /bin содержит то, что нужно для однопользовательского режима, и это разделение имеет практический смысл, так как FreeBSD не использует initramfs.

## Источники

- [FHS 3.0 Specification](https://specifications.freedesktop.org/fhs/latest/index.html) — полный текст стандарта (FreeDesktop.org, republished Nov 2025)
- [The Linux Kernel documentation: procfs](https://www.kernel.org/doc/html/latest/filesystems/proc.html) — описание файлов в /proc
- [The Linux Kernel documentation: sysfs](https://www.kernel.org/doc/html/latest/filesystems/sysfs.html) — правила интерфейса sysfs
- [The Linux Kernel documentation: tmpfs](https://www.kernel.org/doc/html/latest/filesystems/tmpfs.html) — параметры монтирования и лимиты
- [Debian UsrMerge Wiki](https://wiki.debian.org/UsrMerge) — статус перехода и техническая документация
- [systemd file-hierarchy(7)](https://man.archlinux.org/man/file-hierarchy.7.en) — описание иерархии с точки зрения systemd
- [TheCaseForTheUsrMerge](https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/) — аргументация и мифы вокруг UsrMerge
- [LWN: Unexpected fallout from /usr merge in Debian](https://lwn.net/Articles/773342/) — хроника проблем Debian с UsrMerge
- [Virtual filesystems in Linux: Why we need them and how they work](https://opensource.com/article/19/3/virtual-filesystems-linux) — обзор VFS-архитектуры
- [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html) — man page по cgroups v1 и v2
- FreeBSD Handbook: [Directory Structure](https://docs.freebsd.org/en/books/handbook/basics/#dirstructure) — для сравнения

---

## Связанные заметки

- [Linux — systemd: init, сервисы, таймеры](./linux-systemd.md) — `/run`, tmpfiles и управление runtime-каталогами
- [Linux — пакетные менеджеры](./linux-package-managers.md) — кто и куда раскладывает файлы при установке
- [FreeBSD — файловая структура](./freebsd-filesystem-hierarchy.md) — разделение base system и `/usr/local`, для сравнения
- [Linux — сводный cheatsheet](./linux-map-cheatsheet.md) — быстрая справка по циклу
- [Debian: модель релизов и управление пакетами](./debian-releases-and-packages.md) — как дистрибутив раскладывает файлы по этой иерархии и где проходит граница `/usr/local`
