Publicar un servidor domèstic a través d’un VPS quan CGNAT bloqueja els ports
El camí del navegador a la màquina de casa: demostrar que la línia és darrere CGNAT, apuntar el DNS al VPS, fer DNAT d’un port, arreglar la ruta de tornada i verificar des de fora.
Vaig començar des de fora, com ho faria un usuari: vaig escriure el nom al navegador d’un telèfon amb dades mòbils i vaig veure com la connexió es quedava penjada fins que va caducar. El nom es resolia, així que el DNS estava bé. La pàgina de redirecció de ports del router de casa també era un cul-de-sac, perquè la seva adreça WAN marcava 100.64.31.42, i aquesta no és una adreça a la qual un proveïdor m’encamini des d’internet. Aquest número explica tota la fallada: la línia és darrere de carrier-grade NAT, així que l’adreça pública del meu costat del túnel pertany al proveïdor. El que segueix és el camí que vaig recórrer des d’aquella pestanya penjada fins a un servei que respon.
Començar pel client i avançar cap a dins
Abans de canviar cap regla, demostra on s’atura la cadena. Al portàtil vaig executar dig +short files.example.net i vaig obtenir l’adreça del VPS, cosa que descartava un DNS obsolet a la meva màquina. Després, curl -v --connect-timeout 5 files.example.net:5022 va caducar en lloc de ser rebutjat. Aquesta diferència importa: un temps esgotat normalment vol dir que s’estan descartant paquets pel camí, mentre que un rebuig vol dir que alguna cosa va respondre i va dir que no.
El salt següent cap a dins era el mateix VPS. ss -ltnp no va mostrar res escoltant al 5022, cosa que era esperable abans que existís la regla DNAT. A la mateixa màquina, wg show (o ip -br a show tun0 per a OpenVPN) va confirmar que el parell de casa estava actiu amb un handshake recent. Si el parell està caigut, cap regla NAT ajudarà, i el llum verd de la pàgina VPN del router de casa no vol dir res.
Confirmar que la línia de casa és realment darrere de CGNAT
Compara l’adreça que el router informa a la seva interfície WAN amb el que veu un servei extern. Tot el que està a 100.64.0.0/10, és a dir, 100.64.x.x fins a 100.127.x.x, és el rang d’adreces compartides del RFC 6598 i no es pot assolir des d’internet. Arribes a la mateixa conclusió quan el router afirma tenir una adreça privada normal i una consulta pública retorna una cosa que no hi té res a veure. Una línia CGNAT també pot portar una adreça pública que només dura fins al següent arrendament, de manera que una redirecció de port sembla funcionar una hora i després mor en silenci.
Alguns proveïdors sí que lliuren una adreça pública real, però bloquegen els ports entrants 80 i 443 en comptes residencials. Si el teu servei és només web i l’adreça WAN és realment pública, pregunta al suport abans de construir un relé. Si no ho és, el disseny de sota s’aplica a tots els ports per igual, i val la pena aturar l’experiment al costat del router: el traductor de la xarxa del proveïdor tanca la connexió abans que arribi a la teva interfície WAN.
Apuntar el nom a l’adreça del VPS
El DNS no retransmet trànsit, així que el registre A del servei ha de contenir l’adreça pública del VPS. Un registre A cap a 192.168.1.20 només es resol de manera útil per als clients que ja són dins la VPN; des d’internet es resol a una adreça que ningú no pot encaminar. Per a l’accés d’administració del mateix VPS mantinc un nom a part, per no confondre mai a quin amfitrió apunta un registre.
Si tant el VPS com la màquina de casa serveixen HTTP, dona a cadascun el seu propi nom i deixa que el VPS decideixi qui respon. Fondre’ls en un sol nom i esperar que el proxy triï el backend correcte és exactament com acabes depurant l’amfitrió equivocat durant tota una tarda.
Un port en DNAT, SSH es queda al 22
L’opció directa és NAT de destinació al VPS. Activa el reenviament per al nucli en execució i mantén l’adreça de túnel del servidor de casa a la regla, no la seva adreça 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
Deixa l’SSH cap al mateix VPS al 22 i reenvia un altre port, per exemple el 5022, a la màquina de casa. Si reenvies el 22 a una màquina apagada, perds l’únic camí que l’hauria pogut arreglar. La mateixa lògica s’aplica al proxy: deixa el port d’administració del VPS fora de les regles de relé.
Fes persistents les regles quan funcionin. A Debian o Ubuntu, apt install iptables-persistent i després netfilter-persistent save les escriuen a /etc/iptables/rules.v4. En un amfitrió amb firewalld l’equivalent és un reenviament de port permanent a la zona, que necessita firewall-cmd --reload abans d’aplicar-se. Les regles que només viuen en memòria desapareixen al primer reinici de manteniment del proveïdor, normalment a una hora dolenta.
Arreglar la ruta de tornada, o evitar necessitar-la
DNAT reescriu només la destinació. El servidor de casa veu una connexió des de l’adreça del client original, i si la seva ruta per defecte apunta al router de casa, la resposta surt per la WAN domèstica on el traductor del proveïdor la descarta. Aquesta asimetria va ser la segona fallada que vaig trobar, després que la regla DNAT semblés completament correcta.
Dues correccions funcionen. Dona a la màquina de casa una ruta de política perquè el trànsit del túnel torni pel túnel:
ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100
O deixa que el VPS reescrigui l’origen perquè la resposta tingui una adreça que pugui assolir, i deixa que conntrack la inverteixi a la sortida:
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1
La versió SNAT amaga l’adreça real del client al servidor de casa, així que els registres de l’aplicació mostren 10.8.0.1 com a parell. Passa l’adreça original a la capa d’aplicació, o accepta perdre el registre per client, però decideix-ho deliberadament en lloc de descobrir-ho durant un incident.
Comprovar tot el camí des de fora
Verifica des d’una xarxa que no sigui ni el VPS ni la casa: un telèfon amb dades mòbils, o una shell barata en un altre lloc. nc -vz files.example.net 5022 hauria d’informar d’una connexió correcta, i openssl s_client -connect files.example.net:443 -servername files.example.net hauria de mostrar el certificat del nom públic. Després revisa el grup de seguretat o el tallafoc al núvol del proveïdor. Una regla DNAT que no veu mai cap paquet normalment està bloquejada una capa per sobre de l’amfitrió.
Finalment, decideix què passa quan el túnel cau. Una regla DNAT continua acceptant connexions i les alimenta en silenci cap a un túnel mort, cosa que sembla exactament un servei espatllat. Una comprovació de salut al VPS que rebutgi el port mentre el parell està caigut costa unes quantes línies i estalvia una hora de conjectures. Després, deixa d’editar regles i observa-ho durant un dia abans de confiar-hi.