15 ИЮЛ

Свой VPN за 5 минут: WireGuard, удобная админка и полная защита через Nginx Proxy Manager

15 июля, 2026 Автор: Timur Просмотров: 3 Рейтинг 0.00 (0 Голос)
Оцените статью:
0.00 (0)

WireGuard — один из самых быстрых, безопасных и современных VPN-протоколов. Благодаря высокой производительности, простоте настройки и работе непосредственно в ядре Linux он стал стандартом де-факто для организации личных VPN-серверов, безопасного удаленного доступа и объединения нескольких устройств в единую защищенную сеть.

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

Для этой задачи существует wg-easy — легковесная панель управления WireGuard, работающая в Docker-контейнере.

В этой статье мы рассмотрим, как установить WireGuard VPN на Ubuntu 22.04 или Ubuntu 24.04 с помощью Docker, безопасно опубликовать веб-интерфейс через Nginx Proxy Manager, автоматически получить SSL-сертификат Let’s Encrypt и избежать распространённых ошибок, связанных с Docker Compose и Cloudflare.

Инструкция подходит практически для любого VPS, включая DigitalOcean, Contabo, Hetzner, Vultr, OVH и других провайдеров.


Что получится в результате

После выполнения инструкции вы получите:

  • полностью рабочий WireGuard VPN-сервер;
  • удобную веб-панель управления wg-easy;
  • автоматическую генерацию QR-кодов для подключения смартфонов;
  • защищённый HTTPS-доступ через Let’s Encrypt;
  • отсутствие открытого административного порта;
  • совместимость с Docker Compose V1 и Docker Compose V2;
  • возможность подключения клиентов Windows, Linux, macOS, Android и iPhone.

Архитектура решения

В данной инструкции используется схема, при которой VPN и веб-интерфейс работают независимо друг от друга.

VPN-трафик

Клиенты WireGuard подключаются напрямую к UDP-порту сервера (51820). Такой подход обеспечивает минимальные задержки и максимальную производительность.

Веб-интерфейс

Порт панели управления (51821) не публикуется в Интернет.

Контейнер wg-easy подключается к общей Docker-сети с Nginx Proxy Manager, который:

  • принимает HTTPS-запросы;
  • автоматически получает SSL-сертификат Let’s Encrypt;
  • проксирует запросы во внутреннюю Docker-сеть.

Таким образом административный интерфейс остается изолированным, а наружу доступны только HTTPS и VPN.


Предварительные требования

Перед началом убедитесь, что у вас имеются:

  • VPS с Ubuntu 22.04 или Ubuntu 24.04;
  • установленный Docker;
  • установленный Docker Compose (V1 или V2);
  • установленный Nginx Proxy Manager;
  • Docker-сеть, к которой подключён Nginx Proxy Manager (в примере используется proxy-network);
  • домен или поддомен, указывающий на IP-адрес вашего VPS.

Проверяем установленную версию Docker Compose

Сначала определим, какая версия Docker Compose используется на сервере.

Попробуйте выполнить:

docker compose version

Если отображается номер версии — используется Docker Compose V2.

Если появляется ошибка:

docker: unknown command: compose

проверьте старую команду:

docker-compose version

Если она работает — значит установлен Docker Compose V1.

Скрипт, используемый далее в статье, автоматически определяет доступную версию Docker Compose, поэтому дополнительных действий не требуется.


Шаг 1. Настройка DNS и Cloudflare

Создайте A-запись для поддомена, например:

vpn.example.com

которая указывает на IP-адрес вашего VPS.

Если используется Cloudflare, обязательно переведите запись в режим DNS Only (серое облако).

Это важно, поскольку WireGuard использует UDP-трафик, который Cloudflare не проксирует.


Шаг 2. Открываем порт WireGuard

Если используется UFW, выполните:

sudo ufw allow 51820/udp

Если используется другой фаервол — откройте UDP-порт 51820 соответствующим способом.


