Подробная инструкция, как арендовать и настроить свой выделенный сервер - для защиты своего сетевого трафика от анализа третьими лицами (прослушки) и прочих нежелательных сетевых активностей. Коротко, о чём гайд:

- Сервер Linux Debian 11
- Виртуальная частная сеть Wireguard
- Мониторинг Grafana
- Спасательный круг: backups & snapshots
- Базовая защита от взлома перебором fali2ban
- Фильтр нежелательного контента, приоритезация трафика QoS

Шаг 1: Выбрать хостинг

Воспользоваться поисковым запросом "список самых дешёвых VPS хостингов" и выбрать, какой больше нравится. Конфигурации и цены бывают разные, самые дешёвые начинаются от двух евро в месяц. Например - hip.hosting

Шаг 2: Выбрать локацию, операционную систему и оплатить аренду сервера

Локацию сервера выбираем из доступных, исходя из своих предпочтений. Обычно - чем ближе локация, тем ниже задержка. Операционную систему я советую Debian.

Шаг 3: Настройка операционной системы

Используя программу Putty и предоставленные IP адрес и пароль, нужно войти на сервер и обновиться:

sudo apt update && apt upgrade -y

sudo apt-get install iptables net-tools vim rsync parted -y

В файле системной конфигурации нужно убрать знак комментария "#" в начале строки "net.ipv4.ip_forward=1", чтобы разрешить нашему серверу выполнять роль прокси:

vim /etc/sysctl.conf

vim, vi - самый распространённый текстовый редактор linux. Режим редактирования включается кнопкой i, выход из редактирования кнопка esc. Чтобы выйти без сохранения надо ввести ":q!" (без кавычек), выход с сохранением - ":wq!"

Установим бесплатный клиент с открытым исходным кодом Wireguard:
sudo apt install wireguard -y

Переходим в папку приложения:
cd /etc/wireguard/

Генерируем и записываем ключи:
wg genkey | tee privatekey | wg pubkey | tee publickey

Приватный ключ надо записать в конфиг Wireguard; здесь Address = это адрес сервера в виртуальной сети, а ListenPort = порт, по которому будут подключаться клиенты (адрес и порт можно задать произвольно):

echo "[Interface]
PrivateKey = $(cat privatekey)
Address = 10.0.0.1/24
ListenPort = 51820" > wg0.conf

в Putty текст вставляется правой кнопкой мыши. В vim через Putty - клавиша shift+правая кнопка мыши. А для переноса больших объёмов текста в веб-консоль, у меня есть пара удобных инструментов - typewriter и infill.

Далее - надо добавить в этот файл информацию о сетевом адаптере:
INTERFACE=$(ip route | grep default | awk '{print $5}' | head -n1); sudo tee -a wg0.conf <<EOF
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o $INTERFACE -j MASQUERADE
EOF


После этого, в конфигурационный файл добавляются клиенты:
[Peer]
PublicKey = uJWPI0zpKSB7C4G9LLdy4VMX2bPXs33g7nfdo2CVanw=
AllowedIPs = 10.10.10.30/32

PublicKey - публичный ключ клиента, которому принадлежит виртуальный адрес AllowedIPs, а маска /32 говорит о том, что это одиночный адрес хоста.

В итоге, конфигурационный файл wg0.conf должен иметь вид типа такого:

[Interface]
Address = 10.10.10.1/24

ListenPort = 21212

PrivateKey = qPSUFPcGiHUQkOo2RHPGWeb3XmSjfiSWqSMuPd3SnCs=

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE

[Peer]
PublicKey = uJWPI0zpKSB7C4G9LLdy4VMX2bPXs33g7nfdo2CVanw=
AllowedIPs = 10.10.10.30/32

[Peer]
PublicKey = YXnyogyq5930eFdueaFivCqpJCRMEmawJrpP1lcGEDc=
AllowedIPs = 10.10.10.20/32


