WireGuard Server + Client Automation

Проект автоматизирует установку и настройку WireGuard-сервера и WireGuard-клиента на Debian/Ubuntu.

Основная идея: один репозиторий с понятными Bash-скриптами для быстрого разворачивания и переустановки WireGuard-стека.

Назначение проекта

  • Быстро развернуть WireGuard-сервер (wg-quick@wg0) с автозапуском через systemd.
  • Включить IP forwarding и NAT для выхода клиентов в интернет через сервер.
  • Установить легкий GUI для управления (wireguard-ui в Docker).
  • Автоматизировать добавление клиента с клиентской машины через SSH на сервер.
  • Поддержать 2 режима маршрутизации клиента:
    • полный туннель (весь трафик через VPN)
    • выборочный туннель (только заданные сети)

Поддерживаемые ОС

  • Debian 11/12
  • Ubuntu 22.04/24.04

Скрипты ориентированы на Debian-family (APT, systemd).

Структура проекта

  • README.md
  • .gitignore
  • lib/common.sh — общие функции
  • bootstrap/install_wg_install.sh — установка короткой команды wg-install
  • templates/wg0.conf.template — шаблон базового wg0.conf
  • server/install_server.sh — установка сервера + GUI
  • server/wg-peerctl.sh — helper для регистрации peer на сервере
  • client/install_client.sh — установка и автонастройка клиента

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

  • Сервер разворачивается нативно на wg-quick + systemd (стабильность после reboot).
  • GUI (wireguard-ui) запускается в Docker, но работает с тем же /etc/wireguard, где лежит серверный конфиг.
  • На сервере ставится wg-syncconf@wg0.path: при изменении /etc/wireguard/wg0.conf (в том числе после Apply в GUI) конфиг автоматически применяется в живой интерфейс wg0.
  • Клиентский скрипт:
    1. генерирует ключи локально,
    2. подключается к серверу по SSH,
    3. вызывает /usr/local/sbin/wg-peerctl add ...,
    4. получает параметры подключения,
    5. пишет локальный /etc/wireguard/wg0.conf,
    6. запускает и включает wg-quick@wg0. Каждый запуск клиентского установщика сначала очищает старые клиентские ключи/конфиг выбранного интерфейса и поднимает клиента заново.

Почему выбран GUI wireguard-ui

  • Легкий для VPS (один контейнер).
  • Понятный веб-интерфейс.
  • Не требует переносить основной WireGuard в Docker: VPN остается в нативном systemd.
  • Проще обслуживание: серверная сеть и NAT остаются под полным контролем Bash-скрипта.
  • GUI не разрабатывается в этом проекте с нуля: используется готовый wireguard-ui, а проект автоматизирует его установку и настройку.

Какие пакеты устанавливаются

Сервер

  • wireguard, wireguard-tools
  • iproute2, iptables
  • curl, ca-certificates, openssl, qrencode
  • docker.io и один из пакетов: docker-compose-plugin или docker-compose (в зависимости от версии ОС/репозиториев)

Клиент

  • wireguard, wireguard-tools
  • iproute2
  • openssh-client, sshpass
  • ca-certificates

Установка сервера

  1. Клонировать/открыть репозиторий.
  2. Запустить:
sudo bash server/install_server.sh

Важно: серверный установщик теперь всегда выполняет полный reset прошлого состояния (/etc/wireguard + wireguard-ui data/db) и поднимает всё заново.

Запуск сервера одной командой (без git clone)

tmp="$(mktemp -d)" && curl -fL "https://git.ruslan.xyz/ruslan/Wireguard_server/archive/main.tar.gz" -o "$tmp/repo.tar.gz" && tar -xzf "$tmp/repo.tar.gz" -C "$tmp" && bash "$tmp/wireguard_server/server/install_server.sh"

Короткая команда wg-install (установить один раз)

Из локального репозитория:

sudo bash bootstrap/install_wg_install.sh

После этого запуск сервера:

sudo wg-install

С аргументами тоже работает:

sudo wg-install --non-interactive --server-public-ip 203.0.113.10 --default-iface eth0

Установка wg-install без git clone:

