Транспорт udp2raw: 443 -> 25565/tcp - 443 на сервере занят nginx (reverse-proxy Gitea totmaxim.ru); udp2raw в faketcp через правило -a перехватил бы весь TCP на своём порту и поломал nginx - server/client .service: -l/-r переведены на 25565 Клиент (Raspberry Pi): - wg0.conf: PreUp-маршрут 95.174.102.77/32 via 192.168.200.1 dev usbnet — устраняет петлю транспорта udp2raw при AllowedIPs=0.0.0.0/0 - nftables.conf: MSS-clamp для wlan0->wg0 (клиенты MTU 1500 vs туннель 1200) Сервер (Ubuntu за NAT 192.168.31.163): - wg0.conf: masquerade сужен до 10.66.66.0/24 в изолированной таблице wgfwd (не конфликтует с Docker), MSS-clamp на входе в туннель, MTU=1200 README: - фактическая топология (сервер за NAT, 95.174.102.77 = WAN роутера, проброс 25565 обязателен), таблица предусловий окружения и проверок - шаг закрепления net.ipv4.ip_forward, диагностика петли и выхода в интернет
Файл документации (README.md)
Схема WireGuard + udp2raw
Данный проект содержит конфигурации для развертывания отказоустойчивого VPN-туннеля между Удаленным сервером (Ubuntu 24.04) и Raspberry Pi 4.
Решение маскирует UDP-трафик WireGuard под стандартные TCP-пакеты (режим faketcp), что позволяет успешно обходить ограничения провайдеров, блокирующих или урезающих UDP-протокол на интерфейсе usbnet.
Порт входа —
25565/tcp, а не443. Порт443на сервере занят nginx (reverse-proxy для Giteatotmaxim.ru), иudp2rawв режимеfaketcp(через правило-a) перехватил бы весь TCP на своём порту, поломав nginx. Поэтому транспорт вынесен на выделенный25565/tcp.
0. Справочные данные и пути проекта
Архитектура и сетевые параметры
- Публичный вход сервера:
95.174.102.77:25565(TCP,udp2raw;443занят nginx/Gitea) - Внутренний порт WireGuard (Сервер):
127.0.0.1:51820 - Внутренний порт udp2raw (Клиент RPi):
127.0.0.1:51821 - Подсеть VPN:
10.66.66.0/24(Сервер:10.66.66.1, Клиент:10.66.66.2)
Фактическая топология (важно для маршрутизации)
Сервер (Ubuntu 24.04) — за NAT, НЕ имеет публичного IP напрямую:
- Внешний интерфейс:
enp2s0 = 192.168.31.163/24, шлюз192.168.31.1 95.174.102.77— это WAN-адрес роутера192.168.31.1, а НЕ адрес самого сервера- На хосте работает Docker (бриджи
172.17–172.21.0.0/16,docker0) со своими правилами nftables/iptables — поэтому WG-правила изолированы в отдельной таблицеwgfwdи маскарадят только10.66.66.0/24
Клиент (Raspberry Pi 4) — роутер для локальной сети:
- Uplink (в интернет):
usbnet = 192.168.200.13/24, шлюз и DNS192.168.200.1(мобильный канал; провайдер режет UDP → маскировка под TCP) - Downstream (клиенты):
wlan0 = 192.168.77.0/24— их трафик уходит в интернет через туннель - Прочие интерфейсы (
eth0 10.1.1.33,eth1 192.168.2.10) в схеме VPN не участвуют
⚠️ Обязательные требования к окружению (предусловия)
| # | Требование | Где | Проверка |
|---|---|---|---|
| 1 | Проброс порта TCP 25565 → 192.168.31.163:25565 на роутере 95.174.102.77 |
Роутер сервера | с клиента: nc -vz 95.174.102.77 25565 |
| 2 | net.ipv4.ip_forward = 1 (закрепить в /etc/sysctl.d/) |
Сервер + Клиент | sysctl net.ipv4.ip_forward |
| 3 | Порт 25565/tcp на хосте свободен; 443 оставить за nginx (Gitea) |
Сервер | sudo ss -ltnp 'sport = :25565' |
| 4 | Одинаковый пароль -k в обеих службах udp2raw |
Сервер + Клиент | сверить .service |
| 5 | Маршрут 95.174.102.77/32 via 192.168.200.1 dev usbnet при поднятом wg0 |
Клиент | ip route get 95.174.102.77 (должен быть dev usbnet, НЕ wg0) |
Почему требование #5 критично: на клиенте
AllowedIPs = 0.0.0.0/0, поэтомуwg-quickзаворачивает весь трафик вwg0. Без закреплённого маршрута сам транспортudp2raw(пакеты к95.174.102.77:25565) тоже уйдёт вwg0— получится петля, и туннель порвётся. Маршрут добавляется автоматически черезPreUpвclient/wg0.conf.
Актуальные ключи WireGuard
- Сервер (
95.174.102.77):- Public Key:
dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs= - Private Key:
KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=
- Public Key:
- Клиент (Raspberry Pi 4):
- Public Key:
WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI= - Private Key:
eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=
- Public Key:
⚠️ Важно: Перед запуском служб измените дефолтный пароль
"MY_CONFIDENTIAL_PASS"в аргументе-kв файлах.serviceна ваш собственный секретный пароль. Он должен быть одинаковым везде.
1. Спецификация релиза udp2raw
- Ссылка для скачивания архива:
https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz - Версия: 20230206.0
При распаковке архива (tar -xvf) используются только два конкретных файла:
udp2raw_amd64— устанавливается на Сервер (архитектура x86_64).udp2raw_arm_asm_aes— устанавливается на Raspberry Pi 4 (оптимизированный ARM-бинарник).
2. Пошаговое развертывание на СЕРВЕРЕ (Ubuntu)
Выполняется в терминале сервера (totserver@95.174.102.77):
Шаг 2.0. Подготовка окружения (проброс порта + форвардинг)
# 1) Убедитесь, что на роутере 95.174.102.77 проброшен TCP 25565 -> 192.168.31.163:25565
# 2) Включаем и ЗАКРЕПЛЯЕМ форвардинг пакетов (wg-quick сам его НЕ включает):
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wg.conf
sudo sysctl --system
# 3) Проверяем, что порт 25565 на хосте свободен (udp2raw слушает 0.0.0.0:25565).
# Порт 443 ДОЛЖЕН оставаться за nginx (Gitea) — udp2raw его не трогает:
sudo ss -ltnp 'sport = :25565'
Шаг 2.1. Установка WireGuard
sudo apt update && sudo apt install wireguard -y
Шаг 2.2. Скачивание и сборка udp2raw
Bash
mkdir -p ~/download && cd ~/download
wget [https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz](https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz)
tar -xvf udp2raw_binaries.tar.gz
# Копируем x86_64 бинарник в системный путь и даем права
sudo cp udp2raw_amd64 /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
Шаг 2.3. Создание конфигурационных файлов
Создайте конфиг WireGuard: sudo nano /etc/whiteguard/wg0.conf (или /etc/wireguard/wg0.conf)
Ini, TOML
[Interface]
Address = 10.66.66.1/24
ListenPort = 51820
PrivateKey = KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=
MTU = 1200
# Изолированная таблица wgfwd: masquerade ТОЛЬКО 10.66.66.0/24 (не конфликтует с Docker)
# + MSS-clamp на входе в туннель. PostDown сносит всё одной командой.
PostUp = nft add table ip wgfwd
PostUp = nft add chain ip wgfwd postrouting { type nat hook postrouting priority 100 \; policy accept \; }
PostUp = nft add rule ip wgfwd postrouting ip saddr 10.66.66.0/24 oifname "enp2s0" masquerade
PostUp = nft add chain ip wgfwd mangle { type filter hook forward priority -150 \; policy accept \; }
PostUp = nft add rule ip wgfwd mangle oifname "wg0" tcp flags syn tcp option maxseg size set rt mtu
PostDown = nft delete table ip wgfwd
[Peer]
PublicKey = WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=
AllowedIPs = 10.66.66.2/32
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-server.service
Ini, TOML
[Unit]
Description=udp2raw Server (FakeTCP)
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/udp2raw -s -l 0.0.0.0:25565 -r 127.0.0.1:51820 -k "MY_CONFIDENTIAL_PASS" --raw-mode faketcp -a
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Шаг 2.4. Запуск служб на сервере
Bash
sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-server
sudo systemctl enable --now wg-quick@wg0
3. Пошаговое развертывание на КЛИЕНТЕ (Raspberry Pi 4)
Выполняется в терминале малинки (user@raspberrypi):
Шаг 3.1. Установка WireGuard
Bash
sudo apt update && sudo apt install wireguard -y
Шаг 3.2. Доставка бинарника udp2raw
Если малинка имеет доступ к интернету, скачайте архив прямо на неё:
Bash
mkdir -p ~/download && cd ~/download
wget [https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz](https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz)
tar -xvf udp2raw_binaries.tar.gz
# Переносим специализированный ARM-бинарник в системный путь
sudo cp udp2raw_arm_asm_aes /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
Шаг 3.3. Настройка сетевого экрана (nftables)
Учитывая строгую политику policy drop на вашей Raspberry Pi, откройте текущие правила:
Bash
sudo nano /etc/nftables.conf
Добавьте/разрешите следующие строки в соответствующие таблицы:
В table inet filter -> chain input:
Code snippet
iifname "lo" accept
iifname "wg0" accept
В table inet filter -> chain forward:
Code snippet
iifname "wlan0" oifname "wg0" accept
iifname "wg0" oifname "wlan0" ct state established,related accept
# MSS-clamp: клиенты (MTU 1500) не знают про туннель 1200 -> иначе крупный TCP залипает
iifname "wlan0" oifname "wg0" tcp flags syn tcp option maxseg size set rt mtu
В table ip nat -> chain postrouting:
Code snippet
ip saddr 192.168.77.0/24 oifname "wg0" masquerade
Примените изменения: sudo nft -f /etc/nftables.conf
Шаг 3.4. Создание конфигурационных файлов
Создайте конфиг WireGuard: sudo nano /etc/wireguard/wg0.conf
Ini, TOML
[Interface]
Address = 10.66.66.2/24
PrivateKey = eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=
MTU = 1200
# КРИТИЧНО (анти-петля): маршрут к серверу через реальный uplink ДО поднятия default в wg0.
# 192.168.200.1 — шлюз usbnet; при смене канала поправить адрес здесь.
PreUp = ip route replace 95.174.102.77/32 via 192.168.200.1 dev usbnet
PostDown = ip route del 95.174.102.77/32 2>/dev/null || true
[Peer]
PublicKey = dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=
Endpoint = 127.0.0.1:51821
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-client.service
Ini, TOML
[Unit]
Description=udp2raw Client (FakeTCP)
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/udp2raw -c -l 127.0.0.1:51821 -r 95.174.102.77:25565 -k "MY_CONFIDENTIAL_PASS" --raw-mode faketcp -a
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Шаг 3.5. Запуск служб на клиенте
Bash
sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-client
sudo systemctl enable --now wg-quick@wg0
4. Диагностика и проверка статуса
При возникновении неполадок проверяйте компоненты строго по цепочке от нижнего уровня к верхнему:
1. Проверка работоспособности FakeTCP (udp2raw)
На клиенте: sudo systemctl status udp2raw-client
На сервере: sudo systemctl status udp2raw-server
Критерий успеха: Строка состояния [ready] в логах сервиса и отсутствие циклических перезапусков.
2. Проверка туннеля WireGuard
На любом из устройств: sudo wg show
Критерий успеха: Наличие строчки latest handshake: X seconds ago (данные должны обновляться и не сбрасываться).
3. Проверка сетевого уровня (Пинг)
С Raspberry Pi запустите: ping 10.66.66.1
Если пинг идет, но интернета на устройствах за малинкой (wlan0) нет — перепроверяйте синтаксис правил в /etc/nftables.conf и masquerade на сервере.
4. Проверка отсутствия петли (при поднятом wg0)
На клиенте: `ip route get 95.174.102.77`
Критерий успеха: маршрут идёт через `dev usbnet` (шлюз 192.168.200.1), а НЕ через `dev wg0`.
Если видите `dev wg0` — не отработал `PreUp` из `wg0.conf`, транспорт закольцован.
5. Проверка выхода в интернет через туннель
С устройства за малинкой (192.168.77.0/24): `curl -s https://ifconfig.me`
Критерий успеха: возвращается публичный IP канала сервера (сети `192.168.31.1`), а не мобильного канала клиента.
6. Доступность публичного входа (проброс 25565)
С клиента: `nc -vz 95.174.102.77 25565` — порт должен быть открыт (проброс на роутере сервера).