Мир обожает что-нибудь блокировать. Твоя задача - чтобы люди могли работать. Погнали.
Если тебе нужен VPN с человеческим лицом, где видно клиентов, можно выдать конфиг по QR и при этом не париться с ключами вручную, то связка AmneziaWG и amnezia-wg-easy твой бро.
AmneziaWG - это форк WireGuard(какой же кайф давать ссылки на себя же) с обфускацией трафика (удобно там, где обычный WG режут по форме). В статье - пошаговая установка на Debian 13 (выбрал по ресурсам и доступности)
Шаг 0: что должно быть под рукой
VPS на Debian 12/13 (достаточно 1 GB RAM, 1 CPU, это же Дебиан ♥️).
Домен, направленный на IP сервера (или готовность заходить по IP).
Доступ по SSH под root (или sudo).
Дальше все команды от root. Интерфейс у меня был ens3, IP - свой; у тебя могут быть другие имена интерфейсов подставляй свои.
Шаг 1: подготовка системы и установка Docker
Docker нам нужен, потому что amnezia-wg-easy это образ с панелью и логикой управления WireGuard/AmneziaWG в одном флаконе. Крутить это голыми руками без контейнера примерно так же увлекательно как вручную собирать жигули в гараже.
1.1. Обновление пакетов
aptupdate && aptupgrade-y
Стандартная гигиена: актуальные патчи и пакеты. На триальном VPS иногда висит старый kernel после upgrade сделай перезагрузку.
Добавляем официальный репозиторий Docker под твою кодовую базу Debian (bookworm, trixie и т.д.). Так мы получаем нормальные версии docker-ce, а не из старых репозиториев дистрибутива.
Если hello-world отработал и в логе видно Hello from Docker! - движок поднят.
Шаг 2: включение IP forwarding
VPN работает так: пакеты приходят на сервер от клиента, сервер должен отправить их дальше в интернет от своего имени и вернуть ответ обратно в туннель. Для этого ядро должно разрешать пересылку пакетов между интерфейсами, то есть IP forwarding. Без него клиент поднимется, но в интернет не выйдет.
Если у тебя уже есть свой фаервол (ufw, nftables и т.д.), открой эти порты в нём. У части хостингов есть ещё внешний фаервол в панели, туда тоже стоит добавить 51820/udp и 443/tcp. Иначе будешь полчаса искать причину, почему с сервера curl отвечает, а с ноутбука хуй нет.
Шаг 4: модуль ядра AmneziaWG
AmneziaWG не просто WireGuard: у него свой модуль ядра с обфускацией. Образ amnezia-wg-easy из коробки ожидает, что на хосте этот модуль уже есть, а сам контейнер мы запустим с --network host, чтобы он пользовался интерфейсом wg0 на хосте. Поэтому сначала ставим модуль и утилиты на сам сервер.
да, это Ubuntu PPA, и это нормально, официального Debian-пакета пока нет
4.2. Установка пакетов AmneziaWG
aptinstall-yamneziawgamneziawg-tools
Подтянутся amneziawg-dkms (модуль ядра), amneziawg-tools (утилиты). DKMS соберёт модуль под твоё текущее ядро. После установки модуль уже загружен. Проверка:
lsmod|grepamneziawg
Должна быть строка с amneziawg.
Шаг 5: запуск amnezia-wg-easy (панель на 443)
Используем образ eyrafir/amnezia-wg-easy: в нём и панель, и AmneziaWG. Запуск с --network host нужен, чтобы контейнер создавал интерфейс wg0 на хосте и использовал наш только что установленный модуль ядра. Панель поднимаем на порту 443, чтобы не плодить лишние порты и не упираться в фаервол хостера.
5.1. Каталог для данных и пароль
mkdir-p/root/.amnezia-wg-easy# Пароль для входа в веб-панель - задай свой, сложныйAMNEZIA_PASSWORD="$(openssl rand -base6424)"echo"$AMNEZIA_PASSWORD">/root/.amnezia-wg-easy-password.txtchmod600/root/.amnezia-wg-easy-password.txtecho"Пароль панели сохранён в /root/.amnezia-wg-easy-password.txt"
Замени ТВОЙ_ДОМЕН_ИЛИ_IP на домен (например na.butilky.ru) или IP сервера. В конфигах клиентов будет указан именно он.
Проверка:
dockerpsss-tlnp|grep443ss-ulnp|grep51820
Должен быть контейнер amnezia-wg-easy в статусе Up, на 443, что-то вроде node, на 51820/udp процесс из контейнера.
5.3. NAT для VPN-подсети
Трафик клиентов идёт в подсеть 10.8.0.0/24. Чтобы он уходил в интернет, на хосте нужен NAT (MASQUERADE) в сторону твоего внешнего интерфейса. У меня это ens3; у тебя может быть eth0 или другое имя. Узнать так:
Без этого шага клиенты подключаются, но интернет пропадает, т.к. пакеты до сервера доходят, а дальше не уходят. Со стороны выглядит так, будто VPN сломал сеть. На самом деле сеть просто не знает, куда отправить ответы. Мы её просветим.
Шаг 6: nftables
На многих современных Debian по умолчанию фаерволом управляет nftables (через iptables-nft). Цепочка FORWARD в nft имеет политику drop, а правила для интерфейса wg0 контейнер добавляет в iptables-legacy. В итоге пакеты из туннеля приходят на хост, ядро смотрит в nft, а там для wg0 нет разрешения и всё режется. Клиент видит, что сеть пропала, потому что весь трафик ушёл в VPN, а форвард на сервере его дропает.
После следующей перезагрузки правила подставятся автоматически. На клиенте после этого включение VPN не должно «убивать» интернет.
Основную работу ты сделал(а😘)
Пример конфига сервера (wg0.conf)
Файл лежит в /root/.amnezia-wg-easy/wg0.conf. Его правит сама панель; ниже пример структуры (ключи и прешейр - твои, не копируй!).
# Note: Do not edit this file directly.# Your changes will be overwritten![Interface]PrivateKey=<серверныйприватныйключ>Address=10.8.0.1/24ListenPort=51820PostUp=iptables-tnat-APOSTROUTING-s10.8.0.0/24-oeth0-jMASQUERADE; ...PostDown=iptables-tnat-DPOSTROUTING-s10.8.0.0/24-oeth0-jMASQUERADE; ...Jc=9Jmin=50Jmax=1000S1=81S2=149H1=1985136747H2=1102862225H3=173874812H4=513709483# Client: ly-laptop (uuid)[Peer]PublicKey=<публичныйключклиента>PresharedKey=<presharedkey>AllowedIPs=10.8.0.2/32
Параметры Jc, Jmin, Jmax, S1, S2, H1–H4 — это как раз обфускация AmneziaWG. Их трогать не нужно, если не копируешь конфиг с нуля вручную.
Клиенты на устройствах
Компьютер (Windows / Mac / Linux)
Скачайте файл конфигурации из панели (иконка скачивания у вашего клиента).
Установите клиент Amnezia (https://amnezia.org) или другой с поддержкой AmneziaWG.
В клиенте: Добавить туннель или Импорт и выберите скачанный файл.
Включите подключение.
Телефон (Android / iPhone)
Установите приложение Amnezia из App Store / Google Play.
В панели нажмите иконку QR-кода у вашего клиента.
В приложении выберите Добавить по QR-коду и отсканируйте код с экрана.
Включите VPN в приложении.
Один конфиг или QR - один клиент. Не передавайте свой конфиг другим. Не будет работать.
Проверь на сервере: ss -tlnp | grep 443 что-то должно слушать.
Проверь с сервера: curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:443/ — лучше 200.
Если на сервере всё ок, скорее всего режет фаервол хостера или свой ufw/nft: открой 443/tcp снаружи.
Клиент подключается, но интернет не работает
Включён ли IP forwarding: cat /proc/sys/net/ipv4/ip_forward → 1.
Есть ли NAT: iptables -t nat -L POSTROUTING -n -v должна быть строка MASQUERADE для 10.8.0.0/24 в сторону твоего внешнего интерфейса. Интерфейс в PostUp контейнера может быть eth0; если у тебя ens3, то добавь правило вручную и сохрани (см. шаг 5.3).
Не режет ли nftables FORWARD для wg0, то см. шаг 6.
Контейнер постоянно перезапускается (Restarting)
Смотри логи: docker logs amnezia-wg-easy. Частая причина «Cannot find device wg0» или «Missing WireGuard (Amnezia VPN) kernel module»: модуль amneziawg не установлен или не загружен на хосте. Установи пакеты из шага 4 и проверь lsmod | grep amneziawg. После обновления ядра может понадобиться перезагрузка, чтобы поднялся новый модуль.
После перезагрузки VPN не поднимается
Проверь: systemctl is-active docker, docker ps. Контейнер должен быть с --restart unless-stopped. Правила nft для wg0 добавляет сервис wg0-nft-forward.service и он должен быть включён (enable). NAT и INPUT-правила сохраняй через netfilter-persistent save.
Панель открывается по IP, но не по домену
Проверь DNS: getent hosts твой.домен или dig твой.домен должен резолвиться в IP сервера. В панели и в конфигах клиентов WG_HOST лучше указывать домен, тогда при смене IP достаточно поправить DNS.
У меня получилось и ты сможешь, я верю в тебя ❤️
Бонус 1: отчёт по трафику в Telegram
В панели amnezia-wg-easy видна только текущая скорость (KB/s), а не суммарный трафик. Зато на сервере wg show wg0 даёт по каждому пиру строку transfer: X received, Y sent. Ниже скрипт, который раз в сутки собирает эти данные и шлёт тебе в Telegram список клиентов и объём трафика (суммарно с последнего перезапуска сервера/контейнера).
Что нужно
Создать бота через @BotFather, получить токен.
Написать боту с аккаунта, куда хочешь получать отчёты.
Узнать chat_id: открыть в браузере https://api.telegram.org/bot<ТОКЕН>/getUpdates, в ответе найти "chat":"id": — это chat_id.
Скрипт /root/amnezia-wg-easy/telegram-stats.sh
#!/bin/bashCONF_DIR="/root/.amnezia-wg-easy"CONF_FILE="$CONF_DIR/wg0.conf"ENV_FILE="$CONF_DIR/telegram.env"CONTAINER_NAME="amnezia-wg-easy"[[ -f"$ENV_FILE" ]] || { echo"Create $ENV_FILE with TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID"; exit1; }source"$ENV_FILE"[[ -n"$TELEGRAM_BOT_TOKEN"&&-n"$TELEGRAM_CHAT_ID" ]] || { echo"Set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID"; exit1; }declare-APEER_NAMEScurrent_name=""while IFS=read-rline; doif [[ "$line"=~ ^#\ Client:\ (.+)$ ]]; then current_name="${BASH_REMATCH[1]}"elif [[ "$line"=~ ^PublicKey\ =\ (.+)$ ]]; then [[ -n"$current_name" ]] && PEER_NAMES["${BASH_REMATCH[1]}"]="$current_name" current_name=""fidone<"$CONF_FILE"RAW=$(docker exec "$CONTAINER_NAME" wg show wg0 2>/dev/null)||exit1NL=$'\n'TEXT="*Трафик по братанам и сестрёнкам: *${NL}${NL}"n=1current_key=""while IFS=read-rline; doif [[ "$line"=~ ^peer:\ (.+)$ ]]; then current_key="${BASH_REMATCH[1]}"elif [[ "$line"=~ transfer:\ (.+)\ received,\ (.+)\ sent ]]; then rx="${BASH_REMATCH[1]}"; tx="${BASH_REMATCH[2]}" name="${PEER_NAMES[$current_key]:-$current_key}" name="${name%% (*}" TEXT+="${n}. ${name} ↓ ${rx} ↑ ${tx}${NL}" ((n++)) current_key=""fidone<<<"$RAW"if [[ "$TEXT"==*"↓ "* ]]; thencurl-s-XPOST"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"\-d"chat_id=${TELEGRAM_CHAT_ID}"\-d"parse_mode=Markdown"\--data-urlencode"text=${TEXT}"\-d"disable_web_page_preview=1">/dev/nullfi
chmod+x/root/amnezia-wg-easy/telegram-stats.sh# Раз в сутки в 09:00(crontab-l2>/dev/null|grep-vtelegram-stats; echo"0 9 * * * /root/amnezia-wg-easy/telegram-stats.sh >> /var/log/amnezia-telegram-stats.log 2>&1") |crontab-
Ручной запуск: /root/amnezia-wg-easy/telegram-stats.sh. В Telegram придёт сообщение списком: имя клиента (без UUID), принято/отдано в MiB. Удобно смотреть, кто сколько трафика забирает без захода на сервер и без лишней магии.
Как-то так будет
Бонус 2: алерт в Telegram при нехватке RAM
На VPS с парой гигабайт памяти бывает полезно знать, когда свободная RAM падает ниже порога, чтобы не гадать, почему всё вдруг тормозит. Такой скрипт почти не забирает ресурсы.
Что нужно
Тот же Telegram-бот (или другой).
Скрипт /root/ram_alert.sh
#!/bin/bash# Проверка свободной RAM, уведомление в Telegram при нехваткеBOT_TOKEN="ТВОЙ_ТОКЕН_БОТА"CHAT_ID="ТВОЙ_CHAT_ID"MIN_FREE_MB=200COOLDOWN_FILE="/tmp/ram_alert_cooldown"COOLDOWN_SEC=3600# Свободная память в МБ (MemAvailable = free + buffers/cache)free_mb=$(awk '/MemAvailable/ {printf "%.0f", $2/1024}' /proc/meminfo)if [ "$free_mb"-ge"$MIN_FREE_MB" ]; thenexit0fi# Не спамить: не чаще раза в COOLDOWN_SECif [ -f"$COOLDOWN_FILE" ]; then last=$(stat-c %Y "$COOLDOWN_FILE" 2>/dev/null) [ -n"$last" ] && [ $(($(date +%s) - last))-lt"$COOLDOWN_SEC" ] && exit0fitouch"$COOLDOWN_FILE"msg="RAM low: ${free_mb} MB free (threshold: ${MIN_FREE_MB} MB)"curl-s-XPOST"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage"\-d"chat_id=${CHAT_ID}&text=${msg}">/dev/null
MIN_FREE_MB - порог в мегабайтах: если свободной памяти меньше, уйдёт алерт. COOLDOWN_SEC - не слать повторное уведомление чаще чем раз в этот интервал (3600 = 1 час), чтобы не заспамить при постоянной нехватке RAM.
Права и cron
chmod+x/root/ram_alert.sh# Проверка раз в 5 минутcrontab-e# Строка:*/5 **** /root/ram_alert.sh
Проверить, что бот до тебя доходит: отправить тестовое сообщение вручную:
curl-s-XPOST"https://api.telegram.org/botТВОЙ_ТОКЕН/sendMessage"\-d"chat_id=ТВОЙ_CHAT_ID&text=RAM Alert Bot: все ок, скрипт настроен."
В ответе "ok":true и сообщение пришло в чат.
P.s. в чем сила?
Если что-то устарело или не взлетело - маякни в комментариях или в телеге. Технические статьи имеют свойство прокисать быстрее молока.
Заранее спасибо
Эта статья была полезна?
Оставить комментарий
Если статья была полезной, загляни в мои другие статьи: