feat: cloudflared container with optional WireGuard egress
- Dockerfile.cloudflared builds cloudflared (official static binary) on Alpine with wireguard-tools
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
*.key
|
*.key
|
||||||
*.crt
|
*.crt
|
||||||
certs/
|
certs/
|
||||||
|
wg/
|
||||||
|
|
||||||
# --- Run-time data / uploads ---
|
# --- Run-time data / uploads ---
|
||||||
uploads/
|
uploads/
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Сборка контейнера cloudflared с опциональным WireGuard.
|
||||||
|
# Официальный образ cloudflare/cloudflared — distroless (без оболочки/apk), поэтому:
|
||||||
|
# 1) берём из него статичный бинарник cloudflared;
|
||||||
|
# 2) саму сборку делаем на Alpine, где ставим wireguard-tools.
|
||||||
|
# Если в wg/wg0.conf нет конфига — VPN не поднимается, туннель запускается как обычно.
|
||||||
|
FROM cloudflare/cloudflared:latest AS cf
|
||||||
|
|
||||||
|
FROM alpine:3.20
|
||||||
|
RUN apk add --no-cache wireguard-tools iproute2
|
||||||
|
COPY --from=cf /usr/local/bin/cloudflared /usr/bin/cloudflared
|
||||||
|
COPY start-cloudflared.sh /start-cloudflared.sh
|
||||||
|
ENTRYPOINT ["/bin/sh", "/start-cloudflared.sh"]
|
||||||
@@ -182,7 +182,26 @@ docker exec whatido-tailscale-1 tailscale funnel status
|
|||||||
docker compose logs cloudflared | grep trycloud
|
docker compose logs cloudflared | grep trycloud
|
||||||
```
|
```
|
||||||
|
|
||||||
Адрес меняется при каждом перезапуске контейнера `cloudflared`. Для постоянного адреса используйте именованный туннель (замените `command` сервиса `cloudflared` в `docker-compose.yml` на `["tunnel", "run", "--token", "${CLOUDFLARE_TUNNEL_TOKEN}"]`, токен — из Cloudflare Zero Trust **Networks → Tunnels**) или схему через Tailscale выше.
|
### Опциональный WireGuard для эгресса Cloudflare
|
||||||
|
|
||||||
|
`cloudflared` собирается из `Dockerfile.cloudflared`, в который добавлена поддержка **опционального WireGuard** — полезно, когда Cloudflare не работает с прямого IP хоста, и исход туннеля нужно пустить через VPN.
|
||||||
|
|
||||||
|
- Положите рабочий конфиг провайдера в `wg/wg0.conf` (папка `wg/` монтируется в контейнер как `/etc/wireguard`). Пример-заглушка уже лежит в `wg/wg0.conf` — замените значения на свои.
|
||||||
|
- Если `wg/wg0.conf` есть → контейнер **сначала поднимает WireGuard, дожидается handshake и только потом запускает туннель** (весь эгресс Cloudflare идёт через VPN).
|
||||||
|
- Если `wg0.conf` нет или папка пустая → VPN не включается, туннель стартует сразу, как в базовой схеме.
|
||||||
|
|
||||||
|
Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f cloudflared # в идеале сначала "WireGuard is up", затем URL
|
||||||
|
docker compose exec cloudflared wg show # есть handshake — VPN поднят
|
||||||
|
```
|
||||||
|
|
||||||
|
Примечания:
|
||||||
|
- `wg/wg0.conf` содержит приватный ключ, поэтому папка `wg/` добавлена в `.gitignore` (в репозиторий не попадёт).
|
||||||
|
- При полном туннеле (`AllowedIPs = 0.0.0.0/0`) существующий маршрут docker-сети сохраняется, поэтому `cloudflared` по-прежнему достаёт `app` локально, а наружу уходит через wg0. Если вдруг `app` станет недоступен из-за VPN — переключите `CLOUDFLARE_TUNNEL_URL` в `.env` на docker-шлюз (`http://<gateway-ip>:3003`).
|
||||||
|
|
||||||
|
Адрес Quick Tunnel меняется при каждом перезапуске контейнера `cloudflared`. Для постоянного адреса используйте именованный туннель (для этого в `start-cloudflared.sh` замените последнюю команду на `exec cloudflared --no-autoupdate tunnel run --token "$CLOUDFLARE_TUNNEL_TOKEN"` и задайте токен; токен — из Cloudflare Zero Trust **Networks → Tunnels**) или схему через Tailscale выше.
|
||||||
|
|
||||||
## Структура данных
|
## Структура данных
|
||||||
|
|
||||||
|
|||||||
+13
-8
@@ -68,22 +68,27 @@ services:
|
|||||||
# Публикация наружу через Cloudflare Tunnel (cloudflared), Quick Tunnel:
|
# Публикация наружу через Cloudflare Tunnel (cloudflared), Quick Tunnel:
|
||||||
# случайный публичный URL *.trycloudflare.com, который печатается в логах:
|
# случайный публичный URL *.trycloudflare.com, который печатается в логах:
|
||||||
# docker compose logs -f cloudflared
|
# docker compose logs -f cloudflared
|
||||||
# ВАЖНО: официальный образ cloudflare/cloudflared НЕ содержит /bin/sh,
|
# Сборка из Dockerfile.cloudflared добавляет опциональный WireGuard:
|
||||||
# поэтому логика передаётся аргументами в command (entrypoint образа = cloudflared),
|
# если в wg/wg0.conf лежит конфиг — контейнер сначала поднимает VPN и
|
||||||
# а не скриптом.
|
# только потом запускает туннель (исход Cloudflare через VPN). Без конфига
|
||||||
# Для именованного туннеля на свой домен замените command ниже на:
|
# туннель стартует сразу, как в базовой схеме.
|
||||||
# command: ["tunnel", "run", "--token", "${CLOUDFLARE_TUNNEL_TOKEN}"]
|
|
||||||
# (токен получается в Cloudflare Zero Trust -> Networks -> Tunnels).
|
|
||||||
cloudflared:
|
cloudflared:
|
||||||
image: cloudflare/cloudflared:latest
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.cloudflared
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
volumes:
|
||||||
|
- ./wg:/etc/wireguard:ro
|
||||||
environment:
|
environment:
|
||||||
TZ: Europe/Moscow
|
TZ: Europe/Moscow
|
||||||
command: ["tunnel", "--url", "${CLOUDFLARE_TUNNEL_URL:-http://app:3003}"]
|
CLOUDFLARE_TUNNEL_URL: ${CLOUDFLARE_TUNNEL_URL:-http://app:3003}
|
||||||
depends_on:
|
depends_on:
|
||||||
- app
|
- app
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
text-corrector:
|
text-corrector:
|
||||||
image: ghcr.io/ggml-org/llama.cpp:server
|
image: ghcr.io/ggml-org/llama.cpp:server
|
||||||
container_name: text-corrector
|
container_name: text-corrector
|
||||||
|
|||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Опциональный WireGuard: если в wg/wg0.conf лежит конфиг — поднимаем VPN
|
||||||
|
# и только после установки handshake запускаем туннель. Без конфига —
|
||||||
|
# cloudflared стартует сразу, как в базовой схеме Quick Tunnel.
|
||||||
|
if [ -f /etc/wireguard/wg0.conf ]; then
|
||||||
|
echo "WireGuard config found, bringing up wg0..."
|
||||||
|
wg-quick up wg0
|
||||||
|
echo "Waiting for WireGuard handshake..."
|
||||||
|
# Формат `wg show wg0 latest-handshakes`: "<pubkey> <epoch-ts>"; 0 = handshake ещё не было.
|
||||||
|
until wg show wg0 latest-handshakes | awk '{ if ($2 != 0) found=1 } END { exit !found }'; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "WireGuard is up, starting Cloudflare tunnel through VPN..."
|
||||||
|
else
|
||||||
|
echo "No WireGuard config, starting Cloudflare tunnel directly..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec cloudflared --no-autoupdate tunnel --url "$CLOUDFLARE_TUNNEL_URL"
|
||||||
Reference in New Issue
Block a user