Запуск сервера vpn и прокси на VPS

Итак, Россию отменили в мире. Оценочные суждения оставлю за рамками этой статейки, но одно стало понятно: vpn и проксирование трафика через VPS, находящиеся за рубежом, - это необходимость. Поэтому распишу те решения, которые я самостоятельно развернул и проверил их работоспособность.

Во-первых, немного категоризации. Выделил для себя три типа проксирования трафика:

  1. Уровень приложений. Здесь достаточно обычного sock5-proxy-сервера, который можно прописать в конфигах многих приложений. Например, подобная настройка доступна у Telegram или десктопного Spotify. Неожиданно, но даже в мобильном браузере FireFox можно установить расширение с поддержкой прокси. Из минусов: поддерживается не везде, не сильно безопасно.
  2. Уровень системы. Здесь уже хотелось бы выбрать решение, которое можно использовать на всех системах, заворачивая весь трафик на устройстве через vpn. Вариантов, в целом, не мало: есть достаточно распространённый openvpn, есть классические l2tp соединения, а есть wireguard - тёмная лошадка, о которой как-то не очень много пишут в статьях про “как настроить vpn”.
  3. Уровень роутера. Опционален для большинства, так как не все роутеры поддерживают запуск vpn-клиентов непосредственно на железе. Мне немного повезло выбрать роутер с такой поддержкой. Если есть старенький роутер, который не жалко, то можно попробовать прошить его, поставив на борт dd-wrt. Очень крутая штука, которая может вдохнуть вторую жизнь в устаревшее устройство. По поводу решений: всё тоже самое, что и в пункте 2, главное чтобы роутер поддерживал соединение к выбранному серверу.

Во-вторых, хочется всё максимально простое и портативное. А значит нужно использовать docker-образы. Если у решения слишком сложная настройка или нет хотя бы базового docker-образа, то решение пропускаю.

Итак, пойду по порядку.

Proxy

Решений в данной категории не мало. Я же остановился на проверенном решении - dante. Но здесь проблема, что официального образа на dockerhub нет. Но есть сборки от сторонних людей. Не долго гугля, выбрал это решение с образами на hub.docker.com.

Настройка простая: создаём файл docker-compose.yml и записываем туда основные параметры:

docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3.8"
services:
dante:
image: vimagick/dante:latest
environment:
CFGFILE: /etc/dante/sockd.conf
PIDFILE: /run/sockd.pid
WORKERS: 4
ports:
- "1080:1080"
volumes:
- ./data:/etc/dante
tmpfs:
- /run
restart: unless-stopped

Рядом создаём директорию data и кладём в неё файл sockd.conf со следующим содержимым

data/sockd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
debug: 0
logoutput: stderr
internal: 0.0.0.0 port = 1080
external: eth0
socksmethod: username none
clientmethod: none
user.privileged: root
user.unprivileged: nobody

client pass {
from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
log: error
}

socks pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
#socksmethod: username
log: error
}

Далее docker-compose up -d и profit. Подключение выглядит как <ip>:1080. Для безопасности можно сделать доступ по логину/паролю. Для этого нужно внутри контейнера добавить пользователя:

1
2
3
docker-compose exec dante bash
echo username:password | chpasswd
useradd username

Правда, эти изменения сохраняться до первого перезапуска контейнера. Чтобы их заперсистить, лучше всего создать свой Dockerfile с пробросом логина и пароля через аргументы.

VPN

Далее я взял два решения. Wireguard для повседневного использования и OpenVPN для подключения на уровне роутера

Wireguard

Достаточно легковесное решение, но при этом достаточно безопасное и быстрое, что не маловажно при повседневном использовании. Основной минус - отсутствие нативной поддержки где бы то ни было. Но на всех актуальных платформах (windows/android/linux/ios) есть реализации клиента. При этом, всё это добро open-source, но не всё лежит на github.

Официальных сборок под docker нет, но есть образы сервера с достаточно подробной документацией как это всё запустить и настроить.

Я не особо вдавался в настройку и запустил всё с дефолтными параметрами. Для этого заводим такой docker-compose.yml:

docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: "3.8"
services:
wireguard:
image: linuxserver/wireguard:1.0.20210914
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
- SERVERPORT=51820
- PEERS=4
- PEERDNS=auto
- ALLOWEDIPS=0.0.0.0/0
volumes:
- ./config:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped

Из всего этого можно поменять переменную PEERS, которая указывает количество конфигураций для клиентов, которые будут сгенерированы на старте.

Далее запускаем сервер docker-compose up -d. После того, как всё будет запущено, то по пути ./config/peerX будет находится файл peerX.conf, который нужно будет скормить программе-клиенту. Ещё вариант получить конфигурацию - это вывести логи контейнера docker-compose logs wireguard после первого запуска контейнера. Прямо в логах будут отрендерены qr-коды которые можно считать на мобильных устройствах, что убирает необходимость пересылки файла конфигурации на устройство. Данные qr-коды так же лежат в конфигурации в файле peerX.png.

OpenVPN

Openvpn очень похож на wireguard, вот только у последнего заявлена более высокая производительность. Но при этом openvpn поддерживается б__о__льшим количеством устройств.

В удобстве настройки openvpn так же проигрывает wireguard. Особенно в docker. Как и в предыдущем случае, официальных образов нет, но есть достаточно популярное решение, которое требует предварительной конфигурации перед стартом. Для удобства даже сделали обёртку над командами для пре-конфигурации. Именно эту обёртку я и использовал.

Берём docker-compose.yml

docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
openvpn:
cap_add:
- NET_ADMIN
image: kylemanna/openvpn
container_name: openvpn
ports:
- "1194:1194/udp"
restart: always
volumes:
- ./openvpn-data/conf:/etc/openvpn

И последовательно выполняем следующие команды:

1
2
3
4
5
6
7
docker-compose run --rm openvpn ovpn_genconfig -u udp://<ip>
docker-compose run --rm openvpn touch /etc/openvpn/vars
docker-compose run --rm openvpn ovpn_initpki
# здесь произойдёт генерация сертификата и будет задан вопрос на установку контрольной фразы
# можно задать её, но тогда на следующих шагах потребуется ввести её
docker-compose run --rm openvpn easyrsa build-client-full <username> nopass
docker-compose run --rm openvpn ovpn_getclient <username> > client_configs/<username>.ovpn

Ну и последний шаг docker-compose up -d. Файл client_configs/<username>.ovpn нужно передать на устройство и добавить в клиент.

Небольшая ремарка. Внутри контейнера сервер имеет версию 2.4.x. Соответственно и конфигурация была сгенерирована для клиентов аналогичной версии. Поэтому нужно убедиться, что клиент именно такой версии. В противном случае можно получить ошибки подключения к сайтам, хотя соединение успешно установлено. При этом на сервере будут ошибки Bad compression stub decompression header. В данном случае файл .ovpn нужно отредактировать руками, добавив в конец первого блока (до определения remote) новую строку comp-lzo no.

Afterword

В целом, в 2022 настройка self-hosted решений для vpn требуют минимум знаний, всё предельно просто. Пока все три решения живут на одной виртуалке с 1CPU и 2GB RAM и этого хватает. При 100Mb основного соединения все решения выдают 60-80Mb, что очень неплохо, на мой взгляд.