Шаг 3. Создаем скрипт автоматической установки

Создайте файл:

nano install_vpn.sh

И вставьте код скрипта:

#!/bin/bash
#===============================================================================#
#   WIREGUARD VPN (wg-easy) + NGINX PROXY MANAGER
#   Compatible with Docker Compose V1 and V2
#===============================================================================#

set -Eeuo pipefail

GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'

# Проверенная версия wg-easy. Для ветки v14 в GHCR публикуется мажорный
# тег "14"; если хотите жёстко зафиксировать результат, укажите точный
# тег со страницы https://github.com/wg-easy/wg-easy/releases
WG_EASY_VERSION="14"

VPN_DIR="$HOME/vpn-docker"
VPN_PORT=51820
UI_PORT=51821

# ===================================================================
# ИЗМЕНИТЕ ЭТИ ПАРАМЕТРЫ ПОД СВОЮ ИНФРАСТРУКТУРУ
# ===================================================================
DOMAIN="vpn.example.com"
NPM_NETWORK="proxy-network"
# ===================================================================

echo -e "${CYAN}=== Установка WireGuard VPN (wg-easy) ===${NC}"

# -------------------------------------------------------------------
# Проверка параметров
# -------------------------------------------------------------------
if [ "$DOMAIN" = "vpn.example.com" ]; then
    echo -e "${RED}Измените DOMAIN в начале скрипта.${NC}"
    exit 1
fi

# -------------------------------------------------------------------
# Проверка Docker
# -------------------------------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
    echo -e "${RED}Docker не установлен.${NC}"
    exit 1
fi

# -------------------------------------------------------------------
# Определяем Docker Compose
# -------------------------------------------------------------------
if docker compose version >/dev/null 2>&1; then
    COMPOSE="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
    COMPOSE="docker-compose"
else
    echo -e "${RED}Docker Compose не найден.${NC}"
    echo ""
    echo "Установите Docker Compose и повторите попытку."
    exit 1
fi

echo -e "${GREEN}Используется:${NC} ${COMPOSE}"

# -------------------------------------------------------------------
# Проверка Docker Network
# -------------------------------------------------------------------
if ! docker network inspect "$NPM_NETWORK" >/dev/null 2>&1; then
    echo -e "${RED}Docker-сеть '$NPM_NETWORK' не существует.${NC}"
    echo ""
    echo "Доступные сети:"
    docker network ls
    exit 1
fi

# -------------------------------------------------------------------
# Подготовка каталогов
# -------------------------------------------------------------------
mkdir -p "$VPN_DIR/data"
cd "$VPN_DIR"

# -------------------------------------------------------------------
# Пароль администратора
# -------------------------------------------------------------------
while true; do

    echo -e "${YELLOW}Введите пароль администратора:${NC}"
    read -r -s ADMIN_PASS
    echo

    echo -e "${YELLOW}Повторите пароль:${NC}"
    read -r -s ADMIN_PASS_CONFIRM
    echo

    if [ -z "$ADMIN_PASS" ]; then
        echo -e "${RED}Пароль не может быть пустым.${NC}"
        continue
    fi

    if [ "$ADMIN_PASS" != "$ADMIN_PASS_CONFIRM" ]; then
        echo -e "${RED}Пароли не совпадают.${NC}"
        continue
    fi

    break

done

# -------------------------------------------------------------------
# Скачивание образа
# -------------------------------------------------------------------
WG_IMAGE="ghcr.io/wg-easy/wg-easy:${WG_EASY_VERSION}"

echo -e "${CYAN}Загрузка образа ${WG_IMAGE}...${NC}"

if ! docker pull "$WG_IMAGE"; then
    echo -e "${RED}Не удалось скачать образ ${WG_IMAGE}.${NC}"
    echo "Проверьте подключение к Интернету и доступность ghcr.io."
    exit 1
fi

# -------------------------------------------------------------------
# Генерация BCrypt-хеша
# -------------------------------------------------------------------
echo -e "${CYAN}Генерация хеша пароля...${NC}"

