ZeroTier, el barco entero en el móvil

ZeroTier tiene fama de ser un lío de direcciones, y casi siempre es porque se cuenta al revés. Empecemos por lo que se gana, que es lo que hace que merezca la pena.

A bordo, a Signal K se llega con la dirección y el puerto del equipo donde está instalado: la dirección de la LAN del barco. Mientras estás dentro, eso basta. En cuanto sales —el móvil con datos, el portátil en casa—, esa dirección deja de existir, y sin nada más habría que memorizar una segunda dirección por cada aparato, la que ZeroTier le asigna, y acordarse de cuál es la de cada servicio. Dos juegos de direcciones para lo mismo, y el de siempre ya no sirve justo cuando estás fuera.

Con la ruta gestionada, la dirección de siempre vale dentro y fuera del barco. Si a bordo abres 192.168.1.10:3000 en el navegador, esa misma dirección —sin cambiar nada, sin una nota con la otra— te abre el mismo servicio desde el puerto, desde casa o desde el móvil con cobertura.

La ventaja es doble, y las dos mitades importan:

  • Llegas a los equipos que no llevan cliente. El router, el monitor de baterías o la Raspberry del motor no pueden tener ZeroTier instalado; están en la LAN y ahí se quedan. Con la ruta, los alcanzas igual que si estuvieras sentado en la bañera.
  • Dejas de tener dos direcciones para lo mismo. No hay que recordar la de ZeroTier de cada cacharro: vale la de la LAN, la que ya está en los marcadores y en la cabeza.

No es una promesa de la documentación: en el barco está probado. Con la ruta en servicio, el portátil y la tablet con 4G abren los servicios de a bordo por su dirección de la LAN, la de siempre.

En la primera parte vimos cómo crear la red, instalar el cliente en el equipo Linux del barco y llegar a lo que corre dentro: Signal K, el panel, la alarma de fondeo. Falta el resto de la LAN de a bordo, que no lleva cliente.

1. El problema

ZeroTier conecta aparatos que llevan su cliente, uno por uno. El router, el monitor de baterías y la Raspberry del motor no lo llevan: están en la LAN del barco y ahí se quedan. Desde el móvil llego a 10.147.20.10 y veo el panel; 192.168.1.1 no lleva a ninguna parte, porque solo existe dentro del barco. ¿Cómo se llega a una red entera con una herramienta que solo sabe de aparatos?

2. La solución son dos piezas

En la consola, en rutas gestionadas, se le dice a la red: «para llegar a 192.168.1.0/24, pasa por 10.147.20.10». La orden se reparte a los miembros: el móvil aprende que esa red está detrás del equipo Linux y le manda ese tráfico.

En el equipo Linux hay que hacer dos cosas: reenviar los paquetes de una interfaz a otra y enmascarar lo que sale hacia la LAN. Reenviar se entiende solo: el paquete entra por la interfaz de ZeroTier, va dirigido a 192.168.1.50 y, en vez de descartarlo, sale por la de la LAN.

Enmascarar es lo que cuesta. El monitor de baterías no sabe que existe 10.147.20.0/24: si le llega una petición con origen 10.147.20.10, la atiende, pero la respuesta no tiene por dónde volver. Al enmascarar, el equipo Linux pone su propia dirección de la LAN —192.168.1.10— como origen y se encarga de devolver cada respuesta a su dueño. Para la LAN, todo lo que viene del móvil parece venir del equipo Linux.

Y hacen falta las dos. Con la ruta y sin el reenvío, los paquetes se quedan en el equipo Linux; con el reenvío y sin la ruta, el móvil intenta salir por su red de casa y no llega; con ambas y sin enmascarar, la respuesta se pierde.

3. Por qué enmascarar y no poner una ruta en el router

Lo limpio sería decirle al router del barco «para llegar a 10.147.20.0/24, pasa por el equipo Linux». Si la admite, el resultado es el mismo sin tocar nada más.

En la práctica no siempre se puede: muchos routers de a bordo esconden esa opción, y otros van en modo puente porque el que reparte es otro aparato. Enmascarar en el equipo Linux no toca el router y solo configura el aparato que ya tenía el cliente. Es la pieza que todo el mundo intenta evitar y luego entiende.

4. Cómo se configura, paso a paso

Ejemplo: LAN 192.168.1.0/24; el equipo Linux, 192.168.1.10 en la LAN y 10.147.20.10 en ZeroTier. La interfaz de ZeroTier se llama zt… y la de la LAN eth0, enp1s0 o wlan0; se mira con ip -br addr.

La ruta, en la consola

En rutas gestionadas se añade la subred con el equipo Linux como puerta:

192.168.1.0/24   via   10.147.20.10

Si la LAN es más ancha —una /23—, el prefijo tiene que reflejarlo. Se guarda y los miembros reciben la ruta.

La ruta: la subred del barco, a través del equipo que hace de puerta

En el propio equipo Linux la ruta puede no aparecer: ya tiene esa LAN conectada y esa ruta gana. Se comprueba desde el móvil.

