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 работает
Правильная проверка не “подключилось в приложении”, а фактическая маршрутизация.
-
Подключите клиента и откройте в браузере сайт проверки IP. IP должен стать серверным.
-
На сервере посмотрите, что интерфейс wg поднялся внутри контейнера:
docker exec -it wg-easy wg show
Если команда показывает peers, handshakes и transfer, это хороший знак.
-
Если 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, дальше упираетесь в скорость шифрования и сеть, а не в “настройки”.
