README: чистое форматирование + раздел тюнинга

- Переписан весь README с корректной markdown-разметкой (закрыты код-блоки,
  убраны литеральные "Bash"/"Ini, TOML"/"Code snippet", исправлены заголовки
  и съехавшие таблицы, устранена двойная нумерация раздела 4)
- install -m 755 вместо cp+chmod, бинарник ФАЙЛОМ (частая ошибка на Pi)
- Раздел 5 "Известные нюансы": автозагрузка с порядком запуска,
  диагностика "не все сайты" (QUIC/MTU), устранение дублей nftables
This commit is contained in:
Maxim
2026-07-07 16:24:57 +03:00
parent 5ab5ad2dce
commit 888fd86dfa
3 changed files with 138 additions and 142 deletions

278
README.md
View File

@@ -1,112 +1,105 @@
Файл документации (README.md)
# Схема WireGuard + udp2raw # Схема WireGuard + udp2raw
Данный проект содержит конфигурации для развертывания отказоустойчивого VPN-туннеля между **Удаленным сервером (Ubuntu 24.04)** и **Raspberry Pi 4**. Проект содержит конфигурации для развёртывания отказоустойчивого VPN-туннеля между **удалённым сервером (Ubuntu 24.04)** и **Raspberry Pi 4**.
Решение маскирует UDP-трафик WireGuard под стандартные TCP-пакеты (режим `faketcp`), что позволяет успешно обходить ограничения провайдеров, блокирующих или урезающих UDP-протокол на интерфейсе `usbnet`. Решение маскирует UDP-трафик WireGuard под обычные TCP-пакеты (режим `faketcp`), что позволяет обходить ограничения провайдеров, блокирующих или урезающих UDP на интерфейсе `usbnet`.
> **Порт входа — `25565/tcp`, а не `443`.** Порт `443` на сервере занят nginx (reverse-proxy для Gitea `totmaxim.ru`), и `udp2raw` в режиме `faketcp` (через правило `-a`) перехватил бы весь TCP на своём порту, поломав nginx. Поэтому транспорт вынесен на выделенный `25565/tcp`. > **Порт входа — `25565/tcp`, а не `443`.** Порт `443` на сервере занят nginx (reverse-proxy для Gitea `totmaxim.ru`); `udp2raw` в режиме `faketcp` через правило `-a` перехватил бы весь TCP на своём порту и поломал nginx. Поэтому транспорт вынесен на выделенный `25565/tcp`.
--- ---
## 0. Справочные данные и пути проекта ## 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`) | Публичный вход сервера | `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`) |
| MTU туннеля | `1200` (симметрично на обоих концах) |
### Фактическая топология (важно для маршрутизации) ### Фактическая топология (важно для маршрутизации)
**Сервер (Ubuntu 24.04) — за NAT, НЕ имеет публичного IP напрямую:** **Сервер (Ubuntu 24.04) — за NAT, без прямого публичного IP:**
* Внешний интерфейс: `enp2s0 = 192.168.31.163/24`, шлюз `192.168.31.1` - Внешний интерфейс: `enp2s0 = 192.168.31.163/24`, шлюз `192.168.31.1`.
* `95.174.102.77` это WAN-адрес роутера `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` - На хосте работает Docker (бриджи `172.17172.21.0.0/16`, `docker0`) со своими правилами nftables/iptables — поэтому правила WG изолированы в отдельной таблице `wgfwd` и маскарадят **только** `10.66.66.0/24`.
**Клиент (Raspberry Pi 4) — роутер для локальной сети:** **Клиент (Raspberry Pi 4) — роутер для локальной сети:**
* Uplink (в интернет): `usbnet = 192.168.200.13/24`, шлюз и DNS `192.168.200.1` (мобильный канал; провайдер режет UDP → маскировка под TCP) - Uplink: `usbnet = 192.168.200.13/24`, шлюз и DNS `192.168.200.1` (мобильный канал; провайдер режет UDP → маскировка под TCP).
* Downstream (клиенты): `wlan0 = 192.168.77.0/24` их трафик уходит в интернет через туннель - Downstream: `wlan0 = 192.168.77.0/24` — трафик клиентов уходит в интернет через туннель.
* Прочие интерфейсы (`eth0 10.1.1.33`, `eth1 192.168.2.10`) в схеме VPN не участвуют - Прочие интерфейсы (`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` | | 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` | | 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'` | | 3 | Порт `25565/tcp` на хосте свободен; `443` оставить за nginx | Сервер | `sudo ss -ltnp 'sport = :25565'` |
| 4 | Одинаковый пароль `-k` в обеих службах `udp2raw` | Сервер + Клиент | сверить `.service` | | 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 | Маршрут `95.174.102.77/32 via 192.168.200.1 dev usbnet` при поднятом `wg0` | Клиент | `ip route get 95.174.102.77` `dev usbnet`, НЕ `wg0` |
| 6 | Установлен пакет `iptables` (udp2raw добавляет правило `-a` только через него) | Клиент (чистый nft) | `iptables -V` | | 6 | Установлен пакет `iptables` (udp2raw добавляет правило `-a` только через него) | Клиент | `iptables -V` |
| 7 | udp2raw на сервере слушает `192.168.31.163`, а НЕ `0.0.0.0` (иначе `bind fail` из-за docker-бриджей) | Сервер | см. `-l` в `.service` | | 7 | udp2raw на сервере слушает `192.168.31.163`, а НЕ `0.0.0.0` (иначе `bind fail` из-за docker-бриджей) | Сервер | см. `-l` в `.service` |
> **Заметка по портам/интерфейсам, проверено на стенде:** faketcp-рукопожатие успешно проходит (сервер `server_ready`, клиент `client_ready`). Клиент виден серверу под мобильным публичным IP (напр. `95.174.126.11`). Привязка сервера к `0.0.0.0` даёт `bind fail` — обязательно указывать конкретный IP интерфейса. > **Почему #5 критично:** на клиенте `AllowedIPs = 0.0.0.0/0`, поэтому `wg-quick` заворачивает весь трафик в `wg0`. Без закреплённого маршрута сам транспорт `udp2raw` (пакеты к `95.174.102.77:25565`) тоже уйдёт в `wg0` — получится **петля**, и туннель порвётся. Маршрут ставится автоматически через `PreUp` в `client/wg0.conf`.
> **Почему требование #5 критично:** на клиенте `AllowedIPs = 0.0.0.0/0`, поэтому `wg-quick` заворачивает весь трафик в `wg0`. Без закреплённого маршрута сам транспорт `udp2raw` (пакеты к `95.174.102.77:25565`) тоже уйдёт в `wg0` — получится **петля**, и туннель порвётся. Маршрут добавляется автоматически через `PreUp` в `client/wg0.conf`. ### Ключи WireGuard
### Актуальные ключи WireGuard - **Сервер:** pub `dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=` / priv `KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=`
* **Сервер (`95.174.102.77`):** - **Клиент:** pub `WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=` / priv `eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=`
* Public Key: `dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=`
* Private Key: `KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=`
* **Клиент (Raspberry Pi 4):**
* Public Key: `WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=`
* Private Key: `eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=`
> ⚠️ **Важно:** Перед запуском служб измените дефолтный пароль `"MY_CONFIDENTIAL_PASS"` в аргументе `-k` в файлах `.service` на ваш собственный секретный пароль. Он должен быть одинаковым везде. > ⚠️ Перед боевым запуском смените дефолтный пароль `MY_CONFIDENTIAL_PASS` в аргументе `-k` обеих служб `.service`. Он должен быть **одинаковым** на сервере и клиенте.
--- ---
## 1. Спецификация релиза udp2raw ## 1. Релиз udp2raw
* **Ссылка для скачивания архива:** `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`
* **Версия:** 20230206.0 - Версия: `20230206.0`
При распаковке архива (`tar -xvf`) используются только два конкретных файла: Из архива нужны только два файла:
1. `udp2raw_amd64` устанавливается на **Сервер** (архитектура x86_64). 1. `udp2raw_amd64` — на **сервер** (x86_64).
2. `udp2raw_arm_asm_aes` — устанавливается на **Raspberry Pi 4** (оптимизированный ARM-бинарник). 2. `udp2raw_arm64` (64-битная RPi OS, `aarch64`) или `udp2raw_arm_asm_aes` (32-битная, `armv7l`) — на **Raspberry Pi**. Уточнить: `uname -m`.
--- ---
## 2. Пошаговое развертывание на СЕРВЕРЕ (Ubuntu) ## 2. Развёртывание на СЕРВЕРЕ (Ubuntu)
Выполняется в терминале сервера (`totserver@95.174.102.77`): ### Шаг 2.0. Подготовка окружения
### Шаг 2.0. Подготовка окружения (проброс порта + форвардинг)
```bash ```bash
# 1) Убедитесь, что на роутере 95.174.102.77 проброшен TCP 25565 -> 192.168.31.163:25565 # 1) Проброс на роутере: TCP 25565 -> 192.168.31.163:25565 (проверить заранее)
# 2) Включаем и ЗАКРЕПЛЯЕМ форвардинг пакетов (wg-quick сам его НЕ включает): # 2) Включаем и закрепляем форвардинг (wg-quick сам его НЕ включает):
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wg.conf echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wg.conf
sudo sysctl --system sudo sysctl --system
# 3) Проверяем, что порт 25565 на хосте свободен (udp2raw слушает 192.168.31.163:25565). # 3) Порт 25565 на хосте должен быть свободен (443 остаётся за nginx):
# Порт 443 ДОЛЖЕН оставаться за nginx (Gitea) — udp2raw его не трогает:
sudo ss -ltnp 'sport = :25565' sudo ss -ltnp 'sport = :25565'
# ПРИМЕЧАНИЕ: udp2raw слушает КОНКРЕТНЫЙ IP 192.168.31.163, а НЕ 0.0.0.0.
# На 0.0.0.0 из-за множества docker-бриджей он падает с "bind fail" (проверено).
``` ```
### Шаг 2.1. Установка WireGuard ### Шаг 2.1. Установка WireGuard
```bash ```bash
sudo apt update && sudo apt install wireguard -y sudo apt update && sudo apt install wireguard -y
```
### Шаг 2.2. Установка бинарника udp2raw
Шаг 2.2. Скачивание и сборка udp2raw ```bash
Bash
mkdir -p ~/download && cd ~/download 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) wget https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz
tar -xvf udp2raw_binaries.tar.gz tar -xvf udp2raw_binaries.tar.gz
sudo install -m 755 udp2raw_amd64 /usr/local/bin/udp2raw # именно ФАЙЛОМ, не каталогом
udp2raw -h >/dev/null && echo OK
```
# Копируем x86_64 бинарник в системный путь и даем права ### Шаг 2.3. Конфигурации
sudo cp udp2raw_amd64 /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
`/etc/wireguard/wg0.conf` (права `600`):
Шаг 2.3. Создание конфигурационных файлов ```ini
Создайте конфиг WireGuard: sudo nano /etc/whiteguard/wg0.conf (или /etc/wireguard/wg0.conf)
Ini, TOML
[Interface] [Interface]
Address = 10.66.66.1/24 Address = 10.66.66.1/24
ListenPort = 51820 ListenPort = 51820
@@ -125,10 +118,11 @@ PostDown = nft delete table ip wgfwd
[Peer] [Peer]
PublicKey = WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI= PublicKey = WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=
AllowedIPs = 10.66.66.2/32 AllowedIPs = 10.66.66.2/32
```
`/etc/systemd/system/udp2raw-server.service` (не забыть заменить пароль в `-k`):
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-server.service ```ini
Ini, TOML
[Unit] [Unit]
Description=udp2raw Server (FakeTCP) Description=udp2raw Server (FakeTCP)
After=network.target After=network.target
@@ -136,93 +130,85 @@ After=network.target
[Service] [Service]
Type=simple Type=simple
User=root User=root
# Слушать КОНКРЕТНЫЙ IP 192.168.31.163 (на 0.0.0.0 — bind fail из-за docker-бриджей)
ExecStart=/usr/local/bin/udp2raw -s -l 192.168.31.163:25565 -r 127.0.0.1:51820 -k "MY_CONFIDENTIAL_PASS" --raw-mode faketcp -a ExecStart=/usr/local/bin/udp2raw -s -l 192.168.31.163:25565 -r 127.0.0.1:51820 -k "MY_CONFIDENTIAL_PASS" --raw-mode faketcp -a
Restart=always Restart=always
RestartSec=5 RestartSec=5
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
```
### Шаг 2.4. Запуск (сначала транспорт, потом туннель)
Шаг 2.4. Запуск служб на сервере ```bash
Bash
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-server sudo systemctl start udp2raw-server # или enable --now — для автозагрузки
sudo systemctl enable --now wg-quick@wg0 sudo systemctl start wg-quick@wg0
sudo wg show
sudo nft list table ip wgfwd
```
---
3. Пошаговое развертывание на КЛИЕНТЕ (Raspberry Pi 4) ## 3. Развёртывание на КЛИЕНТЕ (Raspberry Pi 4)
Выполняется в терминале малинки (user@raspberrypi):
Шаг 3.1. Установка WireGuard и iptables
### Шаг 3.1. Установка WireGuard и iptables
```bash
Bash
# iptables обязателен: на чистой nft-системе udp2raw не сможет добавить правило -a # iptables обязателен: на чистой nft-системе udp2raw не сможет добавить правило -a
sudo apt update && sudo apt install wireguard iptables -y sudo apt update && sudo apt install wireguard iptables -y
iptables -V # должно печатать версию (nf_tables) iptables -V # должно печатать версию (nf_tables)
```
### Шаг 3.2. Установка бинарника udp2raw
Шаг 3.2. Доставка бинарника udp2raw ```bash
# Внимание: положить бинарник ФАЙЛОМ по пути /usr/local/bin/udp2raw (не каталогом!).
# Архитектура: aarch64 -> udp2raw_arm64, armv7l -> udp2raw_arm_asm_aes (см. `uname -m`).
Если малинка имеет доступ к интернету, скачайте архив прямо на неё:
Bash
mkdir -p ~/download && cd ~/download 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) wget https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz
tar -xvf udp2raw_binaries.tar.gz tar -xvf udp2raw_binaries.tar.gz
uname -m # aarch64 -> udp2raw_arm64 ; armv7l -> udp2raw_arm_asm_aes
# ВАЖНО: класть ФАЙЛОМ по пути /usr/local/bin/udp2raw (не каталогом!)
sudo install -m 755 udp2raw_arm64 /usr/local/bin/udp2raw
udp2raw -h >/dev/null && echo OK
```
# Переносим специализированный ARM-бинарник в системный путь ### Шаг 3.3. Firewall (nftables)
sudo cp udp2raw_arm_asm_aes /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
Правила уже собраны в `client/nftables.conf` (полный ruleset малинки + MSS-clamp). Бэкап и применение:
Шаг 3.3. Настройка сетевого экрана (nftables) ```bash
Учитывая строгую политику policy drop на вашей Raspberry Pi, откройте текущие правила: sudo cp /etc/nftables.conf /etc/nftables.conf.bak.$(date +%F)
sudo cp client/nftables.conf /etc/nftables.conf
sudo nft -f /etc/nftables.conf # применяется с flush (без дублей)
```
Ключевые строки, которые должны присутствовать:
```nft
Bash # table inet filter, chain forward:
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 "wlan0" oifname "wg0" accept
iifname "wg0" oifname "wlan0" ct state established,related 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 # MSS-clamp
iifname "wlan0" oifname "wg0" tcp flags syn tcp option maxseg size set rt mtu
# table ip nat, chain postrouting:
В table ip nat -> chain postrouting:
Code snippet
ip saddr 192.168.77.0/24 oifname "wg0" masquerade ip saddr 192.168.77.0/24 oifname "wg0" masquerade
```
> `nft -f` применяет файл с очисткой (flush) — это важно, чтобы не накапливались дубли правил при повторном запуске.
Примените изменения: sudo nft -f /etc/nftables.conf ### Шаг 3.4. Конфигурации
Шаг 3.4. Создание конфигурационных файлов
Создайте конфиг WireGuard: sudo nano /etc/wireguard/wg0.conf `/etc/wireguard/wg0.conf` (права `600`; перед копированием сверить шлюз `ip route show default`):
Ini, TOML
```ini
[Interface] [Interface]
Address = 10.66.66.2/24 Address = 10.66.66.2/24
PrivateKey = eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw= PrivateKey = eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=
MTU = 1200 MTU = 1200
# КРИТИЧНО (анти-петля): маршрут к серверу через реальный uplink ДО поднятия default в wg0. # КРИТИЧНО (анти-петля): маршрут к серверу через реальный uplink ДО подъёма default в wg0.
# 192.168.200.1 — шлюз usbnet; при смене канала поправить адрес здесь. # 192.168.200.1 — шлюз usbnet; при смене канала поправить здесь.
PreUp = ip route replace 95.174.102.77/32 via 192.168.200.1 dev 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 PostDown = ip route del 95.174.102.77/32 2>/dev/null || true
@@ -231,10 +217,11 @@ PublicKey = dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=
Endpoint = 127.0.0.1:51821 Endpoint = 127.0.0.1:51821
AllowedIPs = 0.0.0.0/0 AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25 PersistentKeepalive = 25
```
`/etc/systemd/system/udp2raw-client.service` (пароль в `-k` — тот же, что на сервере):
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-client.service ```ini
Ini, TOML
[Unit] [Unit]
Description=udp2raw Client (FakeTCP) Description=udp2raw Client (FakeTCP)
After=network.target After=network.target
@@ -248,39 +235,46 @@ RestartSec=5
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
```
### Шаг 3.5. Запуск (сначала транспорт, потом туннель)
Шаг 3.5. Запуск служб на клиенте ```bash
Bash
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-client sudo systemctl start udp2raw-client # или enable --now — для автозагрузки
sudo systemctl enable --now wg-quick@wg0 sudo systemctl start wg-quick@wg0
sudo wg show
```
---
4. Диагностика и проверка статуса ## 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. Проверка выхода в интернет через туннель 1. **Транспорт udp2raw:** `sudo systemctl status udp2raw-{server,client}` — в логах `now listening` / `client_ready`, без циклических перезапусков.
С устройства за малинкой (192.168.77.0/24): `curl -s https://ifconfig.me` 2. **Туннель WireGuard:** `sudo wg show` — есть `latest handshake: N seconds ago`, счётчики `transfer` растут.
Критерий успеха: возвращается публичный IP канала сервера (сети `192.168.31.1`), а не мобильного канала клиента. 3. **Отсутствие петли (клиент):** `ip route get 95.174.102.77``dev usbnet`, а не `dev wg0`. Иначе не отработал `PreUp`.
4. **Сетевой уровень:** с Pi `ping 10.66.66.1`. Идёт пинг до сервера — туннель жив.
5. **Выход через туннель:** с устройства за `wlan0` `curl -s https://ipinfo.io/ip` → должен вернуть `95.174.102.77` (адрес сети сервера).
6. **Доступность входа:** с клиента `nc -vz 95.174.102.77 25565` — порт открыт (проброс на роутере).
6. Доступность публичного входа (проброс 25565) ---
С клиента: `nc -vz 95.174.102.77 25565` — порт должен быть открыт (проброс на роутере сервера).
## 5. Известные нюансы и тюнинг
- **Автозагрузка + порядок.** Для боевого режима на обоих концах: `sudo systemctl enable udp2raw-<role> wg-quick@wg0`. Чтобы после ребута WG стартовал строго за udp2raw, добавить drop-in `sudo systemctl edit wg-quick@wg0`:
```ini
[Unit]
After=udp2raw-client.service
Wants=udp2raw-client.service
```
(на сервере — `udp2raw-server.service`).
- **«Не все сайты открываются» при рабочем туннеле** — почти всегда MTU/PMTUD:
- Многие сайты используют HTTP/3 (QUIC поверх UDP 443), который **не подчиняется MSS-clamp**. Лечится либо снижением MTU туннеля (пробовать `1200 → 1160 → 1120` на обоих концах симметрично), либо блокировкой QUIC, чтобы браузер откатывался на TCP:
```nft
# в chain forward клиента, до accept-правил wg0:
iifname "wlan0" oifname "wg0" udp dport 443 reject
```
- Проверка pMTU напрямую: с клиента `ping -M do -s 1172 10.66.66.1` (1172+28=1200). Если не проходит — MTU занижаем.
- **Дубли правил nftables.** Если `nft list ruleset` показывает удвоенные строки — файл применяли `nft -f` поверх без flush. Лечится одним `sudo nft -f /etc/nftables.conf` со свежего файла (он начинается с flush) или ребутом.