RAW_OUTPUT=$(docker run --rm "$WG_IMAGE" wgpw "$ADMIN_PASS" 2>/dev/null)

if [ -z "$RAW_OUTPUT" ]; then
    echo -e "${RED}Не удалось создать хеш пароля.${NC}"
    exit 1
fi

# wgpw может вернуть "PASSWORD_HASH='$2a$12$...'" или просто хеш.
# Извлекаем чистый bcrypt-хеш через sed (POSIX-совместимо).
HASH=$(printf '%s\n' "$RAW_OUTPUT" | sed -n "s/.*\\(\\\$2[aby]\\\$[^ '\"]*\\).*/\\1/p" | tail -1)

if [ -z "$HASH" ]; then
    echo -e "${RED}Не удалось извлечь bcrypt-хеш из вывода wgpw.${NC}"
    echo "Вывод команды: $RAW_OUTPUT"
    exit 1
fi

echo -e "${GREEN}Хеш пароля создан.${NC}"

# -------------------------------------------------------------------
# .env
# -------------------------------------------------------------------
cat > .env <<EOF
WG_HOST=$DOMAIN
WG_PORT=$VPN_PORT
PORT=$UI_PORT
PASSWORD_HASH=$HASH
EOF

if [ ! -f .env ]; then
    echo -e "${RED}Не удалось создать файл .env${NC}"
    exit 1
fi

# -------------------------------------------------------------------
# docker-compose.yml
# -------------------------------------------------------------------
cat > docker-compose.yml <<EOF
services:

  wg-easy:

    image: $WG_IMAGE

    container_name: wg-easy

    restart: unless-stopped

    environment:
      - LANG=ru
      - WG_HOST
      - PASSWORD_HASH
      - PORT
      - WG_PORT
      - WG_DEFAULT_DNS=1.1.1.1,1.0.0.1
      - WG_ALLOWED_IPS=0.0.0.0/0
      - WG_MTU=1420

    volumes:
      - ./data:/etc/wireguard

    ports:
      - "\${WG_PORT}:\${WG_PORT}/udp"

    cap_add:
      - NET_ADMIN
      - SYS_MODULE

    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1

    networks:
      - $NPM_NETWORK

networks:

  $NPM_NETWORK:
    external: true
EOF

if [ ! -f docker-compose.yml ]; then
    echo -e "${RED}Не удалось создать файл docker-compose.yml${NC}"
    exit 1
fi

# -------------------------------------------------------------------
# Диагностика при сбое запуска
# -------------------------------------------------------------------
show_diagnostics() {
    echo ""
    echo "Диагностика:"
    if docker container inspect wg-easy >/dev/null 2>&1; then
        docker logs wg-easy --tail 20 2>&1 || true
        echo ""
    fi
    docker ps -a --filter name=wg-easy
}

# -------------------------------------------------------------------
# Запуск
# -------------------------------------------------------------------
echo -e "${CYAN}Запуск контейнера...${NC}"

$COMPOSE down >/dev/null 2>&1 || true

if ! $COMPOSE up -d; then
    echo -e "${RED}Ошибка запуска контейнера.${NC}"
    exit 1
fi

# -------------------------------------------------------------------
# Ожидание запуска
# -------------------------------------------------------------------
echo -e "${CYAN}Ожидание запуска контейнера...${NC}"

STARTED=false

for i in $(seq 1 20); do
    if docker ps --format '{{.Names}}' | grep -q '^wg-easy$'; then
        STARTED=true
        break
    fi
    sleep 1
done

if [ "$STARTED" != "true" ]; then
    echo -e "${RED}Контейнер wg-easy не запустился.${NC}"
    show_diagnostics
    exit 1
fi

# Контейнер появился в спискеубедимся, что он не упал через
# несколько секунд после старта (типично при ошибке в конфигурации).
sleep 3