tmp="$(mktemp -d)" && curl -fL "https://git.ruslan.xyz/ruslan/Wireguard_server/archive/main.tar.gz" -o "$tmp/repo.tar.gz" && tar -xzf "$tmp/repo.tar.gz" -C "$tmp" && sudo bash "$tmp/wireguard_server/bootstrap/install_wg_install.sh"

Скрипт интерактивно спросит недостающие данные:

  • публичный IP (если не определился автоматически)
  • порт WireGuard
  • параметры GUI (логин/пароль)

Если пароль GUI не передан аргументом, скрипт генерирует случайный пароль из 8 символов. В интерактивном режиме можно ответить y и ввести новый пароль отдельным шагом или сразу ввести пароль в том же вопросе.

Non-interactive пример

sudo bash server/install_server.sh \
  --non-interactive \
  --wg-interface wg0 \
  --wg-port 51820 \
  --wg-network 10.66.66.0/24 \
  --wg-address 10.66.66.1/24 \
  --server-public-ip 203.0.113.10 \
  --default-iface eth0 \
  --gui-enable yes \
  --gui-host vpn.example.com \
  --gui-port 5000 \
  --gui-user admin \
  --gui-password 'StrongPass123!'

Установка клиента

Запускать на клиентской машине:

sudo bash client/install_client.sh

Важно: клиентский установщик теперь всегда выполняет reset старой конфигурации для выбранного интерфейса (wg0 по умолчанию): удаляет клиентские ключи/конфиг и создает их заново.

Запуск клиента одной командой (без git clone)

tmp="$(mktemp -d)" && curl -fL "https://git.ruslan.xyz/ruslan/Wireguard_server/archive/main.tar.gz" -o "$tmp/repo.tar.gz" && tar -xzf "$tmp/repo.tar.gz" -C "$tmp" && sudo bash "$tmp/wireguard_server/client/install_client.sh"

Скрипт попросит:

  • адрес сервера
  • SSH-учетные данные
  • режим маршрутизации (full/split)
  • список сетей (если split)

По умолчанию адрес интерфейса клиента пишется как /24 (например 10.66.66.2/24). При необходимости можно изменить маску параметром --client-address-prefix <1-32>. Если за клиентом есть локальная сеть (например 192.168.33.0/24), передайте --advertise-subnets 192.168.33.0/24, чтобы сервер маршрутизировал эту сеть через клиента. Если --advertise-subnets не задан, скрипт автоматически пытается определить LAN-сети клиента и объявить их на сервере. В режиме split, если --allowed-ips не задан, скрипт автоматически использует сеть WG сервера.

Non-interactive пример (SSH-ключ)

sudo bash client/install_client.sh \
  --non-interactive \
  --server-host 203.0.113.10 \
  --server-user root \
  --ssh-auth key \
  --mode full \
  --advertise-subnets 192.168.33.0/24 \
  --client-name laptop-01

Non-interactive пример (SSH-пароль)

sudo bash client/install_client.sh \
  --non-interactive \
  --server-host 203.0.113.10 \
  --server-user root \
  --ssh-auth password \
  --ssh-password 'your_password' \
  --mode split \
  --allowed-ips 10.0.0.0/8,192.168.0.0/16 \
  --client-name laptop-02

Как создаются ключи

  • Сервер: /etc/wireguard/server_private.key и /etc/wireguard/server_public.key.
  • Клиент: /etc/wireguard/wg0_client_private.key, ..._public.key, ..._psk.key.
  • При каждом запуске серверного установщика серверные ключи создаются заново (так как выполняется полный reset).

Как задаются маршруты

Клиентский скрипт поддерживает режимы:

  1. fullAllowedIPs = 0.0.0.0/0,::/0
  2. splitAllowedIPs задается списком сетей

Для full добавляется route-exception до IP WireGuard-сервера, чтобы не потерять SSH/доступ при переключении default route.

Как включается автозапуск

Используется systemd:

  • Сервер: wg-quick@wg0.service
  • Клиент: wg-quick@wg0.service

Скрипты выполняют systemctl enable --now ....

Как открыть GUI

После установки сервера GUI доступен по адресу:

http://<GUI_HOST>:<GUI_PORT>

Пример:

http://203.0.113.10:5000

