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
Данный проект содержит конфигурации для развертывания отказоустойчивого 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 напрямую:**
* Внешний интерфейс: `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`
**Сервер (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 не участвуют
- 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` |
|---|---|---|---|
| 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'` |
| 3 | Порт `25565/tcp` на хосте свободен; `443` оставить за nginx | Сервер | `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`) |
| 6 | Установлен пакет `iptables` (udp2raw добавляет правило `-a` только через него) | Клиент (чистый nft) | `iptables -V` |
| 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` только через него) | Клиент | `iptables -V` |
| 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
* **Сервер (`95.174.102.77`):**
* Public Key: `dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=`
* Private Key: `KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=`
* **Клиент (Raspberry Pi 4):**
* Public Key: `WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=`
* Private Key: `eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=`
- **Сервер:** pub `dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=` / priv `KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=`
- **Клиент:** pub `WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=` / priv `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`
* **Версия:** 20230206.0
- Архив: `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-бинарник).
Из архива нужны только два файла:
1. `udp2raw_amd64` — на **сервер** (x86_64).
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
# 1) Убедитесь, что на роутере 95.174.102.77 проброшен TCP 25565 -> 192.168.31.163:25565
# 2) Включаем и ЗАКРЕПЛЯЕМ форвардинг пакетов (wg-quick сам его НЕ включает):
# 1) Проброс на роутере: 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 слушает 192.168.31.163:25565).
# Порт 443 ДОЛЖЕН оставаться за nginx (Gitea) — udp2raw его не трогает:
# 3) Порт 25565 на хосте должен быть свободен (443 остаётся за nginx):
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
```bash
sudo apt update && sudo apt install wireguard -y
```
### Шаг 2.2. Установка бинарника udp2raw
Шаг 2.2. Скачивание и сборка udp2raw
Bash
```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)
wget https://github.com/wangyu-/udp2raw/releases/download/20230206.0/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 бинарник в системный путь и даем права
sudo cp udp2raw_amd64 /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
### Шаг 2.3. Конфигурации
`/etc/wireguard/wg0.conf` (права `600`):
Шаг 2.3. Создание конфигурационных файлов
Создайте конфиг WireGuard: sudo nano /etc/whiteguard/wg0.conf (или /etc/wireguard/wg0.conf)
Ini, TOML
```ini
[Interface]
Address = 10.66.66.1/24
ListenPort = 51820
@@ -125,10 +118,11 @@ PostDown = nft delete table ip wgfwd
[Peer]
PublicKey = WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=
AllowedIPs = 10.66.66.2/32
```
`/etc/systemd/system/udp2raw-server.service` (не забыть заменить пароль в `-k`):
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-server.service
Ini, TOML
```ini
[Unit]
Description=udp2raw Server (FakeTCP)
After=network.target
@@ -136,93 +130,85 @@ After=network.target
[Service]
Type=simple
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
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
### Шаг 2.4. Запуск (сначала транспорт, потом туннель)
Шаг 2.4. Запуск служб на сервере
Bash
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-server
sudo systemctl enable --now wg-quick@wg0
sudo systemctl start udp2raw-server # или enable --now — для автозагрузки
sudo systemctl start wg-quick@wg0
sudo wg show
sudo nft list table ip wgfwd
```
---
3. Пошаговое развертывание на КЛИЕНТЕ (Raspberry Pi 4)
Выполняется в терминале малинки (user@raspberrypi):
Шаг 3.1. Установка WireGuard и iptables
## 3. Развёртывание на КЛИЕНТЕ (Raspberry Pi 4)
### Шаг 3.1. Установка WireGuard и iptables
Bash
```bash
# iptables обязателен: на чистой nft-системе udp2raw не сможет добавить правило -a
sudo apt update && sudo apt install wireguard iptables -y
iptables -V # должно печатать версию (nf_tables)
```
### Шаг 3.2. Установка бинарника udp2raw
Шаг 3.2. Доставка бинарника udp2raw
# Внимание: положить бинарник ФАЙЛОМ по пути /usr/local/bin/udp2raw (не каталогом!).
# Архитектура: aarch64 -> udp2raw_arm64, armv7l -> udp2raw_arm_asm_aes (см. `uname -m`).
Если малинка имеет доступ к интернету, скачайте архив прямо на неё:
Bash
```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)
wget https://github.com/wangyu-/udp2raw/releases/download/20230206.0/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-бинарник в системный путь
sudo cp udp2raw_arm_asm_aes /usr/local/bin/udp2raw
sudo chmod +x /usr/local/bin/udp2raw
### Шаг 3.3. Firewall (nftables)
Правила уже собраны в `client/nftables.conf` (полный ruleset малинки + MSS-clamp). Бэкап и применение:
Шаг 3.3. Настройка сетевого экрана (nftables)
Учитывая строгую политику policy drop на вашей Raspberry Pi, откройте текущие правила:
```bash
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 (без дублей)
```
Ключевые строки, которые должны присутствовать:
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
```nft
# table inet filter, chain forward:
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
iifname "wlan0" oifname "wg0" tcp flags syn tcp option maxseg size set rt mtu # MSS-clamp
В table ip nat -> chain postrouting:
Code snippet
# table ip nat, chain postrouting:
ip saddr 192.168.77.0/24 oifname "wg0" masquerade
```
> `nft -f` применяет файл с очисткой (flush) — это важно, чтобы не накапливались дубли правил при повторном запуске.
Примените изменения: sudo nft -f /etc/nftables.conf
Шаг 3.4. Создание конфигурационных файлов
Создайте конфиг WireGuard: sudo nano /etc/wireguard/wg0.conf
Ini, TOML
### Шаг 3.4. Конфигурации
`/etc/wireguard/wg0.conf` (права `600`; перед копированием сверить шлюз `ip route show default`):
```ini
[Interface]
Address = 10.66.66.2/24
PrivateKey = eKiGDY62/9pgFrwzoNIb7URRLPgEHC1W7zHwIIDYQVw=
MTU = 1200
# КРИТИЧНО (анти-петля): маршрут к серверу через реальный uplink ДО поднятия default в wg0.
# 192.168.200.1 — шлюз usbnet; при смене канала поправить адрес здесь.
# КРИТИЧНО (анти-петля): маршрут к серверу через реальный 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
@@ -231,10 +217,11 @@ PublicKey = dVIwnwxkjan/K278vzhOjp5A79N98j0O1zsYqT24qzs=
Endpoint = 127.0.0.1:51821
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
```
`/etc/systemd/system/udp2raw-client.service` (пароль в `-k` — тот же, что на сервере):
Создайте службу демона udp2raw: sudo nano /etc/systemd/system/udp2raw-client.service
Ini, TOML
```ini
[Unit]
Description=udp2raw Client (FakeTCP)
After=network.target
@@ -248,39 +235,46 @@ RestartSec=5
[Install]
WantedBy=multi-user.target
```
### Шаг 3.5. Запуск (сначала транспорт, потом туннель)
Шаг 3.5. Запуск служб на клиенте
Bash
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now udp2raw-client
sudo systemctl enable --now wg-quick@wg0
sudo systemctl start udp2raw-client # или enable --now — для автозагрузки
sudo systemctl start wg-quick@wg0
sudo wg show
```
---
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. Диагностика
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`), а не мобильного канала клиента.
1. **Транспорт udp2raw:** `sudo systemctl status udp2raw-{server,client}` — в логах `now listening` / `client_ready`, без циклических перезапусков.
2. **Туннель WireGuard:** `sudo wg show` — есть `latest handshake: N seconds ago`, счётчики `transfer` растут.
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 (клиент/роутер)
# uplink : usbnet 192.168.200.13/24, шлюз+DNS 192.168.200.1 (моб. канал, провайдер режет UDP)
# downstream: wlan0 192.168.77.0/24 (клиенты уходят в интернет через туннель)
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.66.66.2/24

View File

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