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

# FreeBSD — sysctl и конфигурация ядра

## Обзор

В FreeBSD есть три уровня конфигурации ядра, и важно понимать, когда какой применяется. Первый — `sysctl(8)`: runtime-тюнинг параметров работающего ядра, без перезагрузки и пересборки. Второй — `loader.conf`: параметры, задаваемые на этапе загрузки (loader tunables), когда ядро уже загружено, но ещё не запущено полностью. Третий — пересборка ядра из исходников с кастомным конфигурационным файлом.

На практике 95% задач решаются на первых двух уровнях. Пересборка ядра — редкая операция, особенно на VPS, но понимание её механики полезно для осознания архитектуры системы. Статья построена от повседневного к редкому: sysctl → loader.conf → кастомное ядро.

## sysctl: runtime-тюнинг ядра

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

`sysctl(8)` — интерфейс к дереву параметров ядра, организованных в иерархическую структуру MIB (Management Information Base). Каждый параметр — это точка в дереве, доступная для чтения, а часто и для записи в runtime. В современном ядре FreeBSD доступно более 5000 переменных.

Параметры организованы по подсистемам: `kern` (ядро: процессы, лимиты, планировщик), `vm` (виртуальная память, swap), `net` (сетевой стек), `vfs` (файловые системы, включая ZFS), `hw` (оборудование), `security` (политики безопасности), `debug` (отладка), `machdep` (платформо-специфичные).

### Базовое использование

```sh
sysctl -a                              # все переменные (5000+)
sysctl kern.ostype                     # конкретная переменная
sysctl kern                            # все переменные в ветке kern.*
sysctl -d kern.maxfiles                # описание переменной
sysctl kern.maxfiles=200000            # установить значение (до перезагрузки)
sysctl -t kern.maxfiles                # показать тип переменной
```

Флаг `-d` особенно полезен — многие переменные имеют встроенное описание, что избавляет от поиска в документации.

### Персистентность: sysctl.conf и loader.conf

Изменения через `sysctl` живут до перезагрузки. Для персистентности:

`/etc/sysctl.conf` — применяется при загрузке rc-системой (после старта ядра). Сюда попадают параметры, которые можно менять в runtime.

```sh
# /etc/sysctl.conf
kern.maxfiles=200000
net.inet.ip.forwarding=1
security.bsd.see_other_uids=0
```

`/boot/loader.conf` — применяется загрузчиком до полного старта ядра. Сюда попадают read-only параметры (tunables), которые нельзя изменить в runtime. Их можно узнать по тому, что `sysctl` покажет значение, но попытка записи вернёт ошибку "read-only".

```sh
# /boot/loader.conf
kern.maxusers=256
kern.ipc.nmbclusters=65536
vfs.zfs.arc.max="4G"
```

Как определить, куда класть параметр: попробовать `sysctl переменная=значение`. Если сработало — `/etc/sysctl.conf`. Если "read-only" — `/boot/loader.conf`. Деление не строгое: часть переменных помечена `CTLFLAG_RWTUN` и задаётся обоими способами — так устроены `vfs.zfs.arc.max` и `kern.ipc.nmbclusters`. Полный список того, что вообще читается загрузчиком, даёт `sysctl -T`, а дефолтные значения loader tunables — `/boot/defaults/loader.conf`.

### Практически важные sysctl по категориям

#### Сеть (net.inet.*)

```sh
# Размер очереди входящих соединений (дефолт 128 — мало для web-сервера)
kern.ipc.soacceptqueue=4096

# Буферы TCP
net.inet.tcp.recvspace=65536           # буфер приёма (дефолт 65536)
net.inet.tcp.sendspace=65536           # буфер отправки

# Диапазон эфемерных портов (для серверов с большим числом исходящих соединений)
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535

# Быстрый recycling TIME_WAIT сокетов
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.finwait2_timeout=5000     # мс (дефолт 60000)

# IP forwarding (для роутера/firewall)
net.inet.ip.forwarding=1

# Congestion control алгоритм
net.inet.tcp.cc.algorithm=cubic        # дефолт с 14.0; ещё newreno, htcp, dctcp, vegas, cdg
```

`kern.ipc.soacceptqueue` — один из первых параметров, который стоит увеличить на web-сервере. Дефолтное значение 128 может быть мало для обработки всплесков входящих соединений; старое имя `kern.ipc.somaxconn` осталось рабочим синонимом, но скрыто из вывода `sysctl -a`, и `tuning(7)` говорит уже только о `soacceptqueue`.

