Недавно ко мне в руки попал мини-пк 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 и прокинули порты в виртуальные машины. Заголовок статьи был более громкий, чем на самом деле оказалась статья. Надеюсь, что эта заметка, которую я больше для себя делал, окажется полезной и другим.