MAATRIX / Блог / wg-easy: веб-панель управления WireGuard без консоли

wg-easy: веб-панель управления WireGuard без консоли

MAATRIX

Если вы уже настраивали WireGuard на VPS вручную, то знаете это ощущение: третий клиент — и вы снова редактируете wg0.conf через nano, вручную подбираете свободный IP в подсети и генерируете QR-код отдельной командой. wg-easy убирает всю эту рутину: один контейнер поднимает и WireGuard, и веб-панель, где клиент добавляется тремя кликами, а конфиг и QR-код появляются сразу же. Ниже — как развернуть wg-easy через Docker, что означают его переменные окружения и на что обратить внимание в первую очередь.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что делает wg-easy и когда он оправдан

wg-easy — это открытый проект, который упаковывает WireGuard-сервер и Node.js-панель в один Docker-контейнер. Внутри контейнер сам генерирует ключи, поднимает интерфейс wg0, прописывает правила iptables для NAT и форвардинга, а панель на порту 51821 даёт веб-интерфейс для управления пирами. Никакого SSH после установки не требуется — все операции с клиентами делаются через браузер.

Это оправдано, когда:

  • клиентов больше двух-трёх и они появляются/исчезают регулярно (сотрудники, устройства, гости);
  • конфиги и QR-коды нужно выдавать людям, которые не разбираются в WireGuard и не полезут в терминал;
  • хочется видеть в одном месте, кто подключён сейчас и когда был последний handshake, без wg show.

Если сервер один, а клиента два и они не меняются месяцами, ручная настройка по классической схеме будет проще и без лишнего слоя — панель добавляет процесс (контейнер, порт, пароль), за который тоже нужно отвечать. Взамен она экономит время на каждом следующем клиенте.

Установка через Docker Compose

Нужен VPS с публичным IP и установленным Docker Engine с плагином Compose. Если Docker ещё не стоит — сначала установите Docker на Ubuntu 24.04 или на используемый вами дистрибутив.

Понадобятся два открытых порта: 51820/udp — сам туннель WireGuard, и 51821/tcp — веб-панель (номер можно и нужно сменить, об этом ниже). Ядро должно поддерживать WireGuard (в современных дистрибутивах Ubuntu, Debian, AlmaLinux — из коробки) и разрешать форвардинг пакетов:

echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf

Проверьте, что порты не заняты другим процессом, и откройте их в firewall хоста заранее — контейнер сам с ufw или firewalld ничего не сделает:

ufw allow 51820/udp
ufw allow 51821/tcp

Порт панели стоит открывать точечно, а не на весь интернет — вернёмся к этому в разделе про безопасность. Теперь создайте каталог проекта и файл docker-compose.yml:

mkdir -p ~/wg-easy && cd ~/wg-easy
nano docker-compose.yml

Базовый конфиг:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy
    container_name: wg-easy
    environment:
      - WG_HOST=203.0.113.10
      - PASSWORD_HASH=замените_на_bcrypt_хэш
      - PORT=51821
      - WG_PORT=51820
      - WG_DEFAULT_DNS=1.1.1.1
      - WG_DEFAULT_ADDRESS=10.8.0.x
    volumes:
      - ./data:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

Разберём ключевые переменные. WG_HOST — публичный IP или доменное имя сервера, именно этот адрес попадёт в поле Endpoint всех выданных клиентских конфигов, поэтому здесь нужен реальный внешний адрес, а не localhost и не внутренний IP контейнера. WG_PORT — UDP-порт туннеля, PORT — порт веб-панели внутри контейнера (наружу он проброшен той же цифрой в секции ports, но их можно развести). WG_DEFAULT_ADDRESS задаёт шаблон подсети для новых клиентов — символ x панель сама заменит на очередной свободный номер.

Каталог ./data — это единственное, что нужно бэкапить: внутри лежат все ключи сервера и клиентов, конфиг wg0.json и служебные файлы.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Пароль и первый запуск

Открытая веб-панель без пароля — это доступ к вашему VPN-серверу для кого угодно, поэтому PASSWORD_HASH обязателен. Хэш генерируется тем же образом, что и сам сервис, без установки лишних утилит:

docker run --rm ghcr.io/wg-easy/wg-easy wgpw 'ваш_надёжный_пароль'

Команда выведет строку вида PASSWORD_HASH='$2a$...' — вставьте её в docker-compose.yml целиком, вместе с кавычками, если в хэше есть символ $ (в YAML его лучше экранировать одинарными кавычками, как в примере выше). Пустой PASSWORD_HASH в некоторых версиях образа трактуется как «пароль не требуется» — проверьте, что переменная реально попала в контейнер, прежде чем открывать порт наружу.

Запускаем:

docker compose up -d
docker compose logs -f wg-easy

В логах должно появиться сообщение о том, что интерфейс wg0 поднят и панель слушает порт. Дальше открываем http://<IP-сервера>:51821 в браузере и вводим пароль. Если панель не открывается — сначала проверьте docker compose ps (контейнер должен быть running, не restarting), а затем — что порт 51821 действительно проброшен и не блокируется firewall хостера отдельно от ufw на самом сервере.

Добавление и удаление клиентов

Внутри панели вся работа с пирами сведена к кнопке «New Client» вверху экрана:

  1. нажмите «New Client», введите имя (например, laptop-anna или phone-ivan) — по имени потом легче искать нужное устройство в списке;
  2. панель сама сгенерирует пару ключей и выдаст свободный IP из подсети WG_DEFAULT_ADDRESS;
  3. на карточке клиента сразу доступны кнопка скачивания .conf-файла и QR-код для мобильных приложений.

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