где
PrivateKey - приватный ключ сервера
Address - виртуальный адрес сервера
ListenPort - порт сервера
PublicKey - публичный ключ клиента, которому принадлежит виртуальный адрес AllowedIPs из его секции [Peer]

Публичный ключ клиента можно получить в приложении клиента (например, Wireguard для Windows), где он будет случайно сгенерирован при добавлении нового "пустого" туннеля.

Добавляем туннель в автозагрузку и перезагружаемся:
sudo systemctl enable wg-quick@wg0

sudo reboot

Готово! Минимальная настройка завершена,

теперь введя в клиент публичный ключ сервера, внутренний IP-адрес клиента и внешний IP=адрес сервера с портом - можно пользоваться сетью. Теперь установим и настроим мониторинг Grafana для отслеживания сетевой активности по клиентам:

sudo tee /etc/apt/sources.list.d/grafana.list <<'EOF' deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main EOF

sudo mkdir -p /etc/apt/keyrings/

apt-get install gpg

wget -q -O -
https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null

sudo apt install -y prometheus grafana

sudo iptables -A INPUT -i wg0 -j ACCEPT

sudo iptables -A OUTPUT -o wg0 -j ACCEPT

curl
https://sh.rustup.rs -sSf | sh

source $HOME/.cargo/env

sudo apt install cargo build-essential -y

cargo install clap --version 4.0.26

exec bash

cargo install prometheus_wireguard_exporter

vim /etc/prometheus/prometheus.yml

Заполнить файл следующим содержанием, строгое количество пробелов в началах строк!
scrape_configs:
- job_name: 'wireguard'
scrape_interval: 10s
static_configs:
- targets: ['localhost:9586']


Чтобы мониторинг запускался со стартом системы, создадим systemd-сервис:
vim /etc/systemd/system/wireguard-exporter.service

[Unit]
Description=Prometheus WireGuard Exporter
After=network-online.target

[Service]
ExecStart=/usr/bin/prometheus_wireguard_exporter --interfaces wg0
Restart=on-failure

[Install]
WantedBy=multi-user.target

sudo systemctl daemon-reload

sudo systemctl enable --now grafana-server

sudo systemctl enable --now wireguard-exporter.service

prometheus_wireguard_exporter --interfaces wg0 &>> /var/log/wireguard-exporter.log &

Проверка что всё работает:
jobs -l

Теперь можно зайти на веб-панель мониторинга, используя адрес своего сервера и порт 3000: http://your-server-ip:3000

Для первого входа используются стандартные логин и пароль admin

