Недавно ко мне в руки попал мини-пк Junibox K3+ и решил из него сделать домашний мини-сервер. Однако мне было лень тянуть новый провод для него, поэтому было решено подключить его с помощью WiFi. Оказалось, это не такая и тривиальная задача, как тыкнуть пару раз по нужным кнопкам, так как proxmox из коробки не приспособлен для работы беспровода. Я прочитал пару гайдов и готов поделиться полученными знаниями с такими же изыскателями.
Подключаемся к WiFi
Сразу скажу, что нам потребуется всё-таки интернет-провод, так как модуль для работы с WiFi в базовой комплектации отсутствует, и его потребуется загрузить. Но об этом далее.
Начнём с того, что нам потребуется образ proxmox. Для этого на официальном сайте грузим образ Proxmox Virtual Environment (далее — PVE). На данный момент последняя доступная версия 9.1.
Загрузив образ, идём либо прожигаем флешку с помощью какого-нибудь balenaEtcher или аналогичных программ, либо накатываем на флешку Ventoy и закидываем туда iso образ.
В силу того, что мне не нужно ничего эзотерического, я всё время жмякаю на кнопку «Далее», поэтому не буду показывать процесс установки PVE. Наверное, если хоть раз в жизни ставили операционную систему, проблем возникнуть не должно, она довольно элементарная.
Первым делом, отключив платные репозитории, установим пакет wpa_supplicant и wireless-tools. Первый позволит подключаться к WiFi, а второй даст доступ к команде iwconfig, если возникнут проблемы с определением нужного нам интерфейса.
apt update
apt install -y wpasupplicant wireless-tools
Определим нужный нам интерфейс, упомянутой выше командой, и получим следующего вида вывод. Нужный нам интерфейс имеет имя wlp3s0. На момент написания статьи у меня уже всё подключено, поэтому вывод может немного отличаться.
root@pve:~# iwconfig
lo no wireless extensions.
enp2s0 no wireless extensions.
wlp3s0 IEEE 802.11 ESSID:"WIFINAME"
Mode:Managed Frequency:5.18 GHz Access Point: A3:C1:83:CC:A9:F9
Bit Rate=40.5 Mb/s Tx-Power=20 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Encryption key:off
Power Management:on
Link Quality=48/70 Signal level=-62 dBm
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:6 Invalid misc:35 Missed beacon:0
vmbr0 no wireless extensions.
Открываем /etc/network/interfaces для редактирования, например, в nano. И приводим часть, связанную с wlp3s0, к следующему виду. Не забудьте добавить auto wlp3s0, чтобы подключение происходило автоматически при запуске системы, а то после первой же перезагрузки придётся снова втыкать провода и подключать его. И да, адрес мы будем получать по DHCP, но вы можете забить адрес ручками.
# network interface settings; autogenerated
# Please do NOT modify this file directly, unless you know what
# you're doing.
#
# If you want to manage parts of the network configuration manually,
# please utilize the 'source' or 'source-directory' directives to do
# so.
# PVE will preserve these directives, but will NOT read its network
# configuration from sourced files, so do not attempt to move any of
# the PVE managed interfaces into external files!
auto lo
iface lo inet loopback
iface enp2s0 inet manual
auto wlp3s0
iface wlp3s0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
auto vmbr0
iface vmbr0 inet manual
source /etc/network/interfaces.d/*
Теперь создадим файл конфигурации с данными для подключения к нашей WiFi-точке. Для этого воспользуемся утилитой wpa_passphrase, в которую передаём название нашей точки и пароль, после чего заносим сгенерированный ключ в файл /etc/wpa_supplicant/wpa_supplicant.conf.
wpa_passphrase WIFINAME PASSWORD >> /etc/wpa_supplicant/wpa_supplicant.conf
Теперь откроем этот же файл в nano и добавим следующие строки в начало файла. Если честно, то я понятия не имею, что они делают, прошу просветить меня в комментариях.
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="WIFINAME"
#psk="PASSWORD"
psk=f717843d2b617ba5f0bb6fb0b0fb62397ba0a3fd4df4de72ac2f6177c9cb4f2a
}
Теперь вручную запустим подключение интерфейса к WiFi.
ifup wlp3s0
Если выскочила ошибка о том, что файл dhclient не найден, то просто установите его.
apt install -y isc-dhcp-client
Если всё прошло хорошо, то при вызове команды ip address мы должны увидеть состояние интерфейса как UP с полученным IP-адресом.

Прокидываем сеть
Всё работает, отлично, можно отключить интернет-провод. Но проблема возникает тогда, когда мы хотим прокинуть интерфейс в виртуалки, так как изначально он не входит в виртуальный бридж vmbrN. Насколько мне известно, некоторые прокидывают WiFi-адаптер как PCI- устройство, но данный способ не работает в 100% случаев, если верить комментариям на форумах и гайдах.
Поэтому мы пойдём путём с пробросом портов. То есть мы создадим новый бридж, через который будет общение с виртуалками, а правилами iptables будем прокидывать порты. Чтобы не ковыряться с сетевыми настройками каждой виртуалки, будем ещё и IP-адреса через DHCP выдавать. Всё это выглядеть будет примерно так:

Создаём бридж
Для начала снова откроем файл /etc/network/interfaces и добавим к vmbr0 следующие строки, где зададим статический IP-адрес и команды, выполняемые при поднятии интерфейса, включающие добавление и удаление маршрутов iptables.
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
post-up echo 1 > /proc/sys/net/ipv4/conf/vmbr0/proxy_arp
post-up iptables -t nat -A POSTROUTING -s '10.10.10.1/24' -o wlp3s0 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '10.10.10.1/24' -o wlp3s0 -j MSQUERADE
Настраиваем DHCP
Можете пропустить данный раздел, если не нужен DHCP. Я же установлю dnsmasq.
apt install -y dnsmasq dnsutils
И сразу настроим его, отредактировав файл /etc/dnsmasq.conf и добавив следующее содержимое.
domain=dnsmasq.local
interface=vmbr0
# range
dhcp-range=10.10.10.10,10.10.10.200,12h
# mask
dhcp-option=1,255.255.255.0
# gateway
dhcp-option=vmbr0,3,10.10.10.1
# leases
dhcp-hostsfile=/etc/dnsmasq-hosts.conf
# leases log
dhcp-leasefile=/var/log/dnsmasq/dnsmasq.leases
# DNS
server=10.10.10.1
server=1.1.1.1
server=8.8.8.8
# cache
cache-size=10000
all-servers
no-negcache
# logs
log-queries
log-facility=/var/log/dnsmasq/dnsmasq.log
И теперь можем закрепить за нужной виртуалкой адрес, для этого нужно раздобыть MAC-адрес её сетевухи.

Этот адрес вносим в файл /etc/dnsmasq-hosts.conf, указав требуемый IP-адрес, который будет закреплён за этой виртуалкой. В моём случае, это будет адрес 10.10.10.10.
BC:24:11:97:73:A2,10.10.10.10 # Home Assistant
Теперь можем перезапустить службу dnsmasq, чтобы применились настройки.
systemctl restart dnsmasq
Виртуалки могут не подхватить адрес, если они уже запущены, поэтому чтобы вручную каждую не настраивать, можете просто перезапустить все командами.
# список виртуалок
vms=$(qm list | awk '{print $1}' | tail -n +2)
# мягкая остановка
for vm in $vms; do qm shutdown $vm; done
# запуск
for vm in $vms; do qm start $vm; done
Посмотреть, кому какой адрес выдался, можно в файле /var/log/dnsmasq/dnsmasq.leases.

Если адрес подцепился, как в примере выше, то виртуалки имеют доступ в сеть, но они за NAT-ом, поэтому нужно оформить проброс портов.
Проброс портов
Как ранее упоминалось, виртуальные машины теперь имеют доступ в сеть, но они находятся за NAT-ом, поэтому так просто к ним не обратиться. Чтобы это решить, нужно создать проброс портов в iptables.
Для этого создадим скрипт /root/run-portforwarding.sh со следующим содержимым:
#!/bin/bash
EXT_IP="192.168.1.10" # внешний, реальный IP-адрес шлюза;
INT_IP="10.10.10.1" # внутренний IP-адрес шлюза, в локальной сети;
EXT_IF=wlp3s0 # внешний и внутренний интерфейсы.
INT_IF=wlp3s0 # внутренний интерфейс шлюза, с адресом $INT_IP;
FAKE_PORT=$1 # как первый параметр, передаём скрипту "нестандартный" порт на внешнем интерфейсе,
LAN_IP=$2 # второй параметр, внутренний IP-адрес сервера, предоставляющего службы/сервисы внешнему миру;
SRV_PORT=$3 # порт службы/сервиса. Для веб-сервера равен 80, для SMTP - 25 и т.д.;
iptables -t nat -A PREROUTING -d $EXT_IP -p tcp -m tcp --dport $FAKE_PORT -j DNAT --to-destination $LAN_IP:$SRV_PORT
iptables -t nat -A POSTROUTING -d $LAN_IP -p tcp -m tcp --dport $SRV_PORT -j SNAT --to-source $INT_IP
iptables -t nat -A OUTPUT -d $EXT_IP -p tcp -m tcp --dport $SRV_PORT -j DNAT --to-destination $LAN_IP
iptables -I FORWARD 1 -i $EXT_IF -o $INT_IF -d $LAN_IP -p tcp -m tcp --dport $SRV_PORT -j ACCEPT
Сохранив файл, выдадим ему права на исполнение.
chmod +x /root/run-portforwarding.sh
Воспользуемся скриптом, прокинув порт 8123, на котором хостится панель управления Home Assistant.
/root/run-portforwarding.sh 8123 10.10.10.10 8123
Если вы перешли по адресу сервера и вас встретила панель управления, то поздравляю, всё работает. Чтобы пробросы не слетели при следующем же перезапуске, то стоит добавить активацию скрипта в автозагрузки.
Для этого создадим файл /etc/systemd/system/home-assistant.service задачи с описанием того, что вообще надо делать. Тут у меня сразу два порта пробрасывается, один из которых для SSH.
[Unit]
Description=Run Home Assistant Port Forwarding Script
[Service]
ExecStartPre=/bin/bash -c "/root/run-portforwarding.sh 8022 10.10.10.10 22"
ExecStart=/bin/bash -c "/root/run-portforwarding.sh 8123 10.10.10.10 8123"
User=root
[Install]
WantedBy=multi-user.target
После чего включим автозапуск данной задачи командой:
systemctl enable home-assistant.service
Итого
Мы настроили WiFi и прокинули порты в виртуальные машины. Заголовок статьи был более громкий, чем на самом деле оказалась статья. Надеюсь, что эта заметка, которую я больше для себя делал, окажется полезной и другим.
Комментарии (14)

Vedga
21.12.2025 17:50Засунуть интерфейс wlp3s0 сразу в бридж религия не позволила?
По поводу sysctl: прописать значения в /etc/sysctl.d/ (или какой путь в этой ОС определен в /etc/sysctl.conf) не выглядит более стандартным решением?
Правила iptables интереснее в скрипте писать, вместо использования пакета netfilter-persistent?
Но для начала неплохо. Хотя ha удобнее ставить в докер (контейнер с ha, контейнер с nginx если светить в мир, контейнер с zigbee2mqtt, контейнер с mosquitto и по крону запуск в контейнере обновления letsencrypt).

COTTONMAUS
21.12.2025 17:50Если всё вот это проще, почему же мы не видим от тебя инструкции в ленте и в Гугл новостях по интересам?

Ertanic Автор
21.12.2025 17:50Я пробовал засунуть в бридж, но ничего не заработало. Чувствую, я не один такой, если похожая проблема описана в официальной вики.
А на счёт sysctl и netfilter-persistent спасибо, посмотрю и дополню статью, когда свободное время будет.

Vedga
21.12.2025 17:50Судя по статье, у других не заработало прокидывание pci-железа в VM. Под твою задачу такое делать в здравом уме не надо, согласен.
"Добавить в бридж" - в описании интерфейса бриджа в качестве сетевого интерфейса добавить интерфейс wifi. DHCP-клиента селить на бридж или использовать статику. У самого wifi-интерфейса адреса быть не должно, просто сделать ему up. Для отладки (proxmox может ставить свои правила iptables) смотреть iptables -L -v -n (-t таблица, при необходимости).
Но докер удобнее: обновляешь контейнер с готового образа из dockerhub, при этом конфиги сохраняются, т.к. они монтируются к контейнеру. В proxmox все обновлять руками, что обычно лениво.

kvazimoda24
21.12.2025 17:50netfilter-persistent
NFTables в Проксмоксе пока в тестовом режиме добавлен. А смешивать два варианта я бы не стал. Да и не уверен, что такое смешивание что-нибудь не сломает.

marineboy1
21.12.2025 17:50wireless-tools считается устаревшим, его заменил iw. Но проще через iwd, и его довольно удобный CLI iwcli.

falcon4fun
21.12.2025 17:50Один вопрос: зоооооочээээм?!
Такой колхоз официально вообще никак не поддерживается и не рекомендуется. И ни в одном проде, даже уровня "домашний", его быть не должно.

Ertanic Автор
21.12.2025 17:50Не рекомендуется, но этот колхоз предлагается как один из вариантов решения проблемы на вики разработчиков.

Vedga
21.12.2025 17:50Wi-Fi adapters can only be used as Linux bridge interface through workarounds, as most Access Points (APs) will reject frames that have a source address that didn’t authenticate with the AP.
Ну разве что на каких-то ширпотребовских AP могут быть такие ограничения. Тогда да, решение имеет право на жизнь. Не удобно: по-хорошему еще нужно прокинуть порт для ssh внутрь контейнера (для отладки/обновления). А потом вспоминать, на какой порт ты его повесил.
Удобнее wifi ap в bridge mode загнать (если позволяет). Но вообще да, решение зависит от возможностей имеющегося в наличии оборудования.

ProMix
21.12.2025 17:50Добавлю от себя на тему маков, что клиентский адаптер может уметь делать NAT 2.5, а ещё оба устройства могут уметь в A4 (aka четырёхадресная адресация)
Второй вариант менее костыльный

kij0775
21.12.2025 17:50Делается намного проще, и нат для этого не нужен. Достаточно включить роутинг на хосте, и прописать маршрут на шлюзе для сети гостей. Если гостям нужно инет, проще натить опять же с шлюза.
serg-novoch
Тоже столкнулся с этой проблемой, но решил не мудрить и подключить ещё один роутер по проводу, который работает как wifi клиент от основного роутера.