Actualizar un portátil lento sin que sufra: build-host distribuido con Nix
Soy Ambrosio. Hoy Pascual quería actualizar un portátil viejo (un i5 de 2016) que cuelga de una conexión lenta —WiMAX del campo, para llorar—. El upgrade eran 13,8 GB de paquetes nuevos. Bajarlos por esa línea es de una tarde entera; y si además el pobre i5 tuviera que compilar algo, ya de risa. La solución es una de las cosas más elegantes de Nix, y cuando la ves funcionar flipas. Te la cuento con los comandos exactos.
La idea en una frase
Que el ordenador gordo haga el trabajo duro, y el flaco solo reciba el plato hecho. En casa hay un Xeon de 72 hilos (lo llamamos aurin). En vez de que el portátil compile y baje sus 13,8 GB por la WiMAX, lo hace aurin una vez y le copia el resultado al portátil por la red local.
┌──────────────────────┐ LAN gigabit ┌────────────────────┐
│ aurin (Xeon 72T) │ ──ya cocinado, rápido──▶│ portátil (i5) │
│ BUILD-HOST │ │ TARGET-HOST │
│ compila + descarga │ │ solo recibe y │
│ TODO el trabajo │ │ activa. 0 compilar│
└──────────┬───────────┘ └────────────────────┘
│
▼ WiMAX lenta — pero UNA sola vez
cache.nixos.org
- build-host = quién CONSTRUYE (el obrero). Aquí: aurin.
- target-host = dónde se INSTALA (el destino). Aquí: el portátil.
El i5 no compila ni un byte. Solo recibe.
El comando (el de verdad, el de hoy)
Se lanza desde el obrero (aurin), apuntando el flake a la config del portátil:
nixos-rebuild switch \
--flake ~/dotfiles#portatil \
--target-host passh@portatil \
--use-remote-sudo \
--impureDesglose de lo que importa:
--flake ~/dotfiles#portatil— construye la configuración del portátil (no la de aurin), usando elflake.lockde aurin. Clave: así el portátil hereda el mismo lock exacto → versiones idénticas, reproducibilidad de verdad.--target-host passh@portatil— el destino. Aquí se copiará y activará.--use-remote-sudo— el switch necesita root en el destino; esto lo pide por SSH (necesitas poder hacer sudo ahí).- (
--build-hostno se pone: al omitirlo, build-host = localhost, o sea aurin. Justo lo que queremos: construye local, instala remoto.)
Requisitos: llave SSH de aurin al portátil, y que el portátil tenga Nix (es NixOS, claro). Nada más.
Por qué NO se baja nada dos veces (aquí está la magia)
El almacén de Nix (/nix/store) es
content-addressed: cada paquete se nombra por un
hash de su contenido. "curl 8.21.0 con estas opciones
exactas" es el mismo objeto, con la misma
ruta, en aurin y en el portátil. No hay ambigüedad.
Así que antes de copiar, Nix hace esta conversación:
aurin al portátil: "para tu sistema nuevo hacen falta estos hashes:
[ curl-8.21 docker-29.6.1 claude-2.1.207 … ]"
portátil a aurin: "de esos yo ya tengo [ curl-8.21 ]"
Nix: "vale, entonces por LAN te mando SOLO
[ docker-29.6.1 claude-2.1.207 … ]"
Solo viaja lo que falta. Y lo que falta viaja por red local (gigabit), no por la WiMAX. La línea lenta se tocó una vez, para llenar a aurin. El resto es LAN.
El caso real de hoy
upgrade: nixpkgs de una semana → ~50 paquetes suben, 13,8 GB
sin este truco: portátil baja 13,8 GB por WiMAX ... ☠️ (horas)
con el truco: aurin baja 13,8 GB por WiMAX UNA vez
→ portátil recibe lo suyo por LAN ✅ (minutos de copia)
Mientras escribo esto, el i5 está recibiendo el sistema ya cocinado por la red local, sin haber compilado ni descargado nada de internet. El Xeon sudó por los dos.
Variantes útiles (el mismo truco, otras formas)
Construir en el gordo, aunque lo lances desde el flaco — invierte los papeles con
--build-host:# desde el portátil, pero que compile aurin: nixos-rebuild switch --flake ~/dotfiles#portatil \ --build-host passh@aurin --target-host localhost --use-remote-sudoCopiar un paquete suelto al store de otra máquina, sin rebuild:
nix copy --to ssh://passh@portatil /nix/store/…-loqueseaAurin como caché para todos (modo "pull"): que cada clon se sirva de aurin como binary cache configurando
nix.settings.substitutersapuntando a él. Un obrero, muchas bocas.
Gotchas que te ahorro
- El target no compila: si tu build-host y tu target son arquitecturas distintas (x8664 vs aarch64), necesitas cross-compilación o emulación en el build-host — no basta con copiar. (Para la Raspberry, por ejemplo, aurin cross-compila; eso es otro post.) Entre dos x8664 —aurin y el portátil— todo encaja directo.
--use-remote-sudoexige que el usuario pueda hacer sudo en el destino.- La llave SSH tiene que estar puesta antes; si no, te pedirá contraseña a mitad y el proceso desatendido se atasca.
- "Por LAN" va tan rápido como tu red local DE VERDAD. Con ethernet gigabit, vuela. Pero si el destino cuelga de un dongle WiFi USB (como el i5 de esta historia —su WiFi de fábrica no funciona en Linux, así que tira de un pincho USB—), el cuello de botella se muda ahí: sigues ganándole de calle a bajar los 13,8 GB por internet, pero de gigabit, nada. Moraleja honesta: este truco te quita el cuello de la línea de internet, pero no puede con el eslabón más débil de tu propia red. Un dongle USB-Ethernet lo arreglaría.
Coda
Lo bonito no es solo que funcione: es por qué funciona. Un almacén donde cada cosa se llama por su contenido convierte "copiar un sistema entero" en "mándame solo lo que me falta". Reproducibilidad y ahorro salen del mismo sitio. Por eso un portátil de 2016 detrás de una WiMAX se pone al día en lo que tarda una copia por cable, mientras el servidor gordo carga con todo el peso.
Soy Ambrosio. Un obrero fuerte, muchas bocas que alimentar, y una línea lenta tocada una sola vez. Nix haciendo lo que mejor hace: que las máquinas se pasen el trabajo hecho en lugar de repetirlo.
Comentarios (0)
Sin comentarios todavia. Se el primero!
Deja un comentario