Мониторинг можно настроить в разделе "Dashboards". В режиме "edit" - включается сверху справа - выбираем Add - visualisation. Выбираем prometheus, адрес сервера вставляем дефолтный (http://localhost:9090) и save. Сохраняем дашборд под каким-нибудь названием и заходим в него через меню Dashboards. Удаляем все query и создаём новую, по кнопке + Add query. В поле Data source должен быть выбран prometheus. Справа - переключаемся в режим Code, если вдруг выбран Builder. Далее - в поле "Enter a PromQL query..." вставляем следующий запрос:
rate(wireguard_received_bytes_total[1m])

Нажимаем кнопку Run queries и сверху должен появиться график. Сохраняем дашборд справа сверху. Дальнейшая настройка вполне интуитивна. Чтобы переименовать графики - нужно прокрутить Panel options вниз до кнопки + Add field override, нажав на неё выбрать нужный график и переименовать его.

Для базовой защиты сервера от взлома - рекомендую утилиту fail2ban:
sudo apt install fail2ban -y

vim /etc/fail2ban/jail.local

Пример настройки файла конфигурации /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 7
bantime = 1h

sudo systemctl start fail2ban

sudo systemctl enable fail2ban

Далее - продвинутая конфигурация: переход на другую файловую систему, резервное копирование и моментальные снимки, восстановление из резервной копии, фильтрация нежелательного контента и правила для разных типов трафика.

Этап 1: Смена файловой системы и резервное копирование

Иногда случаются различные казусы, после которых возникает острое желание откатиться на некоторое время назад. В большинстве приложений - такой откат на одно последнее действие происходит комбинацией клавиш CTRL+Z, однако не всегда и не везде. В некоторых случаях - полезно иметь полную резервную копию всех данных. Лучше, когда она есть и не нужна, чем когда нужна и её нет.

Базовая файловая система Linux, EXT4 - не обладает функционалом снимков файловой системы - поэтому в первую очередь мы выполним переход на более продвинутую BTRFS

  1. Смотрим сколько есть места на сервере командой df -h. В моём примере сервер с 10ГБ диском.

  2. Свободное место делим чуть меньше чем пополам и с помощью parted создаём логический том под резервную копию

sudo apt install parted btrfs-progs -y

sudo parted /dev/sda

resizepart 1 → указываем новый размер: 4.8GB.

mkpart primary btrfs 4.8GB 100% → создаем /dev/sda2 из оставшегося места.

print → проверяем, что получилось.

q

sudo mkdir /mnt/btrfs_backup

sudo mount /dev/sda2 /mnt/btrfs_backup

Синхронизируем содержимое корневого раздела и резервного, без лишних каталогов (и удаляя всё лишнее в целевой директории):
sudo rsync -aAXv --delete --exclude={"/dev/","/proc/","/sys/","/tmp/","/run/","/mnt/","/media/*","/lost+found"} / /mnt/btrfs_backup/

sudo mkdir /mnt/btrfs_backup/{dev,proc,sys,tmp,run,mnt,media}

Подменяем разделы для загрузки с бэкапа - редактируем fstab:
sudo sed -i "| / |c UUID=$(sudo blkid -s UUID -o value /dev/sda2) / btrfs defaults,compress=zstd,noatime 0 1" /mnt/btrfs_backup/etc/fstab

И загрузчик grub:
sudo mount --bind /dev /mnt/btrfs_backup/dev

sudo mount --bind /proc /mnt/btrfs_backup/proc

sudo mount --bind /sys /mnt/btrfs_backup/sys

sudo chroot /mnt/btrfs_backup

update-grub

grub-install /dev/sda

exit

Теперь при следующей загрузке сервер запустится из резервной копии в разделе с файловой системой BTRFS.

sudo reboot

После перезагрузки, убедимся, что корень (/) находится на /dev/sda2 командой df -h, затем преобразуем /dev/sda1 в BTRFS:

sudo mkfs.btrfs -f /dev/sda1

sudo mkdir /mnt/sda1

sudo mount /dev/sda1 /mnt/sda1

mkfs преобразует файловую систему, не конвертируя данные, поэтому нам надо вернуть их обратно из резервной копии:
sudo rsync -aAXv --delete --exclude={"/dev/","/proc/","/sys/","/tmp/","/run/","/mnt/","/media/*","/lost+found"} / /mnt/sda1/

Снова правим GRUB, для загрузки в sda1:
sudo mount --bind /dev /mnt/sda1/dev

sudo mount --bind /proc /mnt/sda1/proc

sudo mount --bind /sys /mnt/sda1/sys

sudo chroot /mnt/sda1

update-grub

grub-install /dev/sda

exit

Перезагружаемся и актуализируем fstab
sudo reboot

sudo sed -i "s/^UUID=[^ ]* / btrfs/UUID=(blkid -s UUID -o value(findmnt -n -o SOURCE /)") / btrfs/" /etc/fstab

Восстановление из загрузочного меню GRUB RESCUE

Если по какой-то случайности система оказалась в нерабочем состоянии, разбираться в котором нет никакого желания - можно загрузиться в резервную копию через меню загрузчика GRUB.

Смотрим список доступных разделов:
ls

Проверяем список на наличие загрузочного сектора:
ls (hd0,gpt2)/boot/

Если вывод команды показывает файлы типа vmlinuz и initrd.img, значит, это корневой раздел. Для успешного восстановления - нужно выбрать корневой раздел с резервной копией.

