Проверено на живом стенде: 0% потерь на 10.66.66.1 и 8.8.8.8, выход через сервер (curl -> 95.174.102.77). Транспорт (устранение разрывов faketcp): - anti-RST вписан в конфиги вместо хрупкого -a+flush: клиент — первой строкой chain input (ip saddr 95.174.102.77 tcp sport 25565 drop), сервер — в таблице wgfwd (ip daddr 192.168.31.163 tcp dport 25565 drop, переживает ufw reload). Причина: RST от ядра убивал CGNAT-маппинг оператора -> direction timeout и смена порта. - --fix-gro на обоих концах: чинит дроп GRO «супер-пакетов» (huge packet > max_data_len). Клиент: - nftables.conf: flush ruleset (убирает дубли), reject QUIC/UDP 443 (откат браузера на TCP). - udp2raw-client.service: After=nftables.service (anti-RST применяется до старта udp2raw). Автозагрузка/порядок (обе службы udp2raw): - After=network-online.target, Before=wg-quick@wg0.service. README: раздел 5 «Известные нюансы» (anti-RST vs flush, CGNAT/RST, GRO), сниппеты и таблицы приведены в соответствие.
38 lines
2.7 KiB
Plaintext
38 lines
2.7 KiB
Plaintext
# СЕРВЕР (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
|
||
ListenPort = 51820
|
||
# Приватный ключ Сервера (из файла server_private.key)
|
||
PrivateKey = KMcPBI6LAY/NC1zFNYopsvNXqQ8w8ssluDj4yOh3skk=
|
||
# Симметрично клиенту: транспорт идёт внутри faketcp, держим запас на оверхед
|
||
MTU = 1200
|
||
|
||
# Всё хозяйство WG держим в отдельной nft-таблице wgfwd, чтобы:
|
||
# - не конфликтовать с правилами Docker/UFW в главных таблицах;
|
||
# - на PostDown снести одной командой (идемпотентно).
|
||
# NAT: маскарадим ТОЛЬКО подсеть туннеля (не трогаем docker и трафик хоста).
|
||
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
|
||
# MSS-clamp для пакетов, входящих В туннель (SYN-ACK от внешних серверов),
|
||
# чтобы large-TCP не «залипал» из-за MTU 1200 и заблокированного PMTUD.
|
||
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
|
||
# udp2raw faketcp anti-RST (дубль к флагу -a): прячем входящий транспорт от TCP-стека,
|
||
# иначе ядро шлёт RST на faketcp -> туннель рвётся. Матч по СВОЕМУ IP+порту (стабильно,
|
||
# не зависит от динамического мобильного IP клиента). Приоритет -300 = раньше ufw/docker.
|
||
# udp2raw читает через AF_PACKET (до netfilter), так что drop ему не мешает.
|
||
# В своей таблице wgfwd — переживает ufw reload (в отличие от правила -a в table ip filter).
|
||
PostUp = nft add chain ip wgfwd prerst { type filter hook input priority -300 \; policy accept \; }
|
||
PostUp = nft add rule ip wgfwd prerst ip daddr 192.168.31.163 tcp dport 25565 drop
|
||
PostDown = nft delete table ip wgfwd
|
||
|
||
[Peer]
|
||
# Публичный ключ Raspberry Pi (из файла client_public.key)
|
||
PublicKey = WWFhoYfIgIhGOsvdJ/F9eWx7hPksrV6riiqo5lFPExI=
|
||
AllowedIPs = 10.66.66.2/32
|