Gremlins Responsables: una Raspberry Pi 3 como quinto clon NixOS
Cuando le cae agua a un gremlin se multiplica y destroza todo. Cuando le cae agua a un sistema NixOS clone-first, se multiplica y hace backups. Somos gremlins responsables.
Este fin de semana montamos una Raspberry Pi 3 Model B como quinto nodo de nuestro sistema distribuido. Dentro de la torre del servidor principal. Enchufada, olvidada, replicando. El salvaculos definitivo.
El problema: un solo punto de fallo es inaceptable
Tenemos cuatro maquinas NixOS sincronizadas con Syncthing:
- aurin (produccion, Dual Xeon, 128GB RAM)
- vespino (test, headless)
- macbook (movilidad)
- cohete (VPS Hetzner, Nuremberg)
Todas replican lo mismo: org-mode, passwords (GPG), memoria de Ambrosio (sesiones de Claude Code), y la imagen golden de la VPN de trabajo.
Pero si aurin y vespino estan en el mismo sitio fisico… un corte de luz largo, un rayo, un incendio, y adivinad que pasa. Si, tenemos el VPS y el macbook, pero un nodo mas dentro de la propia torre de aurin, alimentado por la misma fuente pero con su propio disco, aniade otra capa de redundancia local. Arranca en 30 segundos, consume 3 watios, y nadie lo toca nunca.
El hardware: reciclaje puro
| Componente | Detalle |
|---|---|
| Placa | Raspberry Pi 3 Model B Rev 1.2 |
| CPU | BCM2837 ARM Cortex-A53, 4 cores a 1350 MHz (overclock) |
| RAM | 894 MB (con 1GB swap) |
| Disco | Samsung 840 PRO 128GB SSD (sacado de vespino) |
| Conexion | USB-to-SATA UGREEN + Ethernet USB |
| Ubicacion | Dentro de la Thermaltake Tower 900 de aurin |
Todo reciclado. La Pi llevaba anos corriendo RetroPie con una SD. El SSD estaba libre despues de migrar vespino a otro disco. El adaptador USB-to-SATA estaba en un cajon. Coste total: 0 euros.
NixOS en ARM: cross-compilacion desde x86
Una Pi 3 con 1GB de RAM no puede compilar NixOS. Se moriria de OOM intentando evaluar el flake. La solucion: cross-compilar en aurin (72 threads Xeon, 128GB RAM) y enviar el resultado por SSH.
Primero, habilitar emulacion QEMU en aurin:
# hosts/aurin/default.nix
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];Luego, crear el host en el flake con systemType aarch64:
# flake.nix
retropix = mkSystem {
hostname = "retropix";
systemType = "aarch64-linux";
};Y el deploy es un pipeline de 4 pasos:
# 1. Compilar (en aurin, cross aarch64 via QEMU)
nix build .#nixosConfigurations.retropix.config.system.build.toplevel
# 2. Firmar (la Pi solo acepta paquetes firmados por aurin)
sudo nix store sign --key-file /etc/nix/signing-key.sec -r $(readlink result)
# 3. Copiar al nix store de la Pi
nix copy --to ssh-ng://[email protected] $(readlink result)
# 4. Activar
ssh [email protected] "$(readlink result)/bin/switch-to-configuration switch"La Pi nunca compila nada. Solo recibe binarios firmados y los activa.
Los problemas que encontramos (y como los resolvimos)
USB Boot OTP
La Pi 3 arranca desde SD por defecto. Para arrancar desde SSD USB hay que activar un flag OTP (one-time programmable) que es irreversible:
# Desde RetroPie (antes de migrar)
echo program_usb_boot_mode=1 | sudo tee -a /boot/config.txt
sudo reboot
# Verificar: vcgencmd otp_dump | grep 17: -> 0x3020000aUna vez activado, la Pi intenta USB primero, SD despues. Para siempre. Sin vuelta atras.
piper-tts no compila en aarch64
Nuestro sistema base incluye Piper TTS (sintesis de voz para Ambrosio). Piper arrastra PyTorch y triton-llvm que no compilan via QEMU para ARM. La solucion: un overlay que reemplaza piper-tts con un dummy solo en retropix:
nixpkgs.overlays = [
(final: prev: {
piper-tts = final.runCommand "piper-tts-dummy" {} ''
mkdir -p $out/bin
cat > $out/bin/piper << 'DUMMY'
#!/bin/sh
echo "piper-tts: not available on aarch64" >&2
exit 1
DUMMY
chmod +x $out/bin/piper
'';
})
];El core del sistema no se toca. Solo este host recibe el dummy.
Paquetes x8664 en home-manager
Google Chrome, Slack, Postman, Spotify… son binarios propietarios que solo existen para x8664. Hay que excluirlos condicionalmente:
# modules/home-manager/passh.nix
home.packages = with pkgs; [
# Solo en x86_64
] ++ lib.optionals (pkgs.system == "x86_64-linux") [
google-chrome
slack
postman
spotify
];Filosofia clone-first: la misma config, adaptada automaticamente al hardware.
Syncthing: el quinto nodo
Con NixOS corriendo, activar Syncthing es declarativo. Un modulo
centralizado (modules/services/syncthing.nix) tiene todos los
device IDs y folders. Cada maquina se excluye a si misma
automaticamente:
# hosts/retropix/default.nix
imports = [ ../../modules/services/syncthing.nix ];
dotfiles.syncthing.enable = true;Despues de un rebuild y un reinicio, retropix aparece como conectado:
OK C2DZIRD (vespino)
OK D3XRGH4 (retropix) <-- nuevo
OK G34YZCV (cohete)
OK Q5FFDRL (macbook)
-- DKH4ALJ (pocapullos) <-- movil offline
Cuatro folders sincronizados:
org(journal, notas)ambrosio-memory(sesiones Claude Code, 219MB)password-store(GPG encrypted)vm-golden(imagen VPN Vocento)
Bonus: emuladores
Como ya teniamos la Pi con RetroPie, no iba a dejar de ser una consola. RetroArch viene instalado con 5 cores:
| Core | Sistema | Juego estrella |
|---|---|---|
| pcsx-rearmed | PSX | Xenogears |
| snes9x | SNES | - |
| mgba | GBA | - |
| nestopia | NES | - |
| genesis-plus-gx | Mega Drive | - |
pcsx-rearmed esta optimizado para ARM.
Xenogears corre fluido a 1350 MHz con el overclock.
El resultado: arquitectura gremlin
Syncthing mesh (5 nodos)
┌──────────┐ ┌──────────┐ ┌──────────┐
│ aurin │◄───►│ vespino │◄───►│ macbook │
│ (prod) │ │ (test) │ │ (laptop) │
└────┬─────┘ └──────────┘ └──────────┘
│
│ (misma torre)
│
┌────┴─────┐ ┌──────────┐
│ retropix │◄────────────────────►│ cohete │
│ (Pi 3) │ │ (VPS) │
└──────────┘ └──────────┘
5 clones. 3 ubicaciones fisicas. 0 euros extra.
Si aurin muere: vespino, macbook, cohete y retropix tienen todo. Si el piso pierde luz: campo (aurin + retropix) y Hetzner siguen. Si Hetzner cierra: cuatro maquinas locales tienen la replica. Si todo explota menos la Pi: 3 watios, 30 segundos de boot, toda la memoria intacta.
Somos gremlins. Pero responsables.
Lo que falta
Pero eso ya es para otro dia. Hoy el objetivo era uno: que la Pi replique y sobreviva. Objetivo cumplido.
—
Escrito desde aurin, replicado automaticamente a retropix mientras escribia.
Comentarios (0)
Sin comentarios todavia. Se el primero!
Deja un comentario