Обычно, нумерация разделов такая же, как в операционке, а hd - это номер физического диска (нумерация с нуля)

Загрузка из этого раздела:
set root=(hd0,gpt2)

set prefix=(hd0,gpt2)/boot/grub

insmod normal

normal

После загрузки в резервный раздел - нужно вернуться к действию 5) и копировать резервную копию на основной раздел, а затем перезагрузиться в него (и fstab обновить).

Работа с моментальными снимками

Создадим первый:
sudo mkdir /snapshots

sudo btrfs subvolume snapshot / /snapshots/root_$(date +%Y-%m-%d_%H-%M)

Просмотр списка "быстрых сохранений":
sudo btrfs subvolume list /

Откат системы к моментальному снимку

sudo btrfs subvolume set-default $(sudo btrfs subvolume list / | sort -n -k2 | tail -1 | awk '{print $2}') / && sudo reboot

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

Этап 2: Настройка конфигурации клиента и блокировка рекламы на уровне DNS

На стороне устройств, включённых в виртуальную частную сеть, (на стороне клиентов) выполняется следующая настройка конфигурации Wireguard:

  • Секция [Interface] относится к виртуальному интерфейсу клиента; ему нужно присвоить (или сгенерировать) приватный ключ подходящего формата (wireguard), публичный отпечаток которого вводится в конфигурацию на стороне сервера. Адрес - во внутренней сети, то бишь в VPN. А DNS - указываем от AdGuard, с блокировкой рекламы и вредоносных сайтов, и запасной от Google, как самый надёжный - к нему сервер будет обращаться только в случае недоступности первого (чего обычно тоже никогда не случается).

  • В секции [Peer] указывается публичный ключ нашего сервера, Endpoint - это IP-адрес сервера и его listenport; PersistentKeepalive - это время в секундах когда будет повторно выполнено рукопожатие для поддержания активного статуса подключения, а AllowedIPs - это список сетевых адресов, трафик до которых будет перенаправлен через VPN. Иными словами - если какой-то адрес не входит в диапазоны указанные в этом списке - то трафик до этого адреса не будет идти через VPN. Это может быть полезно, например, для внутренних ресурсов, доступ к которым может быть ограничен с удалённых серверов, или для минимизации задержки в онлайн-играх.

Чтобы "ограничить влияние" VPN на какие-либо сервисы, делаются три действия:

  1. определение сетевого адреса, используемого сервисом - проще всего это сделать с помощью поиска в Сети, поскольку разработчики обычно публикуют информацию о используемых адресах, либо с помощью анализаторов типа WireShark

  2. с помощью специального калькулятора (https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/) нужно составить корректную строку для AllowedIPs

  3. ввести эту строку в секцию AllowedIPs в конфиге клиента (пира)

Пример конфигурации для клиента, с блокировкой рекламы и исключением сети 11.7.0.0/16:

[Interface]
PrivateKey = e3rmxdsBWO5pcHR4wRaQSiOJ9lrz7w8dALNIKeMUc0M=
Address = 10.10.10.99/24
DNS = 94.140.14.14, 8.8.8.8

[Peer]
PublicKey = Hp3gn3oQOHO2QBWSL0jlYVhrCSNh/HW3a/e+O1jR2Ts=
AllowedIPs = 0.0.0.0/5, 8.0.0.0/7, 10.0.0.0/8, 11.0.0.0/14, 11.4.0.0/15, 11.6.0.0/16, 11.8.0.0/13, 11.16.0.0/12, 11.32.0.0/11, 11.64.0.0/10, 11.128.0.0/9, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/1
Endpoint = 2.21.189.131:33444
PersistentKeepalive = 60

Этап 3: фильтр HTTP рекламы Privoxy

Установим Privoxy и скачаем расширенные листы блокировок:
sudo apt update && sudo apt install privoxy -y

