Cloudflare Tunnel świetnie nadaje się do aplikacji webowych, ale administracja to coś innego: SSH, panel Proxmoxa, iDRAC, udziały SMB. Potrzebujesz do niej pełnego dostępu do sieci LAN, tak jak z domowej sieci — i nikt poza Tobą nie powinien nawet wiedzieć, że taki dostęp istnieje.
WireGuard ma tu przewagę nad innymi VPN-ami: nie odpowiada na pakiety bez poprawnego klucza. Skaner portów nie odróżni go od zamkniętego portu. Do tego jest szybki i mieści się w kilku tysiącach linii kodu w jądrze Linuksa.
CGNAT — jak sprawdzić, czy masz publiczny IP
WireGuard wymaga, żeby urządzenie z zewnątrz mogło dotrzeć do Twojego routera na porcie UDP. Sprawdź to, zanim zaczniesz:
# Adres, pod którym widzi Cię internetcurl -4s https://ifconfig.mePorównaj wynik z adresem WAN w panelu routera:
- Adresy identyczne — masz publiczny IP. Możesz kontynuować.
- Adres WAN z zakresu
100.64.0.0/10(np.100.72.14.3) albo prywatny (10.x,192.168.x) — jesteś za CGNAT-em operatora. Przekierowanie portu nic nie da. Rozwiązania opisuję na końcu artykułu.
Kontener LXC na WireGuard
Moduł WireGuard jest wbudowany w jądro Proxmoxa, więc serwer może działać w lekkim, nieuprzywilejowanym kontenerze LXC — 1 rdzeń i 256 MB RAM-u to więcej, niż potrzeba.
# Najnowszy szablon Debiana 13pveam updateTEMPLATE=$(pveam available --section system | awk '/debian-13-standard/ {print $2}' | sort -V | tail -1)pveam download local "$TEMPLATE"
pct create 120 "local:vztmpl/$TEMPLATE" \ --hostname wireguard \ --cores 1 \ --memory 256 \ --swap 256 \ --rootfs tank-vm:4 \ --net0 name=eth0,bridge=vmbr0,ip=192.168.1.30/24,gw=192.168.1.1 \ --nameserver 192.168.1.1 \ --unprivileged 1 \ --features nesting=1 \ --ssh-public-keys /root/admin.pub \ --onboot 1 \ --start 1
pct enter 120W kontenerze:
apt update && apt full-upgrade -yapt install -y wireguard-tools iptables qrencode
# Przekazywanie pakietów między tunelem a LANcat > /etc/sysctl.d/99-wireguard.conf <<'EOF'net.ipv4.ip_forward = 1EOFsysctl --systemKonfiguracja serwera WireGuard
Poniższy skrypt generuje klucze i plik wg0.conf. Uzupełnij trzy zmienne na górze — wartości w skrypcie odpowiadają sieci z tej serii:
#!/usr/bin/env bashset -euo pipefail
VPN_SUBNET="10.8.0" # sieć tunelu: 10.8.0.0/24, serwer = .1LISTEN_PORT=51820LAN_IFACE="eth0" # interfejs kontenera w sieci LAN
umask 077mkdir -p /etc/wireguard/clientscd /etc/wireguard
[[ -f server.key ]] || wg genkey > server.keywg pubkey < server.key > server.pub
cat > wg0.conf <<EOF[Interface]Address = ${VPN_SUBNET}.1/24ListenPort = ${LISTEN_PORT}PrivateKey = $(cat server.key)# NAT: urządzenia w LAN widzą ruch z VPN jako ruch z kontenera — bez tras statycznych na routerzePostUp = iptables -t nat -A POSTROUTING -s ${VPN_SUBNET}.0/24 -o ${LAN_IFACE} -j MASQUERADEPostDown = iptables -t nat -D POSTROUTING -s ${VPN_SUBNET}.0/24 -o ${LAN_IFACE} -j MASQUERADEEOF
systemctl enable --now wg-quick@wg0wg showbash /root/wg-setup.shDodawanie urządzeń z kodem QR
Każde urządzenie (telefon, laptop) dostaje własną parę kluczy i adres w tunelu. Skrypt dopisuje je do serwera bez restartu tunelu i wyświetla kod QR do zeskanowania aplikacją WireGuard:
#!/usr/bin/env bash# Użycie: wg-add-peer <nazwa> <numer 2-254># Przykład: wg-add-peer telefon 2set -euo pipefail
NAME="${1:?Podaj nazwę urządzenia}"NUM="${2:?Podaj numer urządzenia (2-254)}"
VPN_SUBNET="10.8.0"LAN_SUBNET="192.168.1.0/24"LAN_DNS="192.168.1.1"ENDPOINT="vpn.prywatnylab.pl:51820" # domena z DDNS (niżej) lub stały publiczny IP
cd /etc/wireguardumask 077
if grep -q "AllowedIPs = ${VPN_SUBNET}.${NUM}/32" wg0.conf; then echo "Adres ${VPN_SUBNET}.${NUM} jest już zajęty" >&2 exit 1fi
KEY=$(wg genkey)PUB=$(echo "$KEY" | wg pubkey)PSK=$(wg genpsk)
cat >> wg0.conf <<EOF
[Peer]# ${NAME}PublicKey = ${PUB}PresharedKey = ${PSK}AllowedIPs = ${VPN_SUBNET}.${NUM}/32EOF
cat > "clients/${NAME}.conf" <<EOF[Interface]PrivateKey = ${KEY}Address = ${VPN_SUBNET}.${NUM}/32DNS = ${LAN_DNS}
[Peer]PublicKey = $(cat server.pub)PresharedKey = ${PSK}Endpoint = ${ENDPOINT}# Split tunnel: przez VPN idzie tylko ruch do labu, reszta internetu bezpośrednioAllowedIPs = ${VPN_SUBNET}.0/24, ${LAN_SUBNET}PersistentKeepalive = 25EOF
# Przeładowanie konfiguracji bez zrywania istniejących połączeńwg syncconf wg0 <(wg-quick strip wg0)
qrencode -t ansiutf8 < "clients/${NAME}.conf"echo "Konfiguracja zapisana w /etc/wireguard/clients/${NAME}.conf"chmod 700 /usr/local/sbin/wg-add-peerwg-add-peer telefon 2wg-add-peer laptop 3Odebranie dostępu (zgubiony telefon): usuń sekcję [Peer] danego urządzenia z wg0.conf i wykonaj wg syncconf wg0 <(wg-quick strip wg0).
Router: przekierowanie portu
W routerze przekieruj UDP 51820 na 192.168.1.30 (kontener WireGuard). To jedyny port, jaki otwierasz w całej serii — i jedyny, który nie ujawnia niczego, dopóki klient nie przedstawi poprawnego klucza.
Zmienny adres IP: DDNS przez Cloudflare
Większość domowych łączy dostaje co jakiś czas nowy adres. Kontener cloudflare-ddns pilnuje, żeby rekord vpn.prywatnylab.pl zawsze wskazywał aktualny IP. Dodaj go w maszynie docker01:
services: cloudflare-ddns: image: favonia/cloudflare-ddns:latest container_name: cloudflare-ddns restart: unless-stopped network_mode: host read_only: true cap_drop: [all] security_opt: [no-new-privileges:true] user: '1000:1000' environment: CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN} DOMAINS: vpn.prywatnylab.pl PROXIED: 'false' IP6_PROVIDER: noneToken API utworzysz w panelu Cloudflare: My Profile → API Tokens → Create Token → szablon „Edit zone DNS”, z uprawnieniami ograniczonymi do jednej strefy. Zapisz go w /opt/stacks/ddns/.env jako CLOUDFLARE_API_TOKEN=... i ustaw chmod 600 .env.
PROXIED: 'false' jest tu konieczne. Cloudflare proxy obsługuje tylko HTTP(S), więc rekord VPN musi wskazywać bezpośrednio na Twój IP.
Test
Wyłącz Wi-Fi w telefonie (żeby wyjść przez sieć komórkową), włącz tunel w aplikacji WireGuard i otwórz https://192.168.1.10:8006. Na serwerze:
wg showPrzy urządzeniu powinna pojawić się linia latest handshake: … seconds ago i rosnące liczniki transfer.
Jak ominąć CGNAT
Bez publicznego IP połączenie przychodzące do domu jest niemożliwe, ale wychodzące — jak najbardziej. Masz trzy wyjścia:
- Poproś operatora o publiczny adres IPv4. Wielu dostawców światłowodu przydziela go bezpłatnie albo za kilka złotych miesięcznie. To najprostsze rozwiązanie.
- IPv6. Jeśli operator daje natywne IPv6, każde urządzenie ma publiczny adres. Otwórz UDP 51820 w firewallu routera dla adresu IPv6 kontenera i ustaw
IP6_PROVIDERw DDNS. Warunek: sieć, z której się łączysz, też musi mieć IPv6. - Serwer pośredniczący w chmurze. Darmowa maszyna w Oracle Cloud z publicznym IP służy jako punkt spotkań. Dom łączy się z nią tunelem wychodzącym (
PersistentKeepalive), a Ty łączysz się z nią z zewnątrz. Tę samą maszynę wykorzystasz w serii o niezależnym monitoringu — konfigurację VPS-a opisuję w części o Oracle Cloud.
Na tym kończy się seria o infrastrukturze. Masz serwer z Proxmoxem, pulę ZFS ze snapshotami, Dockera w maszynie wirtualnej, aplikacje dostępne przez Cloudflare Tunnel i prywatny kanał administracyjny. Pozostaje jedno pytanie: skąd dowiesz się, że coś przestało działać? Odpowiedź w serii Niezależny monitoring domowej sieci.