El reenvío y el enmascaramiento

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -I POSTROUTING -s 10.147.20.0/24 -o eth0 -j MASQUERADE
sudo iptables -I FORWARD -i zt+ -o eth0 -s 10.147.20.0/24 -j ACCEPT
sudo iptables -I FORWARD -i eth0 -o zt+ -m state --state RELATED,ESTABLISHED -j ACCEPT

Aviso: en las distribuciones recientes —Debian 13, el Raspberry Pi OS actual— el cortafuegos de serie es nftables y puede que el paquete iptables no venga instalado, con lo que estos comandos fallan en cuanto se copian y se pegan. Si pasa, se instala con el gestor de paquetes de tu distribución antes de seguir. No lo he comprobado en una máquina recién instalada, así que tómalo como aviso y no como certeza.

  • La primera activa el reenvío: sin eso el equipo no mueve paquetes entre interfaces.
  • La segunda enmascara: lo que sale a la LAN desde la subred de ZeroTier lleva la dirección del propio equipo.
  • La tercera y la cuarta abren el paso en los dos sentidos: del barco virtual a la LAN solo desde esa subred, y de vuelta solo las respuestas de conversaciones ya abiertas.

Van con -I (en cabeza) y no con -A: en un equipo con Docker la cadena FORWARD está en DROP y una regla al final no se aplica nunca. Tampoco sobreviven a un reinicio: en el barco las repone una unidad de systemd al arrancar, tras ZeroTier. Es la pieza que falta para que todo siga en pie al día siguiente, y la tienes entera en el anexo del final.

5. La trampa del MTU

ZeroTier va a 2800 por defecto y una LAN normal a 1500. El equipo Linux recibe un paquete de 2800 y lo reenvía, pero la LAN no lo lleva: se descarta en silencio.

El síntoma parece un fallo aleatorio: el ping responde y la portada del router carga, pero un fichero se queda a medias, una sesión SSH se congela al listar una carpeta grande, el gráfico del panel se queda pensando. Al rato vuelve. No es el servicio ni el wifi: son las transferencias grandes.

Se arregla recortando el tamaño máximo al salir a la LAN:

sudo iptables -t mangle -I FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Al abrir cada conexión TCP los dos extremos acuerdan el tamaño máximo de segmento; esta regla reescribe ese acuerdo en lo que sale hacia la LAN para que quepa en 1500. Medido en el barco: el cliente anunciaba 2740 y salía con 1460. Es la línea que falta en casi todos los tutoriales y la que convierte una red que «a veces va» en una que va.

6. Los límites, sin adornos

No cruza broadcast ni multicast. En esta red no hay difusión, así que fuera los nombres .local —se usan direcciones IP— y fuera el descubrimiento automático: el programa que busca impresoras o cámaras no las encuentra. Para consultar el router por su IP, da igual.

Desde la LAN no se inician conexiones hacia ZeroTier. El monitor no puede llamar al móvil; al revés sí, que es lo que hace falta.

El enmascaramiento oculta el origen. En los registros del router, los accesos desde ZeroTier aparecen con la dirección del equipo Linux: conviene saberlo antes de buscar un intruso que eres tú.

7. Si tu cuenta es de las nuevas

Desde noviembre de 2025 hay dos consolas. La antigua, my.zerotier.com, es la de las cuentas anteriores a esa fecha: mantiene su cupo —25 dispositivos en la mayoría— y permite rutas gestionadas gratis. La nueva, central.zerotier.com, es la de las altas nuevas: plan Personal gratis con 10 dispositivos, una red y un administrador, y sin rutas gestionadas. El equipo no sabe en qué consola vive su red.

Si te diste de alta hace poco, la ruta de la sección 4 no se puede poner con el plan gratuito: la pantalla está, pero deshabilitada. Hay que subir a un plan de pago —Essential, 18 $/mes, como referencia—; no afirmo cuál es el mínimo exacto: la tabla de precios y los foros no dicen lo mismo.

Tampoco hay migración automática: red nueva, identificador nuevo, cada equipo unido y autorizado otra vez, y rutas, DNS y reglas rehechas. El cupo de la cuenta vieja no viaja.

En la consola nueva, esa misma pantalla con el plan gratuito

8. Cierre

Con esto tengo el router, el monitor de baterías y la Raspberry del motor en el móvil: mirar las baterías sin bajar a la sala de máquinas, ver quién está conectado, asomarme al motor. También la música, la que vive en el barco y no en una lista de internet: la tablet con la app Tempo tira del Navidrome del equipo de a bordo, y fondeado a unos diez kilómetros suena sin problema. No es magia: dos piezas y una regla de MTU que casi nadie menciona.

Si algún día esto cambia, hay plan B: Tailscale hace lo mismo con un subnet router —un equipo que anuncia la subred—, en su plan gratuito y en Android sin root; también es capa 3, así que tampoco lleva broadcast ni multicast. Y Headscale es un plano de control propio, instalable en un servidor. Mientras tanto, lo que hay funciona sin tocar el router del barco.