RUNNING=$(docker inspect -f '{{.State.Running}}' wg-easy 2>/dev/null || echo "false")

if [ "$RUNNING" != "true" ]; then
    echo -e "${RED}Контейнер wg-easy запустился, но сразу завершился.${NC}"
    show_diagnostics
    exit 1
fi

echo ""
echo -e "${GREEN}====================================================${NC}"
echo -e "${GREEN} WireGuard VPN успешно установлен!${NC}"
echo -e "${GREEN}====================================================${NC}"
echo ""
echo -e "Домен            : ${GREEN}${DOMAIN}${NC}"
echo -e "VPN UDP порт     : ${GREEN}${VPN_PORT}${NC}"
echo -e "UI порт (внутр.) : ${GREEN}${UI_PORT}${NC}"
echo -e "Образ            : ${GREEN}${WG_IMAGE}${NC}"
echo -e "Docker Compose   : ${GREEN}${COMPOSE}${NC}"
echo -e "Данные WireGuard : ${GREEN}${VPN_DIR}/data${NC}"
echo ""
echo "Следующий шаг:"
echo "Создайте Proxy Host в Nginx Proxy Manager:"
echo ""
echo "  Domain Names          : ${DOMAIN}"
echo "  Scheme                : http"
echo "  Forward Hostname/IP   : wg-easy"
echo "  Forward Port          : ${UI_PORT}"
echo "  Block Common Exploits : включить"
echo "  SSL                   : Request a new SSL Certificate"
echo "  Force SSL             : включить"
echo "  HTTP/2 Support        : включить"
echo ""
echo "После этого откройте: https://${DOMAIN}"
echo ""

Обратите внимание: скрипт содержит проверку параметра DOMAIN — если оставить значение по умолчанию (vpn.example.com), он завершится с ошибкой и не будет создавать файлы. Это защита от случайного запуска без настройки.

Поэтому перед запуском скрипта измените следующие параметры:

DOMAIN="vpn.example.com"
NPM_NETWORK="proxy-network"

DOMAIN

Полное доменное имя панели управления. Например:

DOMAIN="vpn.example.com"

NPM_NETWORK

Имя Docker-сети, к которой подключен Nginx Proxy Manager. Узнать список сетей можно командой:

docker network ls

Например:

NETWORK ID     NAME
xxxxxxxxxxxx   bridge
xxxxxxxxxxxx   proxy-network

В этом случае необходимо указать:

NPM_NETWORK="proxy-network"

Сохраните файл (Ctrl+O, Enter, Ctrl+X).

После этого сделайте его исполняемым:

chmod +x install_vpn.sh

Запустите:

./install_vpn.sh

Во время выполнения скрипт попросит придумать пароль администратора, автоматически создаст необходимые файлы, скачает образ wg-easy и запустит контейнер.


Шаг 4. Проверяем успешный запуск

После установки рекомендуется убедиться, что контейнер действительно работает.

Самый универсальный способ:

docker ps

В списке должен присутствовать контейнер:

wg-easy

со статусом:

Up (healthy)

Если используется Docker Compose V2, можно также выполнить:

docker compose ps

Если используется Docker Compose V1:

docker-compose ps

Где хранятся данные VPN

Все данные WireGuard — конфигурация сервера и список созданных клиентов — находятся в каталоге ~/vpn-docker/data. Именно этот каталог стоит регулярно резервировать: в нём хранятся ключи и профили всех подключённых устройств.

Если понадобится перенести VPN на другой сервер, достаточно скопировать туда весь каталог ~/vpn-docker (включая data/.env и docker-compose.yml) и запустить docker compose up -d (или docker-compose up -d) — все клиенты продолжат работать без переустановки.


Шаг 5. Настраиваем Nginx Proxy Manager

Откройте панель управления Nginx Proxy Manager.

Перейдите:

Hosts → Proxy Hosts → Add Proxy Host

Во вкладке Details заполните поля:

Domain Names

vpn.example.com

Scheme

http

Forward Hostname / IP