Логин/пароль задаются во время установки сервера.

Как получить QR для iPhone в GUI

  1. Откройте GUI по ссылке из итоговой сводки установки.
  2. Перейдите в раздел клиентов (Clients).
  3. Создайте клиента (New Client) или выберите существующего.
  4. Нажмите кнопку показа QR (или Show QR) у клиента.
  5. На iPhone: WireGuard → Add TunnelCreate from QR code и отсканируйте код.

В установщике уже задаются дефолты GUI для корректной генерации клиентских конфигов: endpoint, DNS, порт и путь к wg0.conf.

Взаимодействие клиента с сервером

  • Клиент генерирует локальные ключи.
  • Клиент по SSH вызывает на сервере wg-peerctl add.
  • Серверный helper:
    • выделяет IP клиенту внутри VPN-сети,
    • добавляет peer идемпотентно,
    • применяет конфиг,
    • возвращает параметры подключения.
  • Клиент собирает локальный wg0.conf, запускает интерфейс и автозапуск.

Примеры использования

Проверка статуса на сервере

sudo systemctl status wg-quick@wg0
sudo wg show

Ручное добавление peer через helper

sudo /usr/local/sbin/wg-peerctl add \
  --client-name test-client \
  --client-public-key '<client_pub_key>'

Проверка клиента

sudo wg show
ip route
curl -4 ifconfig.me

Безопасность и ограничения

  • Приватные ключи не пишутся в лог.
  • Конфиги и ключи сохраняются с ограниченными правами (600).
  • Перед перезаписью конфигов делаются backup-файлы.
  • SSH по паролю поддержан, но менее безопасен, чем SSH-ключи.
  • В non-interactive режиме пароль в командной строке может попасть в shell history — лучше использовать SSH-ключ.
  • Скрипты предполагают root-доступ на сервере для изменения /etc/wireguard и systemd.
  • GUI запускается без TLS по умолчанию (HTTP). Для production рекомендуется ставить reverse proxy (Nginx/Caddy) с HTTPS и ограничением доступа.

Диагностика и устранение проблем

  1. WireGuard не поднялся:
sudo systemctl status wg-quick@wg0
sudo journalctl -u wg-quick@wg0 -n 100 --no-pager
sudo wg show
  1. Не работает интернет у клиента:
ip route
sudo wg show

Проверьте AllowedIPs, ip_forward, NAT и внешний интерфейс сервера.

  1. Клиент не добавляется по SSH:
  • Проверьте доступность SSH (ssh user@server).
  • Проверьте, что на сервере установлен helper:
ls -l /usr/local/sbin/wg-peerctl
  1. GUI недоступен:
sudo docker ps
sudo docker logs wireguard-ui --tail=100
sudo ss -tulpn | grep 5000

Если при запуске встречается ошибка KeyError: 'ContainerConfig' (обычно на legacy docker-compose v1), перезапустите установщик из актуальной версии репозитория: в нем добавлена автоматическая очистка старого контейнера wireguard-ui перед запуском.

Для уже сломанного состояния можно вручную очистить старые контейнеры и запустить установщик снова:

docker ps -aq --filter 'label=com.docker.compose.service=wireguard-ui' | xargs -r docker rm -f
docker ps -a --format '{{.Names}}' | grep -E '(^|[_-])wireguard-ui($|[_-])' | xargs -r docker rm -f

Если клиенты из GUI создаются в неправильной подсети, просто перезапустите серверный установщик: теперь он автоматически очищает БД GUI и поднимает всё с нуля.

Важные пути

  • Серверный конфиг: /etc/wireguard/wg0.conf
  • Метаданные сервера: /etc/wireguard/wg-meta.env
  • Клиентский конфиг: /etc/wireguard/wg0.conf
  • Server install log: /var/log/wireguard-server-install.log
  • Client install log: /var/log/wireguard-client-install.log
  • Peer helper log: /var/log/wireguard-peerctl.log

Справка по ключам

bash server/install_server.sh --help
bash client/install_client.sh --help
bash bootstrap/install_wg_install.sh
Description
No description provided
Readme 368 KiB
Languages
Shell 67.5%
Python 23.8%
HTML 6.3%
CSS 2.4%