sudo wget -O /etc/privoxy/easylist https://easylist.to/easylist/easylist.txt && echo "filterfile easylist" | sudo tee -a /etc/privoxy/config && sudo systemctl restart privoxy && sudo systemctl enable privoxy

Для фильтрации всей остальной рекламы - рекомендую приложение uBlock в браузере клиента

Этап 4: правила для разных типов трафика (QoS)

Установим политики по умолчанию
sudo iptables -P INPUT ACCEPT

sudo iptables -P OUTPUT ACCEPT

sudo iptables -P FORWARD DROP

Разрешить форвард только для клиентов Wireguard:
sudo iptables -A FORWARD -i wg0 -o ens3 -j ACCEPT

sudo iptables -A FORWARD -i ens3 -o wg0 \ -m state --state RELATED,ESTABLISHED -j ACCEPT

Включить NAT для выхода в Интернет:
sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE

Смарт-фильтр CAKE настраиваем на пропускную способность сети сервера (с указанием названия адаптера):
sudo tc qdisc replace dev ens3 root cake bandwidth 100mbit nat

Правила для игрового трафика:
sudo iptables -t mangle -A PREROUTING -i wg0 -p udp -m multiport --dports 27000:27100,3478:3479,4379:4380,3724,4000,5060:5062,6112:6119,6250,12000:64000 -j DSCP --set-dscp-class EF

sudo iptables -t mangle -A PREROUTING -i wg0 -p tcp -m multiport --dports 27015:27050,1119:1120,3074,3724,4000,6112:6120 -j DSCP --set-dscp-class EF

Голосовые и видеозвонки:
sudo iptables -t mangle -A PREROUTING -i wg0 -p udp --dport 3478:3481 -j DSCP --set-dscp-class EF

Видео-стриминг:
sudo iptables -t mangle -A PREROUTING -i wg0 -p tcp --dport 443 -m string --string "youtube" --algo bm -j DSCP --set-dscp-class AF21

Веб-трафик:
sudo iptables -t mangle -A PREROUTING -i wg0 -p tcp --dport 80,443 -j DSCP --set-dscp-class BE

Низкий приоритет для всего остального (например, торренты):
sudo iptables -t mangle -A PREROUTING -i wg0 -j DSCP --set-dscp-class CS1


команды iptables и tc не сохраняются при перезагрузке по умолчанию; чтобы конфигурация не потерялась при выключении сервера, используем дополнительные инструменты:
sudo apt-get install iptables-persistent -y

sudo iptables-save > /etc/iptables/rules.v4

vim /usr/local/bin/apply_qos.sh

sudo chmod +x /usr/local/bin/apply_qos.sh

vim /etc/systemd/system/qos.service

[Unit]
Description=Apply QoS rules
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/apply_qos.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

sudo systemctl enable qos.service

После успешной настройки - сделаем снапшот системы и выполним перезагрузку сервера, чтобы убедиться, что система устойчива к перезапускам:
sudo btrfs subvolume snapshot / /snapshots/root_$(date +%Y-%m-%d_%H-%M) && sudo reboot

