Portfolio Обо мне Блог
1 November 2022
LINUX SERVER

В данной заметке я расскажу вам про то, как раскатать свой собственный VPN сервер на VDS. В качестве VPN будет использоваться WireGuard, потому что это самая передовая технология VPN которая даёт наибольшую производительность в условиях ограниченных ресурсов. Данная статья не ставит целью разобраться с работой с WireGuard, лишь установить максимально быстро и просто.

Вот что обещает производитель моего мобильного роутера:

openvpn_vs_wireguard

Поиск vds

Первое, что нужно сделать, это найти подходящего хостера для покупки VDS. В этом могут помочь специальные сервисы, такие как:

Когда-то давно, когда я выбирал себе хостера, я наткнулся на следующий список компаний принимающих к оплате BTC. Я предпочел использовать HostSailor.

Установка

  1. Берем самый дешёвый vps с приемлемым количеством трафика, тут важный момент, для корректной работы сервиса нужно будет работать с модулями ядра линукса это значит что подайдёт не любой тип виртуализации. OpenVZ - не подходит так как это виртуализация на уровне ядра, нам нужна - KVM, это полноценная виртуалка которая позволит нам запустить хоть шиндус на сервере.

  2. Ставим debian 11.

Все шаги между этими 2мя пунктами я пропущу, т.к. у любого хостера навалом подобной информации в справке.

Настройка сервера (Debian)

  1. Подключится через ssh под рутом (ssh root@<YOU IP>) и обновить систему.
apt update
apt dist-upgrade
apt install net-tools sudo wireguard-tools mawk grep iproute2 qrencode iptables

Если сервер с очень маленьким количеством ОЗУ, например 256 или 512 мб, то попытка обновления системы может повалить ее, так что не вводим apt upgrade, выбора все равно нет.

  1. Создать нового пользователя.

Это необходимо для того чтобы, было невозможно подключится к серверу из под рута.

useradd -m -s /bin/bash admin
passwd admin
usermod -aG sudo admin
  1. Проверить какие сервисы висят на портах.

Хостеры часто любят поставить какой-то софт при установке, например Apache. Наша задача удалить его весь, т.к. он потенциальная дыра в безопасности. В результате должен остаться только sshd.

netstat -tulpn

Для отключения лишних сервисов необходимо сделать следующее:

/etc/init.d/apache2 stop
update-rc.d apache2 disable
  1. Для увелечения безопасности настроить ssh:
nano /etc/ssh/sshd_config
  • Сменить порт:
    #Port 22  # ---> раскомментировать, сменить на любое число (1024 до 64000)
  • Ищем параметр PermitRootLogin и ставим no
  • Ищем параметр PermitEmptyPasswords и ставим no
  • Запретить доступ по ssh всем кроме user: добавить внизу
AllowUsers admin
  • Перезапускаем sshd и реконектимся.
service sshd restart

Здесь нужно быть крайне внимательным, в случае ошибки в предыдущих пунктах или утери пароля, вы не сможете больше получить доступ к северу. Для коннекта нужно сделать следующее:

ssh -p <PORT> admin@<YOU IP>

Установка WIREGUARD

Здесь не большое отступление. Мы бы, конечно, могли бы установить VPN с нуля и настроить все ручками, как например тут и тут, но сегодня наша задача получить готовое, а главное удобное для использования решение, а не преисполниться в своем познании, поэтому воспользуемся готовым скриптом, который разрулит всю рутину за нас.

  1. Скачиваем и запускаем скрипт:
wget https://raw.githubusercontent.com/burghardt/easy-wg-quick/master/easy-wg-quick
chmod +x easy-wg-quick
./easy-wg-quick user_1
sudo wg-quick up ./wghub.conf

Ввод предпоследний команды настроит конфиг для первого клиента с именем user_1. Конфиг будет доступен в виде:

  • конфиг файла - wgclient_user_1.conf.
  • qr код - wgclient_user_1.qrcode.txt, его можно вывести в терминале командой cat wgclient_user_1.qrcode.txt
  • uci - wgclient_user_1.uci.txt

После добавления нового клиента нужно обязательно перезагрузить интерфейс:

sudo wg-quick down ./wghub.conf
sudo wg-quick up ./wghub.conf

Для автоматического старта при запуске системы нужно сделать следующее:

sudo cp wghub.conf /etc/wireguard/wghub.conf
sudo systemctl enable wg-quick@wghub
sudo systemctl start wg-quick@wghub
systemctl status wg-quick@wghub

UDP: Дальнейшее было на debian 10, на Debian 11 проблема не воспроизвелась.

После чего я столкнулся с проблемой, при попытки запустится выдавалось такое сообщение:

admin@my-vpn:~$ sudo wg-quick up ./wghub.conf
[#] ip link add wghub type wireguard
RTNETLINK answers: Operation not supported
Unable to access interface: Protocol not supported
[#] ip link delete dev wghub
Cannot find device "wghub"

Также попытка подгрузить модуль wireguard, тоже не успешна:

admin@my-vpn:~$ sudo modprobe wireguard 
modprobe: FATAL: Module wireguard not found in directory /lib/modules/4.19.0-6-amd64

Решение подсмотрел тут:

sudo apt install linux-headers-$(uname -r|sed 's/[^-]*-[^-]*-//')
sudo wg-quick up ./wghub.conf

После установки хедеров, вводим команду запуска сервера и наши конфиги начинают работать.

Клиенты

  • под винду.
  • под андроид.
  • под линукс, а впрочем тут не так все просто:

Linux

Первое, что нужно сделать - это установить клиент под Linux:

sudo apt install wireguard

После чего создаем конфиги для клиентов. Как правило, у меня из несколько, поэтому я называю их в формате wg_<название страны>. Например, конфиг для нидерландов будет такой - /etc/wireguard/wg_nl.conf. Содержимое самого конфига берется с сервера, что описано выше.

sudo nano /etc/wireguard/wg_nl.conf

Для запуска или остановки клиента достаточно сделать следующее:

sudo wg-quick up wg_nl
sudo wg-quick down wg_nl

Для автоматического старта при старте системы нужно сделать:

sudo systemctl enable wg-quick@wg_nl

В случае возникновения следующей проблемы:

 /usr/bin/wg-quick: line 32: resolvconf: command not found

Тут дело в том что в systemd resolvconf это часть команды resolvectl. Для решения проблемы достаточно просто сделать ссылку:

 sudo ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf
 # ИЛИ
 sudo apt install openresolv

Также в случае появления данной ошибки:

Failed to set DNS configuration: Unit dbus-org.freedesktop.resolve1.service not found.

Нужно включить недостающий сервис:

sudo systemctl start systemd-resolved.service
sudo systemctl enable systemd-resolved.service

Для работы скрипта нужно разрешить запуск wg и wg-quick от нашего юзера. Для этого в /etc/sudoers добавим в конец следующую строку (вместо user ваш пользователь):

user ALL=(ALL:ALL) NOPASSWD: /usr/bin/wg, /usr/bin/wg-quick

Switch

Если конфиг один, то для включения и выключения VPN можно использовать простенький обнострочник:

if ip l dev wg_nl | grep -q UP; then; sudo wg-quick down wg_nl; else; sudo wg-quick up wg_nl; fi

Если конфигов больше одного, то можно использовать скрипт, который позволяет их циклически переключать:

#! /bin/bash

vpns=$(ls /etc/wireguard/)
flag=0

for vpn in $vpns
do
    vpnname="${vpn%.*}"
    if [ $flag == 1 ] || ! $(ip l | grep wg | grep -q UP)
    then
        sudo wg-quick up $vpnname
        notify-send -i online  "Wireguard" "Enable $vpnname VPN."
        exit 0
    fi
    if ip l | grep -q $vpnname
    then
        sudo wg-quick down $vpnname
        flag=1
    fi
done

notify-send -i offline  "Wireguard" "Disable VPN!"
exit 0

Для отображения уведомлений в данном скрипте необходимы пакеты dunst, libnotify-bin, papirus-icon-theme. Теперь данный скрипт можно повесть на комбинацию клавиш, например в BSPWM.

Polybar

В Polybar или любой другой бар, можно добавить виджет показывающий статус соединения. Я предлагаю создать 2 таких виджета, первый будет показывать факт соединение, второй-же будет отображать внешний IP и страну соединения.

Первый блок. Показывает щит с замком (из Nerd Fonts) когда запущен любой VPN.

[module/vpn]
type = custom/script
exec-if = ip l | grep wg | grep -q UP
interval = 3
exec = echo " "
format-prefix = "   "
format-prefix-foreground = ${colors.foreground-alt}
format-underline = ${colors.orange}

Второй же запрашивает внешний ip адрес.

[module/vpn_check]
type = custom/script
interval = 1
exec = cat /tmp/vpn_state
click-left = touch /tmp/vpn_check
format-prefix = "    "
format-prefix-foreground = ${colors.foreground-alt}
format-underline = ${colors.orange}

Однако тут все сложнее. Чтобы не есть лишний трафик и не засорять канал, опрос ip адреса проходит раз в минуту или по нажатию на виджет на панели. Однако обновить виджет просто по нажатию нельзя, поэтому мы создаем файл в /tmp, наличие которого проверяет скрипт. Если он существует, скрипт создает документ с данными, которые уже читает док раз в секунду.

#! /bin/bash

counter=0
echo ------ > /tmp/vpn_state
while [ true ]
do
    if [ -f /tmp/vpn_check ]
    then
        addr=$(curl -4 -s ifconfig.net/json)
        ip=$(echo $addr | jq -r '.ip')
        con=$(echo $addr | jq -r '.country_iso')
        echo $con $ip > /tmp/vpn_state
        rm /tmp/vpn_check
        counter=0
    else
        if [[ $counter == 60 ]]
        then
            addr=$(curl -4 -s ifconfig.net/json)
            ip=$(echo $addr | jq -r '.ip')
            con=$(echo $addr | jq -r '.country_iso')
            echo $con $ip > /tmp/vpn_state
            counter=0
        else
            counter=$((counter + 1))
        fi
    fi
    sleep 1
done

Данный скрипт необходимо пихнуть в автозагрузку, а также для его работы нужен пакет jq.


Интересные ссылки: