У Wireguard есть немало прекрасного, включая его простоту реализации, скорость и минималистичные клиенты, которые не вызывают проблем у пользователей. В начале августа некоторые интернет операторы и провайдеры начали блокировку протокола WireGuard в РФ по его рукопожатию. Лично испытывал блокировку у Мегафон и Теле2, но не заметил у Ростелеком. VPN по-прежнему работал через последнего. Очень не хотелось отказываться от Wireguard в пользу прокси-серверов в духе VLESS+TLS-Vision, в виду того, что все наши пользователи уже сильно привыкли именно к Wireguard.Поэтому вариант с кардинальной сменой клиентского софта не рассматривался. Поскольку трафик Wireguard блокируется только на зарубежные адреса было принято решение добавить еще один хоп в систему, а начальное подключение осуществлять к серверу в РФ. Пользователь → Wireguard РФ → обфускатор в РФ → обфускатор в EU → InternetВ качестве обфускатора выбран shadowsocks. Причём с AED шифрованием. Оно уже детектируется GFW (https://en.wikipedia.org/wiki/Great_Firewall), но еще не детектируется у нас. Этот выбор позволит нам всё сильно упростить. На сервере в EU ставим shadowsocks Редактируем /etc/shadowsocks-libev/config.json  Конфиг говорит, что SOCKS5 сервер будет слушать порт 8443 по TCP/UDP с заданным метод шифрования и паролем. Разрешаем коннект только с нашего российского сервера. Делаю через nftables sets Запуск systemctl enable --now shadowsocks-libev Проверим, что порт слушается ss -nltu 'sport = 8443' Переходим к серверу в РФ. Считаем, что Wireguard у нас уже поднят на сервере. На нём не останавливаемся. Поскольку shadowsocks это прокси, а нам нужно маршрутизировать весь трафик из РФ в EU, то нам нужен сетевой интерфейс на сервере, который будет перенаправлять трафик в shadowsocks. Из коробки shadowsocks может либо слушать порт без SOCKS и отправлять его дальше (ss-tunnel), либо слушать socks сразу на хосте (ss-local).  Оба варианта не подходят, т.к. ни один из них не создаёт интерфейс. Поэтому мы ставим tun2socks. https://github.com/xjasonlyu/tun2socks Он будет использовать tun-интерфейс, с которого уже отправит трафик в shadowsocks в EU. Я собрал из исходников go install github.com/xjasonlyu/tun2socks/v2@latest Но можно скачать и готовый бинарный файл. В tun-интерфейс будет маршрутизироваться весь трафик, кроме трафика на сервер в EU и трафика localhost. tun2socks умеет работать с протоколом shadowsocks, т.к. использует go-shadowsocks2-core, что очень удобно. Нам не придется ставить shadowsocks на сервер в РФ.  https://github.com/xjasonlyu/tun2socks/blob/main/proxy/shadowsocks.go#L9C2-L9C44 В /etc/sysctl.conf должен быть включен форвардингnet.ipv4.ip_forward=1На сервере в РФ нужно поменять маршрутизацию. Нужно будет добавить новый шлюз по умолчанию через tun0 Сделать исключение для IP сервера в EU Старому шлюзу по умолчанию нужно будет повысить метрику Создать дополнительную таблицу маршрутизации для IP адреса на сервере (если она уже не создана хостером), чтобы трафик на этот IP не уходил в туннель То есть в итоге у нас будет два шлюза по умолчанию. Если по какой-либо причине tun отвалится, то сервер будет доступен. Как добавить именно tun/tap (не tunnel) интерфейс в netplan, я не нашёл. Поэтому интерфейс и маршруты прописываю в хуки systemd unit. Подразумевается, что интерфейс сервера это ens3. IP адрес tun0 роли не играет. В /etc/default/tun2socks находятся реквизиты подключения в серверу в EU В пароле нужно избегать символов / и :, чтобы не нарушить парсинг URI. Добавляем таблицу для маршрутизации в конец /etc/iproute2/rt_tables systemctl enable --now tun2socks Сетевая задержка между серверами колеблется в районе 25-30ms, что не так уж и плохо. Итоговая скорость хорошая, клиенты довольны. Рассчитываем, что с этим можно жить еще минимум пару-тройку лет не беспокоясь об усилении лютости DPI провайдеров. В дальнейшем между перед shadowsocks планирую установить HaProxy для более гибкой балансировки на несколько узлов зарубежных VPN, а также для повышения отказоустойчивости.  Но пока с текущей базой пользователей этот шаг выглядит избыточным.  Linux-энтузиаст, предприниматель