wg-easy

Forward Port

51821

Включите опцию:

  • Block Common Exploits.

Перейдите во вкладку SSL.

Выберите:

  • Request a new SSL Certificate.

После этого включите:

  • Force SSL;
  • HTTP/2 Support.

Примите условия Let’s Encrypt и нажмите Save.

Через несколько секунд сертификат будет выпущен автоматически.


Проверяем работу VPN

Откройте браузер и перейдите по адресу:

https://vpn.example.com

Должна открыться страница авторизации wg-easy.

После входа вы сможете:

  • создавать новых пользователей;
  • скачивать готовые конфигурации WireGuard;
  • отображать QR-коды для Android и iPhone;
  • удалять клиентов;
  • отключать пользователей.

Типичные ошибки

Ошибка docker: unknown command: compose

На сервере установлен Docker Compose V1.

Это нормально. Скрипт автоматически использует команду docker-compose.


Ошибка 502 Bad Gateway

Обычно это означает, что Nginx Proxy Manager не может подключиться к контейнеру wg-easy.

Проверьте:

docker ps

Контейнер wg-easy должен присутствовать в списке.

Также убедитесь, что wg-easy и Nginx Proxy Manager подключены к одной Docker-сети.


VPN не подключается

Проверьте:

  • открыт ли UDP-порт 51820;
  • правильно ли настроена DNS-запись;
  • используется ли режим DNS Only в Cloudflare;
  • совпадает ли значение WG_HOST с вашим доменным именем.

Часто задаваемые вопросы

Можно ли использовать Cloudflare?

Да. Однако поддомен WireGuard должен работать в режиме DNS Only. Использование режима Proxied для VPN недопустимо.

Подходит ли инструкция для Ubuntu 22.04?

Да. Она полностью совместима как с Ubuntu 22.04, так и с Ubuntu 24.04.

Можно ли использовать DigitalOcean, Contabo или Hetzner?

Да. Инструкция не зависит от VPS-провайдера и подходит для большинства облачных серверов.

Нужно ли открывать порт 51821?

Нет. Порт панели управления остается доступным только внутри Docker-сети. В Интернет публикуется только HTTPS через Nginx Proxy Manager.

Какие устройства поддерживаются?

WireGuard работает на Windows, Linux, macOS, Android, iOS и большинстве современных маршрутизаторов.

Где хранятся созданные клиенты и что нужно бэкапить?

Список клиентов и ключи WireGuard хранятся в файле wg0.json внутри каталога ~/vpn-docker/data. При переносе сервера или создании резервной копии достаточно сохранить этот каталог целиком — переустанавливать клиентов заново не потребуется.

Почему в скрипте используется тег wg-easy:14, а не latest?

Тег latest указывает на самую свежую версию образа на момент скачивания — со временем разработчики wg-easy могут выпустить новый мажорный релиз с изменённым поведением или несовместимыми настройками, и тогда установка по этой инструкции у нового читателя может пойти не так, как описано в статье.

Чтобы инструкция оставалась воспроизводимой и через год давала тот же результат, что и сегодня, скрипт закрепляет конкретную проверенную версию — wg-easy:14. Если вы хотите получать более новые версии автоматически, замените в начале скрипта строку WG_EASY_VERSION="14" на WG_EASY_VERSION="latest", но учитывайте, что в этом случае поведение контейнера может со временем измениться.


Заключение

Использование WireGuard совместно с wg-easy, Docker и Nginx Proxy Manager позволяет развернуть современный VPN-сервер с удобным веб-интерфейсом и безопасной архитектурой. VPN-клиенты подключаются напрямую по UDP без дополнительных посредников, а административная панель остается скрытой за обратным прокси с автоматическими SSL-сертификатами Let’s Encrypt.

Такой подход сочетает высокую производительность, простоту администрирования и безопасность, что делает его подходящим как для личного использования, так и для небольших команд или организаций.

Добавить комментарий Поделиться…

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *