Files
vpn-raspberry/README.md
Maxim 886ba62ea6 Исправление маршрутизации, порт 25565 и документирование окружения
Транспорт 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, диагностика петли и выхода в интернет
2026-07-07 13:16:50 +03:00

14 KiB
Raw Blame History

Файл документации (README.md)

Схема WireGuard + udp2raw

Данный проект содержит конфигурации для развертывания отказоустойчивого VPN-туннеля между Удаленным сервером (Ubuntu 24.04) и Raspberry Pi 4.

Решение маскирует UDP-трафик WireGuard под стандартные TCP-пакеты (режим faketcp), что позволяет успешно обходить ограничения провайдеров, блокирующих или урезающих UDP-протокол на интерфейсе usbnet.

Порт входа — 25565/tcp, а не 443. Порт 443 на сервере занят nginx (reverse-proxy для Gitea totmaxim.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.17172.21.0.0/16, docker0) со своими правилами nftables/iptables — поэтому WG-правила изолированы в отдельной таблице wgfwd и маскарадят только 10.66.66.0/24

Клиент (Raspberry Pi 4) — роутер для локальной сети:

  • Uplink (в интернет): usbnet = 192.168.200.13/24, шлюз и DNS 192.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=
  • Клиент (Raspberry Pi 4):
    • Public Key: WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=
    • Private Key: eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=

⚠️ Важно: Перед запуском служб измените дефолтный пароль "MY_CONFIDENTIAL_PASS" в аргументе -k в файлах .service на ваш собственный секретный пароль. Он должен быть одинаковым везде.


1. Спецификация релиза udp2raw

  • Ссылка для скачивания архива: https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz
  • Версия: 20230206.0

При распаковке архива (tar -xvf) используются только два конкретных файла:

  1. udp2raw_amd64 — устанавливается на Сервер (архитектура x86_64).
  2. 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` — порт должен быть открыт (проброс на роутере сервера).