View File

@@ -1,6 +1,7 @@
# RASPBERRY PI 4 (клиент/роутер) # RASPBERRY PI 4 (клиент/роутер)
# uplink : usbnet 192.168.200.13/24, шлюз+DNS 192.168.200.1 (моб. канал, провайдер режет UDP) # uplink : usbnet 192.168.200.13/24, шлюз+DNS 192.168.200.1 (моб. канал, провайдер режет UDP)
# downstream: wlan0 192.168.77.0/24 (клиенты уходят в интернет через туннель) # downstream: wlan0 192.168.77.0/24 (клиенты уходят в интернет через туннель)
# /etc/wireguard/wg0.conf
[Interface] [Interface]
Address = 10.66.66.2/24 Address = 10.66.66.2/24

View File

@@ -1,6 +1,7 @@
# СЕРВЕР (Ubuntu, за NAT: enp2s0 = 192.168.31.163, шлюз 192.168.31.1) # СЕРВЕР (Ubuntu, за NAT: enp2s0 = 192.168.31.163, шлюз 192.168.31.1)
# Публичный вход: 95.174.102.77:25565 (TCP) --проброс на роутере--> 192.168.31.163:25565 # Публичный вход: 95.174.102.77:25565 (TCP) --проброс на роутере--> 192.168.31.163:25565
# (443 не используем — его держит nginx/Gitea; см. udp2raw-server.service) # (443 не используем — его держит nginx/Gitea; см. udp2raw-server.service)
# /etc/wireguard/wg0.conf
[Interface] [Interface]
Address = 10.66.66.1/24 Address = 10.66.66.1/24