Установка wg-easy на VPS: WireGuard VPN с веб-панелью

wg-easy это самый быстрый способ поднять WireGuard VPN и управлять пользователями через веб-интерфейс: добавлять клиентов, получать QR-коды для телефона, отзывать доступ, смотреть трафик и не ковыряться каждый раз в ручных конфигах. В этом гайде вы поставите wg-easy на чистый VPS (Debian 12, Ubuntu 24.04 или AlmaLinux 9), включите IP forwarding, откроете нужные порты, ограничите доступ к панели и проверите, что VPN реально маршрутизирует трафик. По усилиям это 15-30 минут, по рискам главный один: если оставить панель открытой всему интернету, вы сами создадите себе проблему.

Для запуска без возни обычно проще взять VPS на xhost24, попросить подготовить сервер под Docker, а миграцию и перенос мы закроем бесплатно. Если уже есть VPS, ниже всё делается одним скриптом с прогрессом и самопроверками.

Что нужно от сервера и какие порты понадобятся

wg-easy работает в Docker-контейнере и использует ядро WireGuard на хосте. Минимально хватает 1 vCPU и 1 GB RAM, но комфортнее 2 vCPU и 2 GB, особенно если клиентов больше 10-20 и вы гоняете скорость. Диск не критичен, NVMe приятен, но решает не он.

Порты:

  • 51820/UDP это сам WireGuard

  • 51821/TCP это веб-панель wg-easy

Панель 51821 нельзя держать открытой для всех. Правильная схема: доступ только с вашего IP или через SSH-туннель.

Быстрая установка одним bash-скриптом с проверками

Скрипт делает всё сам:

  • ставит Docker и плагин docker compose

  • включает sysctl для маршрутизации

  • создаёт docker compose для wg-easy без плейсхолдеров

  • поднимает контейнер

  • настраивает firewall (UFW на Debian/Ubuntu, firewalld на AlmaLinux)

  • проверяет порты, модуль wireguard, работу панели и базовую маршрутизацию

Запускать от root. Он спросит домен или IP сервера, пароль для панели и ваш IP, с которого разрешить вход в веб-панель. Если вы не знаете свой IP, откройте любой сайт “what is my ip” в браузере и вставьте значение.

cat > /root/install-wg-easy-xhost24.sh <<'BASH'
#!/usr/bin/env bash
set -euo pipefail

log(){ printf "\n[%s] %s\n" "$(date '+%H:%M:%S')" "$*"; }
die(){ echo "ERROR: $*" >&2; exit 1; }

[[ "$(id -u)" -eq 0 ]] || die "Run as root"

detect_os() {
  if command -v apt-get >/dev/null 2>&1; then
    OS="debian"
  elif command -v dnf >/dev/null 2>&1; then
    OS="rhel"
  else
    die "Unsupported OS. Use Debian/Ubuntu or AlmaLinux"
  fi
}

ask() {
  read -r -p "Public IP or domain for WG endpoint (example 203.0.113.10 or vpn.example.com): " WG_HOST
  [[ -n "${WG_HOST}" ]] || die "WG_HOST is empty"

  read -r -s -p "Password for wg-easy web panel: " WG_PASSWORD; echo
  [[ -n "${WG_PASSWORD}" ]] || die "Password is empty"

  read -r -p "Admin IP allowed to access web panel 51821 (example 203.0.113.55): " ADMIN_IP
  [[ -n "${ADMIN_IP}" ]] || die "ADMIN_IP is empty"

  read -r -p "VPN client subnet [10.8.0.0/24]: " VPN_SUBNET
  VPN_SUBNET="${VPN_SUBNET:-10.8.0.0/24}"

  read -r -p "VPN server address inside tunnel [10.8.0.1]: " VPN_SERVER_IP
  VPN_SERVER_IP="${VPN_SERVER_IP:-10.8.0.1}"

  read -r -p "DNS for clients (comma separated) [1.1.1.1,1.0.0.1]: " VPN_DNS
  VPN_DNS="${VPN_DNS:-1.1.1.1,1.0.0.1}"
}

install_docker_debian() {
  log "Installing Docker on Debian/Ubuntu"
  export DEBIAN_FRONTEND=noninteractive
  apt-get update -y
  apt-get upgrade -y
  apt-get install -y ca-certificates curl gnupg lsb-release ufw

  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  chmod a+r /etc/apt/keyrings/docker.gpg

  echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(. /etc/os-release && echo "$ID") \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  > /etc/apt/sources.list.d/docker.list

  apt-get update -y
  apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl enable --now docker
}

install_docker_rhel() {
  log "Installing Docker on AlmaLinux"
  dnf -y update
  dnf -y install dnf-plugins-core firewalld curl
  dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl enable --now docker
  systemctl enable --now firewalld
}

enable_forwarding() {
  log "Enabling IP forwarding"
  cat > /etc/sysctl.d/99-wg-forwarding.conf <<'CONF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
CONF
  sysctl --system >/dev/null

  if ! lsmod | grep -q '^wireguard'; then
    log "Trying to load wireguard kernel module"
    modprobe wireguard 2>/dev/null || true
  fi
}

deploy_wg_easy() {
  log "Deploy wg-easy via Docker Compose"
  mkdir -p /opt/wg-easy
  cd /opt/wg-easy

  cat > compose.yml <<EOF
services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:latest
    container_name: wg-easy
    environment:
      - WG_HOST=${WG_HOST}
      - PASSWORD=${WG_PASSWORD}
      - WG_DEFAULT_ADDRESS=${VPN_SUBNET}
      - WG_DEFAULT_DNS=${VPN_DNS}
      - WG_PORT=51820
      - WG_DEVICE=eth0
      - WG_ALLOWED_IPS=0.0.0.0/0,::/0
    volumes:
      - ./etc-wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    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
      - net.ipv6.conf.all.forwarding=1
    restart: unless-stopped
EOF

  docker compose up -d
}

configure_firewall_debian() {
  log "Configuring UFW"
  ufw --force reset
  ufw default deny incoming
  ufw default allow outgoing
  ufw allow 22/tcp
  ufw allow 51820/udp
  ufw allow from "${ADMIN_IP}" to any port 51821 proto tcp
  ufw --force enable
  ufw status verbose
}

configure_firewall_rhel() {
  log "Configuring firewalld"
  firewall-cmd --set-default-zone=public
  firewall-cmd --permanent --add-service=ssh
  firewall-cmd --permanent --add-port=51820/udp
  firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='${ADMIN_IP}/32' port port='51821' protocol='tcp' accept"
  firewall-cmd --reload
  firewall-cmd --list-all
}

checks() {
  log "Checks: docker, container, ports"
  docker --version
  docker compose version
  docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

  log "Checks: sysctl forwarding"
  sysctl net.ipv4.ip_forward | grep -q ' = 1' && echo "IPv4 forwarding OK"
  sysctl net.ipv6.conf.all.forwarding | grep -q ' = 1' && echo "IPv6 forwarding OK"

  log "Checks: listening ports"
  ss -lunp | grep -q ':51820' && echo "51820/udp listening OK" || echo "51820/udp not listening"
  ss -lntp | grep -q ':51821' && echo "51821/tcp listening OK" || echo "51821/tcp not listening"

  log "Checks: panel health (local)"
  curl -fsS http://127.0.0.1:51821/ >/dev/null && echo "Panel HTTP OK" || echo "Panel not responding locally"

  log "Result"
  echo "wg-easy panel: http://${WG_HOST}:51821 (allowed only from ${ADMIN_IP})"
  echo "WireGuard UDP port: 51820"
  echo "Config dir: /opt/wg-easy/etc-wireguard"
  echo "Next: open panel, login with your password, create client, scan QR code in WireGuard app"
}

detect_os
ask

if [[ "${OS}" == "debian" ]]; then
  install_docker_debian
else
  install_docker_rhel
fi

enable_forwarding
deploy_wg_easy

if [[ "${OS}" == "debian" ]]; then
  configure_firewall_debian
else
  configure_firewall_rhel
fi

checks
BASH

chmod +x /root/install-wg-easy-xhost24.sh
/root/install-wg-easy-xhost24.sh

После выполнения заходите в панель по адресу http://ваш_IP_или_домен:51821, вводите пароль, создаёте клиента и сканируете QR-код в WireGuard на телефоне. На ПК можно скачать конфиг и импортировать в WireGuard.

Как правильно пользоваться wg-easy в продакшне

Сценарий “просто включить VPN” обычно заканчивается хаосом, если вы не введёте простые правила. Сразу договоритесь о порядке: на каждого человека или устройство отдельный профиль, не один конфиг на всех. При увольнении или смене устройства вы просто отключаете конкретного клиента, а не перевыпускаете всё.

wg-easy показывает список клиентов и позволяет выключать доступ. Это удобно, но не отменяет базовой дисциплины:

  • не храните конфиги в общих чатах

  • давайте доступ на минимум устройств

  • периодически ревизируйте список клиентов и отключайте лишнее

Если вы делаете VPN не только “для себя”, а под команду или клиентов, держите отдельную учётку админа и ограниченный доступ к панели по IP. Панель всегда слабее, чем сам WireGuard протокол, поэтому её надо защищать в первую очередь.

Проверка, что VPN работает

Правильная проверка не “подключилось в приложении”, а фактическая маршрутизация.

  1. Подключите клиента и откройте в браузере сайт проверки IP. IP должен стать серверным.

  2. На сервере посмотрите, что интерфейс wg поднялся внутри контейнера:

docker exec -it wg-easy wg show

Если команда показывает peers, handshakes и transfer, это хороший знак.

  1. Если VPN подключился, но интернет не работает, почти всегда проблема в forwarding или в правилах NAT. В этом руководстве forwarding включается и в sysctl, и в контейнере. Проверьте на хосте:

