- Dockerfile с multi-stage сборкой для linux/amd64 и linux/arm64 - Gitea Actions CI/CD для автоматической сборки и пуша в registry - docker-compose с поддержкой multi-arch образов - install.sh с автоопределением архитектуры и выбором: pull vs build - uninstall.sh обновлён для Docker-деинсталляции - README.md обновлён: multi-arch, CI/CD, Gitea registry
19 KiB
WireGuard VPS Tunnel — Docker Edition
Автоматическая настройка WireGuard-туннеля в Docker-контейнерах между VPS (с публичным IP) и домашним сервером за NAT (Raspberry Pi, Orange Pi, Starlink и т.д.).
Поддерживаемые архитектуры: linux/amd64 (Intel/AMD VPS) и linux/arm64 (Raspberry Pi 4/5, Orange Pi).
Архитектура
Интернет
│
┌────────┴────────┐
│ VPS (сервер) │
│ Публичный IP │
│ например: │
│ 2.59.219.234 │
│ │
│ ┌──────────────┐ │
│ │ Docker │ │
│ │ wireguard- │ │
│ │ server │ │
│ │ │ │
│ │ wg0:10.0.0.1 │ │
│ │ :51820 (UDP) │ │
│ │ │ │
│ │ iptables │ │
│ │ DNAT: │ │
│ │ :80→10.0.0.2 │ │
│ │ :443→10.0.0.2│ │
│ └──────┬───────┘ │
└────────┼────────┘
│
╔══════════════╧══════════════╗
║ WireGuard UDP :51820 ║
║ (PersistentKeepalive=21) ║
╚══════════════╤══════════════╝
│
┌────────┴────────┐
│ Домашний сервер │
│ (за NAT/CGNAT) │
│ Raspberry Pi │
│ Starlink │
│ │
│ ┌──────────────┐│
│ │ Docker ││
│ │ wireguard- ││
│ │ client ││
│ │ ││
│ │ wg0:10.0.0.2 ││
│ │ ││
│ │ Watchdog ││
│ │ (встроенный) ││
│ └──────┬───────┘│
└────────┼────────┘
│
┌────────┴────────┐
│ Nginx Proxy │
│ Manager :80,443│
│ → backend │
└─────────────────┘
Как это работает:
- VPS принимает входящие соединения на порты 80 и 443
- iptables (внутри Docker-контейнера) перенаправляет трафик через WireGuard-туннель на домашний сервер (10.0.0.2)
- Домашний сервер (RPi) инициирует соединение с VPS — работает через любой NAT
PersistentKeepalive = 21секунда поддерживает туннель активным даже при отсутствии трафика- Встроенный Watchdog на клиенте мониторит состояние туннеля и перезапускает при обрыве
- Всё изолировано в Docker-контейнерах — не затрагивает хост-систему
Быстрый старт (1 команда)
На VPS:
git clone http://192.168.2.28:3000/OpenDoor/wireguard-vps-tunnel.git
cd wireguard-vps-tunnel
sudo ./install.sh --vps --ports 80,443
На домашнем сервере (Raspberry Pi / Orange Pi):
git clone http://192.168.2.28:3000/OpenDoor/wireguard-vps-tunnel.git
cd wireguard-vps-tunnel
sudo ./install.sh --client --vps-ip 2.59.219.234
Примечание: Docker-образы автоматически выбираются под архитектуру вашего устройства (amd64 для VPS, arm64 для Raspberry Pi). Сборка не требуется — образы загружаются из Gitea Container Registry. Для локальной сборки добавьте флаг
--build.
Ручная установка через Docker Compose
1. Клонирование репозитория
git clone http://192.168.2.28:3000/OpenDoor/wireguard-vps-tunnel.git
cd wireguard-vps-tunnel
2. Генерация ключей
# Установите wireguard-tools если ещё нет
sudo apt-get install -y wireguard-tools
# Сгенерируйте ключи
mkdir -p config
wg genkey | tee config/server_private.key | wg pubkey > config/server_public.key
wg genkey | tee config/client_private.key | wg pubkey > config/client_public.key
chmod 600 config/*.key
3. Настройка VPS (сервер)
Создайте .env файл:
CLIENT_PUBLIC_KEY=<ключ из config/client_public.key>
SERVER_PUBLIC_IP=2.59.219.234
FORWARD_PORTS=80,443
Запустите:
sudo docker compose -f docker-compose.server.yml up -d
4. Настройка клиента (домашний сервер)
Создайте .env файл:
VPS_PUBLIC_IP=2.59.219.234
SERVER_PUBLIC_KEY=<ключ из config/server_public.key>
PERSISTENT_KEEPALIVE=21
Запустите:
sudo docker compose -f docker-compose.client.yml up -d
5. Проверка
# На VPS
docker exec wireguard-server wg show
docker exec wireguard-server ping 10.0.0.2
# На домашнем сервере
docker exec wireguard-client wg show
docker exec wireguard-client ping 10.0.0.1
Обмен ключами (пошагово)
Шаг 1: На VPS — генерация ключей и запуск
sudo ./install.sh --vps --ports 80,443
Скрипт выведет публичный ключ сервера. Скопируйте его.
Шаг 2: На клиенте — запуск с ключом сервера
# Отредактируйте .env, вставив SERVER_PUBLIC_KEY из шага 1
sudo ./install.sh --client --vps-ip 2.59.219.234
Скрипт выведет публичный ключ клиента. Скопируйте его.
Шаг 3: На VPS — добавление ключа клиента
# Отредактируйте .env, вставив CLIENT_PUBLIC_KEY из шага 2
# Перезапустите контейнер:
sudo docker compose -f docker-compose.server.yml up -d --force-recreate
Переменные окружения
Сервер (VPS)
| Переменная | По умолчанию | Описание |
|---|---|---|
CLIENT_PUBLIC_KEY |
обязательно | Публичный ключ клиента |
SERVER_WG_IP |
10.0.0.1 |
WireGuard IP сервера |
SERVER_WG_PORT |
51820 |
Порт WireGuard |
FORWARD_PORTS |
80,443 |
Порты для проброса (через запятую) |
SERVER_PUBLIC_IP |
авто | Публичный IP VPS |
SERVER_PUBLIC_IFACE |
авто | Внешний сетевой интерфейс |
Клиент (домашний сервер)
| Переменная | По умолчанию | Описание |
|---|---|---|
VPS_PUBLIC_IP |
обязательно | Публичный IP VPS |
SERVER_PUBLIC_KEY |
обязательно | Публичный ключ сервера |
CLIENT_WG_IP |
10.0.0.2 |
WireGuard IP клиента |
VPS_WG_PORT |
51820 |
Порт WireGuard на VPS |
PERSISTENT_KEEPALIVE |
21 |
Интервал keepalive (сек) |
Опции командной строки (install.sh)
| Опция | Описание | По умолчанию |
|---|---|---|
--vps |
Режим VPS (сервер) | — |
--client |
Режим клиента (домашний сервер) | — |
--vps-ip IP |
Публичный IP VPS | автоопределение |
--ports PORT,... |
Порты для проброса (VPS) | 80,443 |
--wg-port PORT |
Порт WireGuard | 51820 |
--keepalive SEC |
PersistentKeepalive (сек) | 21 |
--build |
Локальная сборка образа (вместо загрузки из registry) | pull |
Watchdog (мониторинг туннеля)
Watchdog встроен в клиентский контейнер и выполняет:
- Проверяет, что интерфейс
wg0поднят - Проверяет доступность VPS через туннель (
ping 10.0.0.1) - Проверяет доступность VPS через интернет (
ping VPS_IP) - Если туннель не работает, но VPS доступен — перезапускает WireGuard
- Использует экспоненциальную отсрочку при повторных сбоях:
- 10с → 20с → 40с → 80с → 120с (максимум)
- После 3 успешных проверок подряд сбрасывает отсрочку
Просмотр логов:
docker compose -f docker-compose.client.yml logs -f
Starlink: особенности
Starlink использует CGNAT (Carrier-Grade NAT), что означает:
- Нет публичного IPv4 — домашний сервер недоступен из интернета напрямую
- Высокая задержка — 25-60 мс (спутниковая связь)
- Кратковременные обрывы — при переключении между спутниками
- UDP работает лучше TCP — меньше проблем с TCP congestion control
Рекомендации для Starlink:
PERSISTENT_KEEPALIVE=21— оптимальное значение (каждые 21 сек отправляет keepalive-пакет)- Watchdog обязателен — автоматически восстанавливает туннель после обрывов
- Не используйте SSH reverse tunnel — TCP-over-TCP на спутниковом канале работает плохо
- MTU = 1420 (стандартный для WireGuard) — не меняйте без необходимости
Multi-Arch (Поддержка архитектур)
Docker-образы собираются автоматически для двух архитектур:
| Архитектура | Устройства | Образ |
|---|---|---|
linux/amd64 |
VPS (Intel/AMD), десктопы | git.softuniq.eu/opendoor/wireguard-vps-tunnel-server:latest |
linux/arm64 |
Raspberry Pi 4/5, Orange Pi, Mac M1/M2 | git.softuniq.eu/opendoor/wireguard-vps-tunnel-client:latest |
Установщик автоматически определяет архитектуру хоста и загружает соответствующий образ. Принудительная локальная сборка:
# Собрать образ локально (для текущей архитектуры)
sudo ./install.sh --vps --build
# Или через docker compose
docker compose -f docker-compose.server.yml build
docker compose -f docker-compose.client.yml build
CI/CD
При пуше в ветку main или создании тега v* Gitea Actions автоматически собирает и пушит multi-arch образы:
git.softuniq.eu/opendoor/wireguard-vps-tunnel-server:latestgit.softuniq.eu/opendoor/wireguard-vps-tunnel-client:latest
Сборка использует QEMU для кросс-компиляции и Docker Buildx для multi-arch образов.
Сравнение: Docker vs Host-Based
| Критерий | Docker | Host-Based |
|---|---|---|
| Изоляция | Полная (контейнер) | Нет (хост-система) |
| Зависимости | Только Docker | wireguard-tools, iptables, systemd |
| Multi-arch | ✅ amd64 + arm64 | Ручная установка под каждую ОС |
| Обновление | docker compose pull && up -d |
Ручная замена скриптов |
| Откат | docker compose down && up (предыдущий образ) |
Ручной откат конфигов |
| Переносимость | Любой Linux с Docker | Debian/Ubuntu/Armbian |
| Безопасность | Минимальная поверхность атаки (Alpine) | Полный доступ к хосту |
| Watchdog | Встроен в контейнер | Отдельный systemd-сервис |
| Логи | docker logs |
journald + файлы |
| Ресурсы | ~15 МБ образ, ~20 МБ RAM | ~5 МБ RAM (без контейнера) |
Сравнение: WireGuard vs SSH Reverse Tunnel
| Критерий | WireGuard | SSH Reverse Tunnel |
|---|---|---|
| Протокол | UDP (kernel) | TCP (userspace) |
| Производительность | ~1 Gbps | ~100 Mbps |
| Задержка | Минимальная | TCP-over-TCP проблема |
| Starlink | ✅ Оптимально (UDP) | ❌ Плохо (TCP через TCP) |
| Переподключение | Мгновенное | Заметная задержка |
| NAT traversal | PersistentKeepalive | Autossh + мониторинг |
| Проброс портов | iptables DNAT | ssh -R |
| Отказоустойчивость | Встроенная | Требует autossh |
| Нагрузка на CPU | Минимальная (kernel) | Заметная (шифрование в userspace) |
Устранение неполадок
Контейнер не запускается
# Проверить логи
docker compose -f docker-compose.server.yml logs
docker compose -f docker-compose.client.yml logs
# Проверить статус
docker compose -f docker-compose.server.yml ps
docker compose -f docker-compose.client.yml ps
Туннель не поднимается
# Проверить статус WireGuard внутри контейнера
docker exec wireguard-server wg show
docker exec wireguard-client wg show
# Проверить, что порт открыт на VPS
nc -zvu <VPS_IP> 51820
Порты не пробрасываются
# Проверить правила iptables внутри контейнера
docker exec wireguard-server iptables -t nat -L PREROUTING -n
docker exec wireguard-server iptables -L FORWARD -n
# Проверить IP-форвардинг
docker exec wireguard-server sysctl net.ipv4.ip_forward
Пинг не проходит
# Проверить что интерфейс поднят
docker exec wireguard-server ip link show wg0
docker exec wireguard-client ip link show wg0
# Проверить IP-адреса
docker exec wireguard-server ip addr show wg0
docker exec wireguard-client ip addr show wg0
Полный сброс и переустановка
# Деинсталляция
sudo ./uninstall.sh --remove-images --remove-config
# Переустановка
sudo ./install.sh --vps --ports 80,443
Деинсталляция
sudo ./uninstall.sh
Опции:
--remove-images— также удалить Docker-образы--remove-config— также удалить директориюconfig/с ключами и.env
Деинсталлятор:
- Останавливает и удаляет Docker-контейнеры
- Опционально удаляет образы и конфигурацию
- НЕ трогает SSH-сервер, Docker и другие сервисы
- НЕ изменяет
sshd_config(PasswordAuthentication остаётся без изменений)
Безопасность
- Ключи: приватные ключи хранятся с правами
600(только root) - Изоляция: контейнеры работают в изолированном окружении (Alpine Linux)
- Фаервол: iptables правила применяются атомарно через
PostUp/PostDown - SSH: парольная аутентификация НЕ отключается — скрипт не трогает sshd_config
- Порты: открываются только указанные порты (по умолчанию 80 и 443)
- WireGuard: использует современную криптографию (Curve25519, ChaCha20, BLAKE2s)
- Docker:
--cap-add=NET_ADMIN --cap-add=SYS_MODULE— минимально необходимые capabilities - Read-only:
/lib/modulesмонтируется в режимеro(только чтение)
Структура проекта
wireguard-vps-tunnel/
├── server/
│ ├── Dockerfile # Docker-образ сервера (Alpine 3.20)
│ ├── entrypoint.sh # Точка входа: генерация конфига, запуск WG
│ └── healthcheck.sh # Healthcheck: wg show wg0
├── client/
│ ├── Dockerfile # Docker-образ клиента (Alpine 3.20)
│ ├── entrypoint.sh # Точка входа: генерация конфига, запуск WG + watchdog
│ ├── watchdog.sh # Watchdog: мониторинг и автовосстановление туннеля
│ └── healthcheck.sh # Healthcheck: ping VPS WG IP
├── docker-compose.server.yml # Docker Compose для VPS
├── docker-compose.client.yml # Docker Compose для клиента
├── .env.example # Шаблон переменных окружения
├── install.sh # 1-Click установщик (Docker)
├── uninstall.sh # Деинсталлятор (Docker)
├── .dockerignore # Исключения для сборочного контекста
├── .gitea/
│ └── workflows/
│ └── build.yml # CI/CD: сборка Docker-образов
└── README.md # Документация
Поддерживаемые ОС
- Любой Linux с Docker 20.10+
- Debian 11+ (Bullseye, Bookworm)
- Ubuntu 20.04+ (Focal, Jammy, Noble)
- Armbian (Orange Pi, Banana Pi, etc.)
- Raspberry Pi OS (Raspbian)
Лицензия
MIT