From 0b763e5738e297a9335947a09c5a971ee23403f4 Mon Sep 17 00:00:00 2001 From: dev Date: Sun, 13 Sep 2026 00:34:43 +0300 Subject: [PATCH] feat(cloudflared): timeout+fallback for WG handshake (WG_HANDSHAKE_TIMEOUT) so tunnel still starts when VPN peer is down --- .env.example | 5 ++++- README.md | 2 +- docker-compose.yml | 1 + start-cloudflared.sh | 18 ++++++++++++++---- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index efdd419..6205191 100644 --- a/.env.example +++ b/.env.example @@ -23,4 +23,7 @@ AI_REQUEST_TIMEOUT_MS=120000 # (токен вида "eyJ..." создаётся в Cloudflare Zero Trust -> Networks -> Tunnels). CLOUDFLARE_TUNNEL_TOKEN= # Внутренний адрес приложения, на который указывает Quick Tunnel. -CLOUDFLARE_TUNNEL_URL=http://app:3003 \ No newline at end of file +CLOUDFLARE_TUNNEL_URL=http://app:3003 +# Максимальное ожидание WireGuard handshake перед fallback на прямой запуск +# туннеля без VPN (сек). Если VPN-провайдер не отвечает — сайт всё равно поднимется. +WG_HANDSHAKE_TIMEOUT=60 \ No newline at end of file diff --git a/README.md b/README.md index 8599d17..4310ea0 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ docker compose logs cloudflared | grep trycloud `cloudflared` собирается из `Dockerfile.cloudflared`, в который добавлена поддержка **опционального WireGuard** — полезно, когда Cloudflare не работает с прямого IP хоста, и исход туннеля нужно пустить через VPN. - Положите рабочий конфиг провайдера в `wg/wg0.conf` (папка `wg/` монтируется в контейнер как `/etc/wireguard`). Пример-заглушка уже лежит в `wg/wg0.conf` — замените значения на свои. -- Если `wg/wg0.conf` есть → контейнер **сначала поднимает WireGuard, дожидается handshake и только потом запускает туннель** (весь эгресс Cloudflare идёт через VPN). +- Если `wg/wg0.conf` есть → контейнер **сначала поднимает WireGuard и ждёт handshake** (весь эгресс Cloudflare идёт через VPN). Если handshake не установился за `WG_HANDSHAKE_TIMEOUT` сек (по умолчанию 60) — **fallback: туннель стартует напрямую без VPN**, а в логах пишется предупреждение (сайт не лежит из-за недоступного VPN-провайдера). - Если `wg0.conf` нет или папка пустая → VPN не включается, туннель стартует сразу, как в базовой схеме. Проверка: diff --git a/docker-compose.yml b/docker-compose.yml index 32deeff..e963b35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -85,6 +85,7 @@ services: environment: TZ: Europe/Moscow CLOUDFLARE_TUNNEL_URL: ${CLOUDFLARE_TUNNEL_URL:-http://app:3003} + WG_HANDSHAKE_TIMEOUT: ${WG_HANDSHAKE_TIMEOUT:-60} depends_on: - app diff --git a/start-cloudflared.sh b/start-cloudflared.sh index 7d04335..be97c3e 100755 --- a/start-cloudflared.sh +++ b/start-cloudflared.sh @@ -15,12 +15,22 @@ if [ -f /etc/wireguard/wg0.conf ]; then # wg-quick/resolvconf перезаписывает resolv.conf (убирает docker-DNS 127.0.0.11), # из-за чего внутреннее имя app не резолвится. Восстанавливаем прежний конфиг. cat /tmp/resolv.conf.default > /etc/resolv.conf - echo "Waiting for WireGuard handshake..." + echo "Waiting for WireGuard handshake (timeout: ${WG_HANDSHAKE_TIMEOUT:-60}s)..." # Формат `wg show wg0 latest-handshakes`: " "; 0 = handshake ещё не было. - until wg show wg0 latest-handshakes | awk '{ if ($2 != 0) found=1 } END { exit !found }'; do - sleep 2 + waited=0; handshake=0 + while [ "$handshake" -eq 0 ] && [ "$waited" -lt "${WG_HANDSHAKE_TIMEOUT:-60}" ]; do + if wg show wg0 latest-handshakes | awk '{ if ($2 != 0) found=1 } END { exit !found }'; then + handshake=1 + else + sleep 2 + waited=$((waited + 2)) + fi done - echo "WireGuard is up, starting Cloudflare tunnel through VPN..." + if [ "$handshake" -eq 1 ]; then + echo "WireGuard is up, starting Cloudflare tunnel through VPN..." + else + echo "WARNING: WireGuard handshake not established within ${WG_HANDSHAKE_TIMEOUT:-60}s; starting Cloudflare tunnel directly (no VPN egress)." + fi else echo "No WireGuard config, starting Cloudflare tunnel directly..." fi