С FreeBSD 14.0 алгоритмом управления перегрузкой по умолчанию стал CUBIC вместо NewReno. BBR в этот список не входит — это не congestion control, а альтернативный TCP-стек (модуль `tcp_bbr`), который выбирается через `net.inet.tcp.functions_default`.

#### Лимиты ресурсов (kern.*)

```sh
# Максимальное число открытых файлов в системе
kern.maxfiles=200000
kern.maxfilesperproc=100000

# kern.maxusers — read-only, но влияет на автотюнинг многих параметров
# Устанавливается в /boot/loader.conf; автоматически вычисляется по RAM
# Явно задавать имеет смысл только если автотюнинг не устраивает

# Shared memory (для PostgreSQL, Redis и др.)
kern.ipc.shmmax=1073741824             # 1GB максимальный сегмент
kern.ipc.shmall=262144                 # макс. страниц shared memory
```

`kern.maxusers` — историческая переменная, от которой масштабируются десятки других лимитов (таблицы процессов, сетевые буферы, mbuf'ы). Автоматически вычисляется по объёму RAM. Обычно трогать не нужно, но понимать её влияние полезно.

#### Безопасность (security.bsd.*)

```sh
# Непривилегированные пользователи не видят процессы других пользователей
security.bsd.see_other_uids=0
security.bsd.see_other_gids=0

# Не видят процессы в других jail'ах
security.bsd.see_jail_proc=0

# Непривилегированные пользователи не могут читать dmesg
security.bsd.unprivileged_read_msgbuf=0

# ASLR — с 13.2 включён по умолчанию для 64-битных бинарников
kern.elf64.aslr.enable=1
kern.elf64.aslr.pie_enable=1

# Рандомизация PID
kern.randompid=1
```

Эти параметры — low-hanging fruit для hardening'а VPS. `see_other_uids=0` и `see_jail_proc=0` существенно ограничивают разведку для потенциального атакующего.

#### ZFS (vfs.zfs.*)

```sh
# Максимальный размер ARC (кэш чтения ZFS)
# Меняется и в runtime, но обычно задаётся в loader.conf
vfs.zfs.arc.max="4G"                  # ограничить, если ZFS съедает всю RAM
vfs.zfs.arc.min="512M"                # минимальный размер ARC

# Prefetch (полезен для последовательного чтения)
vfs.zfs.prefetch.disable=0            # 0 = включён (дефолт)

# Лимит транзакционных групп (влияет на latency записи)
vfs.zfs.txg.timeout=5                 # секунд (дефолт 5)
```

`vfs.zfs.arc.max` — возможно, самый востребованный tunable на сервере с ZFS. По умолчанию ARC может занять почти всю RAM, что нормально для чистого файл-сервера, но проблематично если на той же машине работают приложения с собственными кэшами (PostgreSQL, Redis). Со времён OpenZFS 2.x у него два имени: старое `vfs.zfs.arc_max` продолжает работать, но помечено как LEGACY и с 15.1 печатает в лог предупреждение с советом перейти на `vfs.zfs.arc.max`. Вопреки распространённому убеждению, оба варианта пишутся не только из `loader.conf`: это `CTLFLAG_RWTUN`, то есть значение меняется и в runtime (уменьшить фактический размер ARC без давления на память при этом всё равно не выйдет).

#### Виртуальная память (vm.*)

```sh
# Overcommit: битовая маска, дефолт 0. Бит 0 — отказывать, когда резерв свопа
# превысит vm.swap_total; бит 1 — соблюдать RLIMIT_SWAP; бит 2 — считать
# доступной и физическую память, кроме wired и резерва
vm.overcommit=0

# Давление на swap (когда начинать использовать swap)
vm.swappiness=60                       # нет прямого аналога в FreeBSD,
                                       # но vm.pageout_oom_seq влияет на OOM
```

FreeBSD агрессивнее Linux в использовании RAM для кэширования, что обычно хорошо для серверных нагрузок.

### Исследование параметров

```sh
# Найти все параметры, связанные с TCP
sysctl -a | grep tcp

# Показать все изменяемые параметры с описаниями в ветке net
sysctl -ad net

# Посмотреть текущие значения vs дефолтные
# (нет встроенной команды, но можно сравнить с чистой системой)

# Все loader-тюнабли (то, что имеет смысл класть в loader.conf)
sysctl -T

# Все переменные, изменяемые в runtime
sysctl -W
```

Полная документация: `man 8 sysctl`, `man 5 sysctl.conf`, а также `man tuning` — специализированная man-страница по тюнингу FreeBSD.

## loader.conf: конфигурация загрузчика

### Роль загрузчика

FreeBSD boot loader (`loader(8)`) — это этап между BIOS/UEFI и запуском ядра. Он загружает ядро, kernel modules и устанавливает начальные значения tunables. Конфигурация — в `/boot/loader.conf`, дефолты — в `/boot/defaults/loader.conf`.

Это единственное место для: параметров, которые должны быть установлены до старта ядра (read-only sysctl); загрузки kernel modules; выбора альтернативного ядра.

### Типичные настройки

```sh
# /boot/loader.conf

# Загрузка модулей
if_bridge_load="YES"                   # модуль бриджинга
pf_load="YES"                         # модуль PF (можно и через rc.conf)
accf_http_load="YES"                  # accept filter для HTTP (nginx/Apache)
accf_data_load="YES"                  # accept filter для данных

# Tunables
kern.maxusers=256
kern.ipc.nmbclusters=65536            # сетевые mbuf-кластеры (для нагруженной сети)
vfs.zfs.arc.max="4294967296"          # 4GB в байтах (или "4G")

# Задержка автозагрузки (секунды до автоматической загрузки ядра)
autoboot_delay="3"                     # дефолт 10; -1 = без задержки и без приглашения

# Console
kern.vty=vt                            # виртуальный терминал (vt vs sc)
```

### Accept Filters

Accept filters — FreeBSD-специфичная оптимизация: ядро откладывает доставку входящего соединения приложению, пока не получит полный HTTP-запрос или блок данных. Это снижает количество переключений контекста и системных вызовов. Для web-серверов (nginx, Apache) `accf_http` даёт заметный выигрыш при высокой нагрузке.

```sh
# /boot/loader.conf
accf_http_load="YES"
accf_data_load="YES"
```

После этого nginx может использовать `listen 80 accept_filter=httpready`.

### Kernel Modules

Большинство функциональности FreeBSD-ядра реализовано в загружаемых модулях (KLD — Kernel Loadable Modules). Это ключевое архитектурное решение: GENERIC-ядро содержит минимум статически вкомпилированного кода, а всё остальное загружается по необходимости.

```sh
kldstat                                # список загруженных модулей
kldload pf                             # загрузить модуль вручную
kldunload pf                           # выгрузить
```

Постоянная загрузка — через `loader.conf` (`modulename_load="YES"`) или через rc-систему (многие rc-скрипты сами загружают нужные модули).

Модули хранятся в `/boot/kernel/`. При обновлении ядра через `freebsd-update` (или, на pkgbase-системе, через `pkg upgrade`) модули обновляются автоматически. Критично: модули должны быть синхронизированы с ядром — загрузка модуля от другой версии ядра может привести к панике.

## Конфигурация и пересборка ядра

### Когда это действительно нужно

На VPS — практически никогда. GENERIC-ядро покрывает подавляющее большинство сценариев, а загружаемые модули и sysctl обеспечивают необходимую гибкость.

Реальные причины для кастомного ядра: поддержка железа, отсутствующего в GENERIC (экзотические embedded-платформы); hardening через статическую компиляцию только нужных компонентов и запрет загрузки модулей (securelevel); включение функциональности, не существующей в виде модуля (дисциплины ALTQ, например, модулями не загружаются в принципе — это прямо сказано в `altq(4)`); радикальное уменьшение footprint для embedded-систем с ограниченной RAM.

Классические кандидаты из старых руководств — IPsec и MAC — из этого списка давно выпали: в GENERIC есть и `options MAC`, и `options IPSEC_SUPPORT`, который специально существует ради `kldload ipsec`. Для серверных задач на стандартном железе или VPS — sysctl + loader.conf достаточно.

### Архитектура сборки

Исходники ядра — в `/usr/src/sys/`. Конфигурационные файлы — в `/usr/src/sys/<arch>/conf/`:

`GENERIC` — конфигурация ядра, которая поставляется по умолчанию. Никогда не редактируется напрямую — перезаписывается при обновлении исходников.

`NOTES` — документация всех доступных опций для данной архитектуры. `../../conf/NOTES` — платформо-независимые опции. Вместе — полный справочник.

Кастомная конфигурация — копия GENERIC с модификациями:

```sh
cd /usr/src/sys/amd64/conf
cp GENERIC MYKERNEL
```

Рекомендуется хранить кастомный конфиг вне `/usr/src` (например, `/root/kernels/MYKERNEL`) и создавать симлинк — иначе можно потерять конфиг при пересоздании `/usr/src`.

### Формат конфигурационного файла

```conf
ident         MYKERNEL

# Включить всё из GENERIC как базу
include       GENERIC

# Отключить ненужное
nooptions     COMPAT_FREEBSD32       # убрать 32-bit совместимость
nodevice      fdc                     # убрать floppy-контроллер

# Добавить нужное
options       ALTQ                    # ALTQ для QoS в PF
options       ALTQ_HFSC              # HFSC scheduler
options       IPSTEALTH              # не декрементировать TTL при форвардинге
device        pf                      # PF статически (вместо модуля)
device        pflog
device        pfsync                  # синхронизация состояний PF (для CARP)
```

`include GENERIC` + `nooptions`/`nodevice` — современный подход: базируемся на GENERIC и точечно модифицируем, вместо создания конфига с нуля. Это упрощает обновление — при изменении GENERIC кастомный конфиг автоматически наследует изменения.

### Процесс сборки

```sh
cd /usr/src
make buildkernel KERNCONF=MYKERNEL      # сборка (~20-90 мин в зависимости от CPU)
make installkernel KERNCONF=MYKERNEL    # установка в /boot/kernel/
```

Старое ядро автоматически сохраняется в `/boot/kernel.old/`. Если новое ядро не загружается — в меню загрузчика можно выбрать kernel.old.

На системе, установленной пакетами базы (pkgbase; с 15.1 `bsdinstall` ставит систему так по умолчанию), `make installkernel` намеренно заблокирован — иначе база пакетов разошлась бы с содержимым `/boot`. Собранное ядро в этом случае либо упаковывают целью `make update-packages KERNCONF=MYKERNEL` и ставят через `pkg`, либо кладут в отдельный каталог через `INSTKERNNAME` и пробуют загрузиться в него через `nextboot(8)`. Проверку можно снять переменной `ALLOW_PKGBASE_INSTALLKERNEL` в `/etc/make.conf`, но тогда `pkg` перестаёт отражать реальное состояние системы.

Для ускорения итераций: `MODULES_OVERRIDE` в `/etc/make.conf` позволяет собирать только нужные модули вместо всех.

## securelevel: уровни безопасности ядра

FreeBSD поддерживает концепцию securelevel — монотонно возрастающий уровень ограничений ядра. После повышения securelevel его нельзя понизить без перезагрузки.

`-1` — permanently insecure (дефолт). Никаких ограничений.
`0` — insecure. Нет ограничений, но securelevel повышается до 1 при переходе в multi-user.
`1` — secure. Запрещена загрузка/выгрузка модулей ядра, запись в /dev/mem и /dev/kmem, изменение файловых флагов immutable/append-only.
`2` — highly secure. Всё из уровня 1, плюс диски нельзя открыть на запись вообще — ни смонтированные, ни размонтированные (кроме как через `mount(2)`), из-за чего `newfs` в multi-user становится невозможен; изменение времени ядра ограничено шагом в одну секунду.
`3` — network secure. Всё из уровня 2, плюс запрет изменения правил пакетного фильтра.

```sh
# /etc/rc.conf
kern_securelevel_enable="YES"
kern_securelevel="1"
```

На production-сервере securelevel 1 — разумный выбор: предотвращает загрузку вредоносных модулей ядра и модификацию критичных файлов, при этом не мешает нормальной работе.

## Практические рецепты

### Минимальный hardening для VPS

```sh
# /etc/sysctl.conf
security.bsd.see_other_uids=0
security.bsd.see_other_gids=0
security.bsd.see_jail_proc=0
security.bsd.unprivileged_read_msgbuf=0
kern.randompid=1
kern.elf64.aslr.enable=1
kern.elf64.aslr.pie_enable=1
kern.coredump=0
```

### Тюнинг для web-сервера (nginx/PostgreSQL)

```sh
# /etc/sysctl.conf
kern.ipc.soacceptqueue=4096
kern.ipc.shmmax=1073741824
kern.maxfiles=200000
kern.maxfilesperproc=100000
net.inet.tcp.fast_finwait2_recycle=1

# /boot/loader.conf
accf_http_load="YES"
accf_data_load="YES"
kern.ipc.nmbclusters=65536
```

### Тюнинг для ZFS с ограниченной RAM (2-4GB VPS)

```sh
# /boot/loader.conf
vfs.zfs.arc.max="1073741824"           # 1GB — оставить RAM приложениям
```

## Диагностика и мониторинг

```sh
sysctl -a | wc -l                      # сколько всего переменных
sysctl kern.boottime                   # когда система загрузилась
sysctl kern.version                    # версия ядра
sysctl hw.machine                      # архитектура
sysctl hw.model                        # модель CPU
sysctl hw.ncpu                         # число CPU
sysctl hw.physmem                      # физическая память (байты)
sysctl hw.realmem                      # реальная память до резервирования ядром
sysctl vm.loadavg                      # load average
sysctl vm.vmtotal                      # общая картина использования VM

kldstat                                # загруженные модули ядра
kenv                                   # переменные окружения загрузчика
dmesg                                  # сообщения ядра (буфер в памяти)
cat /var/run/dmesg.boot                # dmesg на момент загрузки (сохраняется)
```

## Отличия от Linux

В Linux sysctl организован аналогично (`/proc/sys/`), но с другим пространством имён. Ближайшие аналоги: `net.ipv4.ip_forward` → `net.inet.ip.forwarding`, `vm.swappiness` → прямого аналога нет, `fs.file-max` → `kern.maxfiles`.

В Linux нет аналога `/boot/loader.conf` как отдельного уровня конфигурации — параметры ядра передаются через командную строку загрузки (GRUB), что менее структурировано.

Securelevel не имеет прямого аналога в Linux. Closest — LSM (AppArmor, SELinux), но это другая модель: политики доступа vs глобальные уровни ограничений.

Kernel modules в обеих системах работают похоже, но во FreeBSD KLD и `kldload`/`kldstat`, в Linux — `.ko` и `modprobe`/`lsmod`.

## Источники

- FreeBSD Handbook, "Tuning with sysctl": [docs.freebsd.org/en/books/handbook/config/#configtuning-sysctl](https://docs.freebsd.org/en/books/handbook/config/)
- FreeBSD Handbook, "Configuring the FreeBSD Kernel": [docs.freebsd.org/en/books/handbook/kernelconfig/](https://docs.freebsd.org/en/books/handbook/kernelconfig/)
- Klara Systems, "Customizing the FreeBSD Kernel": [klarasystems.com/articles/customizing-the-freebsd-kernel/](https://klarasystems.com/articles/customizing-the-freebsd-kernel/)
- `sysctl(8)`: [man.freebsd.org/cgi/man.cgi?query=sysctl&sektion=8](https://man.freebsd.org/cgi/man.cgi?query=sysctl&sektion=8)
- `loader.conf(5)`: [man.freebsd.org/cgi/man.cgi?query=loader.conf&sektion=5](https://man.freebsd.org/cgi/man.cgi?query=loader.conf&sektion=5)
- `tuning(7)`: [man.freebsd.org/cgi/man.cgi?query=tuning&sektion=7](https://man.freebsd.org/cgi/man.cgi?query=tuning&sektion=7)
- `security(7)`: [man.freebsd.org/cgi/man.cgi?query=security&sektion=7](https://man.freebsd.org/cgi/man.cgi?query=security&sektion=7)

---

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

- [FreeBSD — безопасность](./freebsd-security-hardening.md) — securelevel и hardening-переменные sysctl
- [FreeBSD — мониторинг и отладка](./freebsd-monitoring-debugging.md) — sysctl как источник счётчиков производительности
- [FreeBSD — обновление системы](./freebsd-updating.md) — пересборка ядра при обновлении из исходников
- [Linux — ядро: сборка, модули, параметры](./linux-kernel.md) — Kconfig и модули Linux, для сравнения
- [FreeBSD — сводный cheatsheet](./freebsd-cheatsheet.md) — ключевые переменные sysctl
