WireGuard-сервер на FreeBSD 15.1 для тех, кто знает Linux
Поднимаем WireGuard на FreeBSD 15.1 по привычкам из Linux: if_wg в ядре, wg-quick через rc.conf, NAT в pf вместо nftables и включение pf по SSH без потери доступа.
Коротко: что получится
WireGuard-сервер на FreeBSD 15.1 ставится проще, чем на Linux: драйвер if_wg уже есть в базовом ядре, и wireguard-go не нужен. Вы ставите пакет wireguard-tools ради wg-quick и rc-скрипта, включаете маршрутизацию через gateway_enable и пишете короткий pf.conf с правилом NAT (network address translation, трансляция адресов). Если у вас уже работает WireGuard на Linux, всё ниже будет переводом знакомых шагов на язык FreeBSD.
Сразу о площадке. SSD Nodes не предлагает образы FreeBSD, поэтому такой сервер вы поднимаете на своём железе или у провайдера, который даёт FreeBSD. Руководство написано для FreeBSD 15.1, текущего production-релиза с 16 июня 2026 года. Где FreeBSD 14.5 ведёт себя иначе, это сказано отдельно. Если базовая настройка системы ещё не сделана, начните с руководства по серверу на FreeBSD 15. Если вы пока выбираете систему, полезно сравнение Linux и FreeBSD для сервера.
Зачем этот сервер, если вы работаете из России
Честная модель угроз. WireGuard по замыслу не маскирует трафик: формат пакетов узнаваем, режима обфускации нет. По многочисленным сообщениям, на трансграничных маршрутах из российских сетей WireGuard блокируют. Поэтому этот сервер не обещает, что туннель пройдёт через такие фильтры. Если задача именно в обходе блокировки, читайте что запускать, когда ваш VPN блокируют. Правовую сторону это руководство не разбирает.
Реальные задачи такого сервера другие. Первая: админский доступ к вашим машинам, когда панели управления, базы и мониторинг слушают только адрес внутри туннеля. Вторая: связь между площадками (site-to-site), например между офисом и стойкой в дата-центре. Для обеих задач WireGuard подходит хорошо, потому что он маленький и работает в ядре.
Шпаргалка: Linux и FreeBSD рядом
Каждая строка: что вы делаете на Linux и что делаете на FreeBSD.
- Драйвер: на Linux модуль
wireguardв mainline с ядра 5.6. На FreeBSD драйверif_wgв базовой системе, интерфейс создаётifconfig wg create, модуль подгружается сам. - Утилиты:
apt install wireguard-toolsпревращается вpkg install wireguard-tools. Самаwgв 15.1 и 14.5 уже входит в базу (/usr/bin/wg). Пакет нужен радиwg-quickи rc-скрипта. - Конфиг:
/etc/wireguard/wg0.confпревращается в/usr/local/etc/wireguard/wg0.conf. Стороннее ПО на FreeBSD хранит настройки под/usr/local/etc. - Автозапуск: вместо
systemctl enable --now wg-quick@wg0пишетеsysrc wireguard_enable=YES wireguard_interfaces=wg0иservice wireguard start. - Маршрутизация: вместо
net.ipv4.ip_forward = 1в/etc/sysctl.d/пишетеsysrc gateway_enable=YES. - Файрвол и NAT: вместо nftables работает pf, один файл
/etc/pf.conf. - Имя сетевой карты: вместо
enp1s0илиens3будетvtnet0,em0илиigb0. FreeBSD называет интерфейс по драйверу. - Права:
sudoв базовой FreeBSD нет. Все команды ниже выполняются от root, черезsu -или консоль.
Почему wireguard-go на FreeBSD не нужен
У драйвера непростая история. Первую версию ядерного WireGuard убрали из FreeBSD в марте 2021 года, до выхода 13.0, после разбора качества кода. Переписанный драйвер wg(4) вернулся в базовую систему в FreeBSD 13.2, это записано в release notes 13.2. Значит, в 14.5 и 15.1 туннель работает в ядре, как на Linux.
Сначала проверьте, что модуль грузится:
kldload -n if_wg && echo okФлаг -n не считает ошибкой уже загруженный модуль. Если команда не напечатала ok, вы, скорее всего, внутри джейла без собственного сетевого стека. Тогда wg-quick пишет [!] Missing WireGuard kernel support и переходит на медленный userspace-вариант wireguard-go. На обычной виртуальной машине или на железе этого быть не должно.
Установка wireguard-tools и ключи
pkg install wireguard-tools
install -d -m 700 /usr/local/etc/wireguard
cd /usr/local/etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
ls -lpkg подтянет bash, потому что wg-quick написан на bash. Есть и вариант wireguard-tools-lite, без wg-quick и со своим rc-скриптом. Здесь используется полный пакет, потому что с ним wg0.conf совпадает с вашим конфигом на Linux.
На Linux есть известная ловушка: umask 077 перед sudo tee ненадёжен, потому что sudo применяет свою маску. Здесь вы уже root, поэтому umask 077 действует прямо на файлы, которые создаёт tee. В выводе ls -l у server.key должны стоять права -rw-------. Маска 077 остаётся в этой оболочке до выхода, так что дальше откройте новую сессию или верните umask 022.
Ключи клиента создайте на самом клиенте. Приватный ключ клиента на сервер не попадает.
Файл /usr/local/etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <содержимое server.key>
[Peer]
PublicKey = <публичный ключ клиента>
AllowedIPs = 10.8.0.2/32Формат тот же, что на Linux, и AllowedIPs работает так же: на сервере это /32 на каждого клиента. Почему этот список одновременно служит таблицей маршрутов и списком доступа, разобрано в статье о cryptokey routing в WireGuard. Строку SaveConfig не добавляйте, иначе wg-quick down перезапишет файл текущим состоянием.
Закройте файл от чужих глаз:
chmod 600 /usr/local/etc/wireguard/wg0.confЕсли права слишком открытые, wg-quick при старте пишет предупреждение is world accessible. Он проверяет и сам файл, и каталог над ним.
Автозапуск через rc.conf вместо systemd
sysrc wireguard_enable=YES wireguard_interfaces=wg0
service wireguard start
ifconfig wg0
wg showsysrc записывает переменные в /etc/rc.conf. При загрузке rc-скрипт wireguard вызывает wg-quick up для каждого интерфейса из wireguard_interfaces, при остановке вызывает wg-quick down. Это прямой аналог юнита wg-quick@wg0.
Что искать в выводе. В ifconfig wg0 должен быть адрес 10.8.0.1 и флаг UP. В wg show должен быть порт 51820 и ваш peer. Строка latest handshake появится только после того, как клиент подключится, и время в ней должно быть свежим.
У rc-скрипта есть полезная команда service wireguard reload. Она выполняет wg-quick strip и wg syncconf, поэтому новые peer-ы применяются без разрыва текущих сессий. Подробнее в статье о том, как добавить peer в WireGuard без перезапуска.
Маршрутизация: gateway_enable вместо ip_forward
FreeBSD не пересылает чужие пакеты, пока вы не сделаете из неё маршрутизатор.
sysrc gateway_enable=YES
sysctl net.inet.ip.forwarding=1
sysctl net.inet.ip.forwardinggateway_enable действует при загрузке, а sysctl включает пересылку прямо сейчас. Последняя команда должна показать 1. Это та же пара, что файл в /etc/sysctl.d/ и sysctl --system на Linux.
Теперь узнайте внешний интерфейс. На Linux это ip route show default, здесь:
route -n get defaultСмотрите на строку interface:. Это имя пойдёт в pf.conf вместо vtnet0 из примера.
Минимальный pf.conf и аналог в nftables
ext_if = "vtnet0"
wg_if = "wg0"
wg_net = "10.8.0.0/24"
set skip on lo0
nat on $ext_if inet from $wg_net to any -> ($ext_if)
pass in quick on $ext_if proto tcp to port 22
block in all
pass out all
pass in on $ext_if proto udp to port 51820
pass in on $wg_if from $wg_net
pass in inet proto icmp
pass in inet6 proto icmp6Та же трансляция на Linux, в nftables:
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.8.0.0/24 oifname "enp1s0" masquerade
}
}Соответствие прямое. nat on $ext_if это oifname. from $wg_net это ip saddr. -> ($ext_if) в скобках это masquerade: pf берёт текущий адрес интерфейса и перечитывает его, если адрес сменился.
Главное отличие для человека с Linux: порядок правил. В nftables судьбу пакета в цепочке решает первое совпавшее правило с accept или drop. В pf без слова quick побеждает последнее совпавшее правило. Поэтому block in all идёт рано, а разрешения идут после него. Правило для SSH стоит первым и помечено quick: оно срабатывает сразу, и никакое правило ниже его не отменит.
Отдельной цепочки forward в pf нет. Пакет клиента проверяется на входе в wg0 и на выходе из vtnet0, а ответы проходят по таблице состояний. Строка про icmp6 нужна, если на внешнем интерфейсе есть IPv6: без неё block in all режет входящие сообщения neighbor discovery, и IPv6 на сервере может перестать работать. Если вам ближе сторона Linux, сравнение двух её файрволов есть в статье iptables или nftables на Ubuntu.
Классический синтаксис nat on ... -> требует, чтобы правила трансляции стояли до правил фильтрации. Он работает и в 15.1, и в 14.5. В pf.conf(5) для 15.1 описан ещё и стиль OpenBSD с nat-to, но здесь выбран классический вариант, чтобы один файл подходил к обоим релизам.
NAT нужен не всегда. Он нужен, если клиенты выходят в интернет через сервер или ходят в сеть за сервером, у которой нет обратного маршрута в 10.8.0.0/24. Для site-to-site с нормальными маршрутами на обеих сторонах строку nat on можно убрать.
SSH: как включить pf удалённо и не потерять сервер
block in all и ошибка в правиле для порта 22 отрезают вас от собственного сервера. Ниже порядок, который оставляет путь назад. Отрепетируйте его, пока под рукой есть другой способ входа.
- Откройте консоль провайдера (VNC или serial) и убедитесь, что можете войти. Она не зависит от сети сервера и от pf.
- Проверьте синтаксис без загрузки правил:
pfctl -nf /etc/pf.conf. Пустой вывод означает, что файл разобран без ошибок. - Поставьте таймер отката, затем включите pf.
- Не закрывая текущую сессию, откройте новое SSH-подключение со своего компьютера.
pfctl -nf /etc/pf.conf
sysrc pf_enable=YES
nohup sh -c 'sleep 300; pfctl -d' > /dev/null 2>&1 &
service pf startЕсли новое подключение прошло, отмените откат:
pkill -f 'sleep 300; pfctl -d'Если не прошло, подождите пять минут. pfctl -d выключит pf, и доступ вернётся. Помните, что pf_enable=YES уже записан в rc.conf. Если вы перезагрузите сервер вместо ожидания, те же сломанные правила загрузятся снова, и останется только консоль провайдера.
Что произойдёт с уже открытой сессией в момент включения pf, здесь не утверждается. Проверьте это на своей машине с открытой консолью и не стройте на этом план. Настоящая проверка: новое подключение из шага 4.
Затем убедитесь, что правила на месте. pfctl -s nat должен показать ваше правило nat on. pfctl -s rules покажет правила фильтрации. В выводе pfctl -s info в строке Status должно быть Enabled. И откройте UDP 51820 в сетевом файрволе провайдера, если он у вас есть: это отдельная настройка в панели.
Клиент для админского доступа
[Interface]
PrivateKey = <приватный ключ клиента>
Address = 10.8.0.2/32
[Peer]
PublicKey = <содержимое server.pub>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25Узкий AllowedIPs = 10.8.0.0/24 отправляет в туннель только адреса VPN, остальной трафик идёт как обычно. Для админского доступа этого достаточно. Добавьте сети за сервером, если ходите в них. Полный туннель с 0.0.0.0/0 потребует ещё и DNS, это разобрано в статье о том, как починить DNS через WireGuard. Для связи двух серверов схема описана в руководстве по частной сети между двумя VPS.
Если рукопожатия нет или нет интернета
В wg show нет строки latest handshake. Пакеты не доходят или не принимаются. Проверьте файрвол провайдера, правило pass in on $ext_if proto udp to port 51820 и ключи: в [Peer] клиента должен стоять публичный ключ сервера, и наоборот. Команда tcpdump -ni vtnet0 udp port 51820 на сервере покажет, приходят ли пакеты вообще. Если ничего не приходит, причина снаружи сервера.
Рукопожатие есть, интернета нет. ping 10.8.0.1 с клиента отвечает, а ping 1.1.1.1 нет. Проверьте, что sysctl net.inet.ip.forwarding показывает 1. Потом посмотрите pfctl -v -s nat, пока клиент пингует. Если счётчик пакетов у правила nat on не растёт, в ext_if указано не то имя интерфейса.
Нужно больше подробностей от драйвера. ifconfig wg0 debug включает отладочные сообщения wg(4), их видно в dmesg.
Бэкап и обновления
Каталог /usr/local/etc/wireguard и есть сервер. Сохраните его вместе с /etc/pf.conf и /etc/rc.conf вне машины, и новый сервер поднимается за минуты. Если корень на ZFS, перед обновлением создайте boot environment командой bectl create pre-upgrade. Тогда неудачное обновление откатывается выбором старого окружения при загрузке. Подробности о ZFS на обеих системах в статье ZFS на FreeBSD и Linux.
Пакет wireguard-tools обновляется через pkg upgrade. Драйвер if_wg обновляется вместе с базовой системой: через freebsd-update или через pkg, если базу ставили пакетами. Как следить за уведомлениями безопасности, описано в статье об обновлениях и advisories FreeBSD. По состоянию на октябрь 2026 года ветка 14 представлена релизом 14.5, который вышел 8 сентября 2026 года. Все команды этого руководства в 14.5 те же.
MTU одной строкой
Если SSH работает, а большие страницы через туннель зависают, уменьшите MTU в [Interface] клиента до 1380, потом до 1280, а точный подбор описан в статье о медленном WireGuard и MTU.
FAQ
Нужен ли wireguard-go для WireGuard на FreeBSD 15.1?
Нет. Драйвер wg(4) вернулся в базовую систему в FreeBSD 13.2, поэтому в 14.5 и 15.1 туннель работает в ядре. Пакет wireguard-tools нужен только ради wg-quick и rc-скрипта. Проверка: kldload -n if_wg && echo ok. Если wg-quick пишет Missing WireGuard kernel support, вы, скорее всего, в джейле без своего сетевого стека.
Можно ли запустить WireGuard-сервер в VNET-джейле, а не на хосте?
Можно, но это руководство описывает только хост. Джейл должен быть VNET, то есть со своим сетевым стеком, иначе интерфейс wg0 в нём не создать. Джейл не может сам загрузить модуль ядра, поэтому if_wg грузят на хосте, например строкой if_wg_load="YES" в /boot/loader.conf. Правила pf и NAT тогда нужно продумать заново: какая часть живёт на хосте, а какая в джейле. Если сервер нужен для простого админского доступа, хост проще. Сравнение джейлов с контейнерами есть в статье о джейлах FreeBSD и Docker.
Работает ли эта настройка по IPv6?
Частично, и это нужно знать заранее. Правило pass in on $ext_if proto udp to port 51820 не ограничено inet, поэтому клиент может подключаться к серверу по IPv6. Внутри туннеля это руководство раздаёт только IPv4. Для IPv6 внутри туннеля нужны адрес в Address, sysrc ipv6_gateway_enable=YES и либо маршрутизируемый префикс от провайдера, либо отдельное правило NAT для inet6. Эта часть здесь не разобрана.
Почему клиент из России не подключается к серверу за границей?
Если рукопожатия нет, а tcpdump на сервере не видит пакетов, туннель, скорее всего, режется по пути. WireGuard не маскирует трафик, и на трансграничных маршрутах из российских сетей его, по многочисленным сообщениям, блокируют. Настройкой сервера это не исправить. Используйте такой сервер для админского доступа и связи площадок, а инструменты для обхода блокировок разобраны в статье что запускать, когда ваш VPN блокируют.