La cuenta, el cliente en Linux y la app del móvil están en la primera parte; lo de aquí empieza donde aquella se quedaba corta.

Anexo: que las reglas sobrevivan a un reinicio

Las reglas de iptables viven en memoria: al apagar el equipo se van y no vuelven solas. El síntoma engaña, porque no hay ningún error: la ruta deja de funcionar y parece que ZeroTier se ha roto.

Para que eso no dependa de que alguien se acuerde de los cuatro comandos, van en dos ficheros: un script que los pone y una unidad de systemd que lo lanza al arrancar.

El script

#!/bin/bash
# Repone las reglas de la ruta ZeroTier -> LAN del barco.
# Es idempotente: si la regla ya existe, no la duplica.
set -u

ZT=10.147.20.0/24      # subred de la red ZeroTier
LAN_IF=eth0            # interfaz de la LAN del barco (se mira con: ip -br addr)
IPT=/usr/sbin/iptables

# add <tabla> <cadena> <regla...>: inserta solo si no esta ya.
add() {
    local t=$1 c=$2; shift 2
    "$IPT" -t "$t" -C "$c" "$@" 2>/dev/null || "$IPT" -t "$t" -I "$c" "$@"
}

add nat    POSTROUTING -s "$ZT" -o "$LAN_IF" -j MASQUERADE
add filter FORWARD     -i zt+ -o "$LAN_IF" -s "$ZT" -j ACCEPT
add filter FORWARD     -i "$LAN_IF" -o zt+ -m state --state RELATED,ESTABLISHED -j ACCEPT
add mangle FORWARD     -o "$LAN_IF" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Se guarda como zerotier-lan-forward.sh. Comprueba con -C antes de insertar con -I, así que se puede lanzar las veces que haga falta sin llenar la tabla de reglas repetidas. La última línea es el clamp de MSS de la sección del MTU: sin ella, el mismo montaje se cuelga con las descargas grandes.

La unidad

[Unit]
Description=Ruta ZeroTier hacia la LAN del barco
After=network-online.target zerotier-one.service
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/zerotier-lan-forward.sh
ExecStop=-/usr/sbin/iptables -t mangle -D FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
ExecStop=-/usr/sbin/iptables -D FORWARD -i eth0 -o zt+ -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=-/usr/sbin/iptables -D FORWARD -i zt+ -o eth0 -s 10.147.20.0/24 -j ACCEPT
ExecStop=-/usr/sbin/iptables -t nat -D POSTROUTING -s 10.147.20.0/24 -o eth0 -j MASQUERADE

[Install]
WantedBy=multi-user.target

Se guarda como zerotier-lan-forward.service. oneshot con RemainAfterExit=yes quiere decir «ejecuta esto una vez y dalo por hecho»: no se queda ningún proceso corriendo. After= espera a que ZeroTier esté levantado, porque antes de eso la interfaz zt… no existe y las reglas no hay dónde ponerlas. Las líneas ExecStop deshacen exactamente lo hecho, para que parar la unidad deje el equipo como estaba.

No hace falta saber systemd para esto: son tres ficheros y tres comandos.

El reenvío del núcleo

Para que los paquetes pasen de una interfaz a otra hay que decírselo al núcleo. Si el equipo no tiene el reenvío activado, las cuatro reglas están puestas y aun así no pasa nada: ni un mensaje de error, ni una pista. Hay quien lo tiene activado por otra cosa —Docker, por ejemplo, lo pone al arrancar—, pero eso es un efecto secundario y puede cambiar con una actualización: mejor declararlo.

# /etc/sysctl.d/99-zerotier-lan-forward.conf
net.ipv4.ip_forward = 1

Se guarda como 99-zerotier-lan-forward.conf y se aplica:

sudo install -m 644 99-zerotier-lan-forward.conf /etc/sysctl.d/
sudo sysctl --system

Y se comprueba: sysctl net.ipv4.ip_forward tiene que devolver net.ipv4.ip_forward = 1.

Con esto son tres ficheros: el script, la unidad y este. Los otros dos se instalan y se ponen en marcha en el apartado siguiente.

Ponerlo en marcha

Con los dos ficheros guardados en el directorio de trabajo:

sudo install -m 755 zerotier-lan-forward.sh      /usr/local/sbin/
sudo install -m 644 zerotier-lan-forward.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now zerotier-lan-forward.service

Comprobarlo

systemctl status zerotier-lan-forward.service tiene que decir active (exited). Las cuatro reglas se ven así:

sudo iptables -t nat -S POSTROUTING
sudo iptables -S FORWARD
sudo iptables -t mangle -S FORWARD

Pero la prueba de verdad no es ninguna de esas: es reiniciar el equipo y volver a entrar desde fuera.

La referencia oficial de la unidad es la de freedesktop, en inglés: systemd.service.

Entrada Anterior Siguiente Entrada