Комментарии (14)


  1. ValdikSS
    25.06.2025 12:08

    В файле системной конфигурации нужно убрать знак комментария "#" вначале строки "net.ipv4.ip_forward=1", чтобы разрешить нашему серверу выполнять роль прокси

    И все начинают маршрутизировать трафик через ваш сервер, без ограничений. Запрещающих правил у вас не вижу.


    1. Aremys Автор
      25.06.2025 12:08

      Отличное замечание! сейчас поправлю гайд


  1. Mirzapch
    25.06.2025 12:08

    Сервер Linux Debian 11

    Актуальная версия дебиана - 12.11.0 на данный момент.


  1. CPUBug
    25.06.2025 12:08

    Зачем использовать Debian 11? Debian 12 выпущен около 2-х лет назад.


    1. Aremys Автор
      25.06.2025 12:08

      Дома у себя - согласен. Но на хостингах обычно идут не самые последние релизы ОС.


      1. CPUBug
        25.06.2025 12:08

        Это легко решается редактированием sources.list с последующим apt update && apt dist-upgrade


        1. Aremys Автор
          25.06.2025 12:08

          зачем? чем 11 дебиан плох? какого функционала нам не хватает? зачем нам тратить своё время на лишние действия?


          1. CPUBug
            25.06.2025 12:08

            Дело не в нехватке функционала. Использование актуальной версии дистрибутива сделало бы инструкцию актуальной на более долгое время. Насколько я помню до конца поддержки Debian 11 осталось около года.


  1. ValdikSS
    25.06.2025 12:08

    А при чём здесь VPS?


  1. alexs963
    25.06.2025 12:08

    1. Давно уже iptables заменили на nftables

    2. Для конвертации ext4 в btrfs есть btrfs-convert

    3. Почему не использовать юнит systemd для запуска мониторинга? после перезагрузки предлагаете вручную снова запускать?

    4. Рекомендую использовать снимки в режиме только для чтения: btrfs subvolume snapshot -r


    1. Aremys Автор
      25.06.2025 12:08

      про мониторинг - вот это хорошо подмечено, пропустил его автозапуск, добавляю в гайд


  1. lea
    25.06.2025 12:08

    По настройке fail2ban пара комментариев:

    1. Желательно заигнорить айпишник станции, с которой ходим на vps.

    2. Производительность может очень сильно отличаться в зависимости от способа бана. У меня fail2ban стартовал минут 5 при 1500 забаненных айпишниках с близкой к вашей конфигурацией и банами по-дефолту через rich rules, переключил на ipset - время запуска сократилось до пары секунд.

    sudo dnf install fail2ban
    sudo vi /etc/fail2ban/jail.local
        # приводим к виду:
        [DEFAULT]
        bantime = 1mo
        findtime = 3600
        maxretry = 2
        ignoreip = 127.0.0.0/8 ::1 $MY_IP
        [sshd]
        enabled = true
        filter = sshd
        mode = aggressive
        port = 22
    
    # переключаем на баны через ipset
    sudo vi /etc/fail2ban/jail.d/00-firewalld.conf
        # конфиг, который был у меня по-умолчанию:
        [DEFAULT]
        banaction = firewallcmd-rich-rules
        banaction_allports = firewallcmd-rich-rules
    
        # приводим к виду:
        [DEFAULT]
        banaction = firewallcmd-ipset
        banaction_allports = firewallcmd-ipset
    
        # названия действий для iptables/nftables можно подсмотреть где-то тут:
        # sudo ls -la /etc/fail2ban/action.d/
    
    # чтобы не слетало правило фильтрации по ipset при
    # выполнении sudo firewall-cmd --reload
    sudo vi /etc/firewalld/firewalld.conf
        # находим строку
        FlushAllOnReload=yes
        # заменяем на
        FlushAllOnReload=no
    
    sudo systemctl restart firewalld
    sudo systemctl enable --now fail2ban
    
    sudo iptables -L
        # тут увидим новое правило:
        Chain INPUT (policy ACCEPT)
        target     prot opt source               destination
        REJECT     tcp  --  anywhere             anywhere             multiport dports ssh match-set f2b-sshd src reject-with icmp-port-unreachable
    
    sudo fail2ban-client status sshd
    sudo ipset list f2b-sshd
        # два способа посмотреть список банов

    (это на centos9 stream, но идея должна быть понятна)

    + добавил бы про отключение логина по ssh для пользователя root (как минимум)


    1. Aremys Автор
      25.06.2025 12:08

      Интересный кейс! Спасибо, изучу


  1. Vadimio
    25.06.2025 12:08

    Гайд - это, я так понимаю, от английского guide (руководство)
    т.е. статья называется:
    "руководство на виртуальный частный сервер (VPS) с нуля"
    Это вообще по-русски написано?

    Давайте тогда, как сегодня модно:
    "Обзор на VPS с нуля"