From 1c4a40f0c1d9ca5cbd79a6eaafcdbe7ab76f428e Mon Sep 17 00:00:00 2001 From: Deploy Bot Date: Thu, 30 Jul 2026 01:05:13 +0100 Subject: [PATCH] feat: add deployment hardening from production experience MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add IP forwarding setup (sysctl) to install.sh — container can't write /proc/sys, must be done on host - Add host-level WireGuard detection and auto-stop in install.sh - Update key exchange instructions: 2-step process (server first, then client, then restart server with client key) - Add deployment nuances section to README (ip_forward, wg0 cleanup, compose version warning, key exchange, network_mode, iptables order) - Add production deployment notes to .env.example - Remove obsolete compose version warnings noted during deployment --- .env.example | 16 +++++++++++- README.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ install.sh | 65 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 145 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index b282e3f..9318e59 100644 --- a/.env.example +++ b/.env.example @@ -43,4 +43,18 @@ VPS_WG_PORT=51820 CLIENT_WG_IP=10.0.0.2 # Интервал Keepalive в секундах (оптимизировано для Starlink, по умолчанию 21) -PERSISTENT_KEEPALIVE=21 \ No newline at end of file +PERSISTENT_KEEPALIVE=21 + +# ── Важные замечания по развёртыванию ────────────────────────────────────── +# 1. На VPS: включите IP-форвардинг на хосте (контейнер не может /proc/sys): +# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf && sysctl -p +# 2. Ключи генерируются автоматически при первом запуске. +# Сервер: /etc/wireguard/server_private.key, server_public.key +# Клиент: /etc/wireguard/client_private.key, client_public.key +# 3. После первого запуска сервера скопируйте SERVER_PUBLIC_KEY в .env клиента. +# 4. После первого запуска клиента скопируйте CLIENT_PUBLIC_KEY в .env сервера. +# 5. Перезапустите контейнеры после обновления ключей: +# docker compose -f docker-compose.server.yml restart (на VPS) +# docker compose -f docker-compose.client.yml restart (на RPi) +# 6. Контейнер использует network_mode: host — порты пробрасываются +# через iptables DNAT, а не через Docker port mapping. \ No newline at end of file diff --git a/README.md b/README.md index f937e07..1bc8ad4 100644 --- a/README.md +++ b/README.md @@ -414,6 +414,76 @@ wireguard-vps-tunnel/ └── README.md # Документация ``` +## Нюансы развёртывания (выявлены на практике) + +### 1. IP-форвардинг на хосте (обязательно) + +Контейнер не может записать в `/proc/sys/net/ipv4/ip_forward` (read-only в Docker). Включите на хосте: + +```bash +# Временно +echo 1 > /proc/sys/net/ipv4/ip_forward +echo 1 > /proc/sys/net/ipv6/conf/all/forwarding + +# Постоянно +echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf +echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.conf +sysctl -p +``` + +Без этого DNAT-трафик не будет перенаправляться. + +### 2. Обмен ключами: двухэтапный запуск + +Ключи генерируются **внутри контейнера** при первом запуске. Поэтому: + +1. Запустите сервер → он сгенерирует ключи и выведет `SERVER_PUBLIC_KEY=...` +2. Впишите `SERVER_PUBLIC_KEY` в `.env` на клиенте +3. Запустите клиент → он выведет `CLIENT_PUBLIC_KEY=...` +4. Впишите `CLIENT_PUBLIC_KEY` в `.env` на сервере +5. Перезапустите сервер: `docker compose -f docker-compose.server.yml restart` + +Конфигурация `wg0.conf` пересоздаётся при каждом перезапуске, поэтому обновление ключей не требует ручного редактирования. + +### 3. Удаление старого интерфейса wg0 + +При перезапуске контейнера интерфейс `wg0` может остаться от предыдущего запуска. Entrypoint автоматически удаляет его перед запуском `wg-quick up`. Если на хосте остался host-level WireGuard — остановите его: + +```bash +systemctl stop wg-quick@wg0 +systemctl disable wg-quick@wg0 +ip link del wg0 2>/dev/null +rm -f /etc/wireguard/wg0.conf +``` + +### 4. Docker Compose `version` устарел + +Поле `version: "3.8"` в docker-compose вызывает предупреждение: +`the attribute 'version' is obsolete`. Оно удалено из файлов проекта. +Если вы видите это предупреждение — просто удалите строку `version:` из compose-файла. + +### 5. Multi-arch сборка требует Buildx + +Стандартный `docker build` не поддерживает `platforms: linux/amd64,linux/arm64`. +Для multi-arch сборки через CI/CD используется Docker Buildx с QEMU. +Для локальной сборки на текущей архитектуре достаточно убрать `platforms:` из compose-файла. + +### 6. network_mode: host и порты + +Контейнеры используют `network_mode: host`. Секция `ports:` в compose-файле игнорируется (Docker выведет предупреждение). Все порты доступны напрямую через iptables DNAT. + +### 7. Конфликт с Docker iptables + +Правила DNAT вставляются через `iptables -I FORWARD 1` — **перед** цепочкой DOCKER-USER. +Это гарантирует, что WireGuard-трафик не блокируется Docker. Не меняйте приоритет +без необходимости. + +### 8. Парольная аутентификация SSH + +Скрипт **НЕ отключает** `PasswordAuthentication` в sshd. Если вы хотите отключить, +сделайте это вручную и обязательно добавьте SSH-ключ в `authorized_keys` **до** +отключения пароля, иначе потеряете доступ. + ## Поддерживаемые ОС - Любой Linux с Docker 20.10+ diff --git a/install.sh b/install.sh index 60a9a08..d252b7f 100644 --- a/install.sh +++ b/install.sh @@ -91,6 +91,50 @@ install_docker() { fi } +# ── Включение IP-форвардинга (обязательно для VPS) ────────────────────────── +enable_ip_forwarding() { + header "Настройка IP-форвардинга" + + # Включить временно + echo 1 > /proc/sys/net/ipv4/ip_forward 2>/dev/null || true + echo 1 > /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true + + # Включить постоянно + if ! grep -q "net.ipv4.ip_forward" /etc/sysctl.conf 2>/dev/null; then + echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf + else + sed -i 's/.*net.ipv4.ip_forward.*/net.ipv4.ip_forward = 1/' /etc/sysctl.conf + fi + + if ! grep -q "net.ipv6.conf.all.forwarding" /etc/sysctl.conf 2>/dev/null; then + echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf + else + sed -i 's/.*net.ipv6.conf.all.forwarding.*/net.ipv6.conf.all.forwarding = 1/' /etc/sysctl.conf + fi + + sysctl -p 2>/dev/null || true + + success "IP-форвардинг включён" +} + +# ── Остановка host-level WireGuard ──────────────────────────────────────── +stop_host_wireguard() { + if systemctl is-active --quiet wg-quick@wg0 2>/dev/null; then + warn "Обнаружен host-level WireGuard (wg-quick@wg0). Останавливаем..." + systemctl stop wg-quick@wg0 2>/dev/null || true + systemctl disable wg-quick@wg0 2>/dev/null || true + ip link del wg0 2>/dev/null || true + success "Host-level WireGuard остановлен и отключён" + fi + + # Остановить watchdog если есть + if systemctl is-active --quiet wg-watchdog 2>/dev/null; then + systemctl stop wg-watchdog 2>/dev/null || true + systemctl disable wg-watchdog 2>/dev/null || true + success "wg-watchdog остановлен" + fi +} + # ── Генерация ключей WireGuard ───────────────────────────────────────────── generate_keys() { header "Генерация ключей WireGuard" @@ -335,6 +379,8 @@ print_summary() { if [[ "$MODE" == "vps" ]]; then echo -e "${BOLD}Проброс портов:${NC} ${PORTS} → ${CLIENT_WG_IP}" + echo "" + echo -e "${GREEN}${BOLD}✅ IP-форвардинг включён (net.ipv4.ip_forward=1)${NC}" fi echo "" @@ -355,11 +401,14 @@ print_summary() { if [[ "$MODE" == "vps" ]]; then echo "" - echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Скопируйте публичный ключ сервера на клиент:${NC}" - echo -e " ${BOLD}cat ${CONFIG_DIR}/server_public.key${NC}" - echo "" - echo -e "${YELLOW}Затем на клиенте (RPi):${NC}" - echo -e " ${BOLD}sudo ./install.sh --client --vps-ip ${VPS_PUBLIC_IP}${NC}" + echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Двухэтапный обмен ключами:${NC}" + echo -e " 1. Запишите публичный ключ сервера:" + echo -e " ${BOLD}cat ${CONFIG_DIR}/server_public.key${NC}" + echo -e " 2. Передайте его на клиент (в .env как SERVER_PUBLIC_KEY)" + echo -e " 3. После запуска клиента, получите CLIENT_PUBLIC_KEY:" + echo -e " ${BOLD}cat ${CONFIG_DIR}/client_public.key${NC} (на клиенте)" + echo -e " 4. Впишите CLIENT_PUBLIC_KEY в .env на VPS и перезапустите:" + echo -e " ${BOLD}docker compose -f docker-compose.server.yml restart${NC}" else echo "" echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Скопируйте публичный ключ клиента на VPS:${NC}" @@ -367,6 +416,8 @@ print_summary() { echo "" echo -e "${YELLOW}И добавьте в .env на VPS:${NC}" echo -e " ${BOLD}CLIENT_PUBLIC_KEY=<ключ>${NC}" + echo -e "${YELLOW}Затем перезапустите сервер:${NC}" + echo -e " ${BOLD}docker compose -f docker-compose.server.yml restart${NC}" fi echo "" @@ -403,8 +454,12 @@ main() { fi install_docker + stop_host_wireguard generate_keys create_env_file + if [[ "$MODE" == "vps" ]]; then + enable_ip_forwarding + fi start_docker print_summary }