sysctl net.ipv4.ip_forward

Должно быть = 1.

Частые ошибки

Панель 51821 не открывается

Сначала отделите firewall от сервиса. Локально на сервере:

curl -I http://127.0.0.1:51821/ | head -n 1
docker logs wg-easy --tail 200
ss -lntp | grep 51821 || true

Если локально панель отвечает, а снаружи нет, значит вы не попали в разрешённый IP или firewall режет. Это нормально, потому что вы сами закрыли панель от всего мира. Проверьте, что ADMIN_IP указан правильно, и при необходимости добавьте ещё один IP в правила.

WireGuard подключается, но трафик не идёт

Типовая причина: отключён forwarding или провайдерский интерфейс не eth0. В скрипте стоит WG_DEVICE=eth0, но на некоторых серверах интерфейс может быть ens3 или enp1s0. Посмотрите имя интерфейса:

ip -br a

Если внешний интерфейс не eth0, замените WG_DEVICE в /opt/wg-easy/compose.yml, затем:

cd /opt/wg-easy
docker compose up -d

Ошибка про wireguard module или нет handshake

На редких VPS ядро без поддержки WireGuard или модуль не грузится. Проверьте:

lsmod | grep wireguard || true
modprobe wireguard || true
dmesg | tail -n 50

Если модуль не загрузился и в dmesg ошибки про “not found”, значит в конкретной конфигурации VPS ядро не поддерживает WireGuard. Решение простое: сменить тариф или локацию на VPS с полноценным ядром. В xhost24 это решается быстрее всего сменой сервера на совместимую площадку, а перенос настроек занимает минуты, потому что весь конфиг лежит в /opt/wg-easy/etc-wireguard.

Безопасность, правильно

Минимальный набор, который реально снижает риск:

  • порт 51821 открывать только с вашего IP или вообще не открывать и заходить через SSH-туннель

  • ставить длинный пароль, не “123456”

  • не держать десятки активных клиентов, которые вы не помните

Если вы хотите вообще убрать риск панели, используйте доступ через SSH-туннель и закройте 51821 полностью. Тогда панель доступна только вам:

ssh -L 51821:127.0.0.1:51821 root@ваш_сервер

И открываете в браузере http://127.0.0.1:51821.

От одного VPN до нескольких регионов и отказоустойчивости

wg-easy по сути single-node. Он идеален как быстрый и понятный шлюз, но когда у вас растёт команда, география и требования к аптайму, появляется нормальная траектория масштабирования.

Стадия 1 это один VPS и один endpoint. Подходит большинству. Обычно выбирают локацию ближе к пользователям и держат 10-50 клиентов.

Стадия 2 это второй VPS в другом регионе как резерв. Клиентам делаете второй профиль, а при проблемах переключаетесь. Это не идеальный “автофейловер”, но это реально работает и стоит копейки по сравнению с простоями.

Стадия 3 это продакшн-схема: отдельные VPN-шлюзы для разных задач, отдельные подсети под сегменты, централизованный мониторинг, и при необходимости свой диапазон IP и управление маршрутизацией. Когда бизнес упирается в сеть, вам важны не “панельки”, а контроль адресов, PTR/WHOIS, иногда подсети и более серьёзные сетевые опции. В этот момент полезно, когда провайдер может дать дополнительные IPv4 и сделать инфраструктуру так, чтобы вы не были привязаны к одному серверу.

Если вы сейчас на стадии “надо быстро поднять VPN и забыть”, wg-easy на VPS xhost24 закрывает задачу идеально: подняли за вечер, доступы выдали, список клиентов управляется из панели, а при росте вы спокойно переноситесь на более мощный сервер без смены подхода.

FAQ

Что выбрать для wg-easy: Debian 12 или Ubuntu 24.04?

Оба норм. Для максимально предсказуемого продакшна чаще берут Debian 12, для более свежей базы и пакетов удобно Ubuntu 24.04.

Нужно ли ставить WireGuard на хост отдельно, если всё в Docker?

Обычно нет. Важнее, чтобы ядро поддерживало WireGuard и был включён forwarding.

Можно ли повесить HTTPS на панель wg-easy?

Можно, но чаще практичнее держать панель закрытой по IP или через SSH-туннель. Это проще и безопаснее, чем выставлять админку наружу.

Почему клиент подключился, но сайты не открываются?

Смотрите forwarding и правильный внешний интерфейс (WG_DEVICE). Это две самые частые причины.

Сколько клиентов выдержит один VPS?

Зависит от CPU и канала. Для десятков пользователей хватает 2 vCPU и 2 GB, дальше упираетесь в скорость шифрования и сеть, а не в “настройки”.

  • vpn
  • 0 Пользователи нашли это полезным
Помог ли вам данный ответ?

Связанные статьи

Установка PHP и MySQL на Debian

Типовая ситуация: вы взяли VPS, поставили Debian, но проект стоит, потому что непонятно с чего...