Zveřejnění domácího serveru přes VPS, když CGNAT blokuje porty
Cesta od prohlížeče k domácímu stroji: dokaž, že linka je za CGNAT, namiř DNS na VPS, udělej DNAT jednoho portu, oprav zpáteční trasu a ověř zvenčí.
Začal jsem zvenčí, jak by to udělal uživatel: napsal jsem název do prohlížeče telefonu na mobilních datech a sledoval, jak spojení visí, dokud nevypršel čas. Název se překládal, takže DNS bylo v pořádku. Také stránka přesměrování portů domácího routeru byla slepou uličkou, protože její adresa WAN ukazovala 100.64.31.42, a to není adresa, na kterou mě poskytovatel z internetu směruje. To číslo vysvětluje celou poruchu: linka je za carrier-grade NAT, takže veřejná adresa na mé straně tunelu patří poskytovateli. Co následuje, je cesta, kterou jsem ušel od toho zaseknutého panelu ke službě, která odpovídá.
Začni u klienta a jdi dovnitř
Než změníš jakékoli pravidlo, dokaž, kde se řetěz zastaví. Na notebooku jsem spustil dig +short files.example.net a dostal zpět adresu VPS, což vyloučilo zastaralé DNS na mém stroji. Potom curl -v --connect-timeout 5 files.example.net:5022 vypršel namísto toho, aby byl odmítnut. Ten rozdíl je důležitý: vypršení obvykle znamená, že se pakety po cestě zahazují, zatímco odmítnutí znamená, že něco odpovědělo a řeklo ne.
Dalším skokem dovnitř bylo samotné VPS. ss -ltnp neukázalo nic, co by naslouchalo na 5022, což se očekávalo před vznikem pravidla DNAT. Na stejném stroji wg show (nebo ip -br a show tun0 pro OpenVPN) potvrdilo, že domácí peer běží a má čerstvý handshake. Pokud peer neběží, žádné pravidlo NAT nepomůže, a zelené světlo na stránce VPN domácího routeru nic neznamená.
Potvrď, že domácí linka je opravdu za CGNAT
Porovnej adresu, kterou router hlásí na rozhraní WAN, s tím, co vidí externí služba. Vše v 100.64.0.0/10, tedy od 100.64.x.x do 100.127.x.x, je rozsah sdílených adres z RFC 6598 a z internetu není dosažitelné. Ke stejnému závěru dojdeš, když router tvrdí, že má běžnou privátní adresu, a veřejné vyhledání vrátí něco nesouvisejícího. Linka CGNAT může mít i veřejnou adresu platnou jen do dalšího lease, takže přesměrování portu vypadá hodinu funkčně a pak tiše zemře.
Někteří poskytovatelé skutečně dávají pravou veřejnou adresu, ale blokují příchozí porty 80 a 443 na rezidenčních účtech. Pokud je tvá služba jen webová a adresa WAN je skutečně veřejná, zeptej se podpory, než postavíš relay. Pokud není, níže uvedený návrh platí pro každý port stejně a stojí za to experiment na straně routeru zastavit: translator v síti poskytovatele ukončí spojení dřív, než vůbec dorazí na tvé rozhraní WAN.
Namiř název na adresu VPS
DNS nepředává provoz, takže záznam A služby musí obsahovat veřejnou adresu VPS. Záznam A na 192.168.1.20 se užitečně překládá jen pro klienty, kteří už jsou ve VPN; z internetu se překládá na adresu, kterou nikdo nedokáže směrovat. Pro administrativní přístup k samotné VPS držím samostatný název, abych nikdy nepletl, na který hostitel záznam ukazuje.
Pokud HTTP servíruje jak VPS, tak domácí stroj, dej každému vlastní název a nech VPS rozhodnout, kdo odpovídá. Složit je do jednoho názvu a doufat, že proxy vybere správný backend, je přesně to, jak strávíš celé odpoledne laděním špatného hostitele.
Jeden port přes DNAT, SSH zůstane na 22
Přímou možností je cílový NAT na VPS. Zapni forwarding pro běžící jádro a drž v pravidle tunelovou adresu domácího serveru, ne jeho adresu LAN:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 198.51.100.10 --dport 5022 -j DNAT --to-destination 10.8.0.2
Nech SSH k samotné VPS na 22 a přeposílej jiný port, například 5022, na domácí stroj. Když přeposíláš 22 na vypnutý stroj, ztratíš jedinou cestu, která ho mohla opravit. Stejná logika platí pro proxy: drž správcovský port VPS mimo pravidla relaye.
Udělej pravidla trvalými, jakmile fungují. Na Debianu nebo Ubuntu je apt install iptables-persistent a potom netfilter-persistent save zapíšou do /etc/iptables/rules.v4. Na hostiteli s firewalld je ekvivalentem trvalé přesměrování portu v zóně, které před uplatněním potřebuje firewall-cmd --reload. Pravidla, která žijí jen v paměti, zmizí při prvním údržbovém restartu poskytovatele, obvykle v nevhodnou hodinu.
Oprav zpáteční trasu, nebo se vyhni tomu ji potřebovat
DNAT přepisuje jen cíl. Domácí server vidí spojení z původní adresy klienta, a pokud jeho výchozí trasa míří na domácí router, odpověď vychází přes domácí WAN, kde ji translator poskytovatele zahodí. Ta asymetrie byla druhá porucha, na kterou jsem narazil, poté co pravidlo DNAT vypadalo naprosto správně.
Fungují dvě opravy. Dej domácímu stroji politickou trasu, aby provoz z tunelu šel zpět tunelem:
ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100
Nebo nech VPS přepsat zdroj, aby odpověď měla adresu, kterou dokáže dosáhnout, a nech conntrack ji na cestě ven otočit:
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1
Verze SNAT skrývá skutečnou adresu klienta před domácím serverem, takže aplikační logy ukazují 10.8.0.1 jako peer. Předej původní adresu na aplikační vrstvě, nebo přijmi ztrátu logování po klientech, ale rozhodni se vědomě, místo abys to zjistil během incidentu.
Zkontroluj celou cestu zvenčí
Ověř ze sítě, která není ani VPS, ani domov: telefon na mobilních datech, nebo levný shell jinde. nc -vz files.example.net 5022 by mělo hlásit úspěšné spojení a openssl s_client -connect files.example.net:443 -servername files.example.net by mělo ukázat certifikát pro veřejný název. Pak zkontroluj security group nebo cloudový firewall poskytovatele. Pravidlo DNAT, které nikdy nevidí paket, bývá blokováno o jednu vrstvu výš než hostitel.
Nakonec rozhodni, co se stane, když tunel spadne. Pravidlo DNAT dál přijímá spojení a tiše je posílá do mrtvého tunelu, což vypadá přesně jako rozbitá služba. Kontrola stavu na VPS, která port odmítá, dokud peer neběží, stojí pár řádků a ušetří hodinu hádání. Potom přestaň upravovat pravidla a sleduj to den, než tomu uvěříš.