В карточке клиента также видно объём переданного и принятого трафика и время последнего handshake — те же данные, что раньше приходилось смотреть через wg show по SSH, только в браузере и сразу по всем клиентам.

QR-коды и раздача конфигов

Ради этого пункта многие и ставят wg-easy: подключение телефона занимает секунды. На карточке клиента нажмите иконку QR-кода — панель покажет код прямо в браузере. На телефоне откройте приложение WireGuard, выберите подключение с Android или с iPhone через сканирование QR — и туннель поднимется без единого символа, введённого вручную.

Для ноутбуков и десктопов, где сканировать QR неудобно, используйте кнопку скачивания .conf-файла — он импортируется в клиент WireGuard как обычный файл конфигурации.

Важный нюанс: QR-код и файл содержат приватный ключ клиента в открытом виде. Показ QR-кода в браузере — это фактически передача секрета, поэтому не отправляйте скриншот кода в общий чат и не оставляйте открытую вкладку панели на чужом экране. Если конфиг скомпрометирован — просто удалите клиента в панели и создайте нового, старые ключи после удаления теряют силу.

Безопасность: за что отвечаете именно вы

wg-easy снимает рутину с управления клиентами, но не снимает с вас ответственность за периметр. Несколько вещей, на которые стоит обратить внимание сразу после установки:

  • Не держите панель открытой на весь интернет. Порт 51821 — привлекательная цель: это единая точка входа ко всем вашим клиентам и ключам. Ограничьте доступ через firewall по конкретным IP, повесьте панель за отдельный VPN-туннель или хотя бы за reverse-proxy с базовой аутентификацией и IP-whitelist.
  • Терминируйте HTTPS перед панелью. Сам wg-easy отдаёт интерфейс по HTTP без TLS. Пароль при входе уходит в открытом виде, если между вами и сервером нет шифрования. Поставьте перед контейнером Caddy или nginx с автоматическим Let's Encrypt и проксируйте на 127.0.0.1:51821, не публикуя порт наружу напрямую.
  • Не теряйте каталог ./data. Это единственное место, где хранятся приватные ключи сервера и всех клиентов. Потеря каталога означает пересоздание всех туннелей с нуля — регулярно копируйте его на отдельный диск или в другое хранилище.
  • Используйте длинный пароль панели, а не то же самое, что и для SSH или почты — компрометация панели даёт доступ ко всей VPN-инфраструктуре разом.

Обновление и типичные проблемы

Обновление — это пересоздание контейнера с новым образом, данные при этом сохраняются в volume:

docker compose pull
docker compose up -d

Перед обновлением на мажорную версию (например, если в тегах образа сменился номер v1x на v1x+1) загляните в changelog проекта на GitHub — формат wg0.json иногда меняется между крупными релизами, и без миграции старые клиенты могут не подхватиться после обновления. Простое правило: перед любым апдейтом делайте копию каталога ./data, тогда откат — это просто docker compose down, возврат старого образа в compose-файле и up -d заново.

Частые проблемы на практике:

  • Панель поднялась, но клиенты не видят интернет — почти всегда причина в net.ipv4.ip_forward, который сброшен на хосте, или в том, что контейнер не получил cap_add: NET_ADMIN — без этой capability он не может настроить iptables-правила NAT.
  • WG_HOST указывает не туда — если в него по ошибке попал внутренний IP или домен без A-записи, все выданные ранее конфиги окажутся нерабочими; после исправления переменной старым клиентам нужно перевыпустить конфиг заново.
  • Контейнер не стартует после перезагрузки хоста — проверьте restart: unless-stopped в compose-файле и что сам Docker в systemd находится в автозапуске.
  • Порт 51820 занят — если на сервере уже стоит классический WireGuard, поднятый вручную по инструкции для VPS, сначала остановите системный интерфейс wg-quick@wg0, иначе оба процесса будут конфликтовать за один порт.

Более общие сетевые сбои самого WireGuard — отсутствие handshake, обрыв туннеля, доступ есть, а трафика нет — разобраны отдельно в статье про частые ошибки WireGuard на сервере, и они актуальны для wg-easy точно так же, потому что внутри контейнера работает тот же протокол.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем wg-easy отличается от обычного WireGuard?

Это тот же протокол и тот же интерфейс wg0, но управление вынесено в веб-панель: генерация ключей, IP-адресов, QR-кодов и правил NAT автоматизирована контейнером вместо ручной правки wg0.conf.

Можно ли запустить wg-easy рядом с уже настроенным вручную WireGuard?

Не на одном UDP-порту — будет конфликт. Либо остановите системный wg-quick@wg0, либо запустите wg-easy на другом порту через переменную WG_PORT.

Нужен ли отдельный домен для панели?

Не обязателен, доступ работает и по IP, но домен нужен, если вы хотите поставить перед панелью HTTPS через Let's Encrypt — для валидного сертификата нужна A-запись.

Как перенести wg-easy на другой сервер?

Скопируйте каталог ./data целиком на новый сервер, разверните тот же docker-compose.yml с обновлённым WG_HOST (новый IP) и запустите — ключи и клиенты сохранятся, но конфиги у клиентов из-за смены Endpoint придётся перевыпустить.

Что будет, если забыть пароль от панели?

Штатного восстановления через интерфейс нет — придётся зайти на сервер и задать новый PASSWORD_HASH в compose-файле, затем пересоздать контейнер командой docker compose up -d.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →