192.168.8.0/24. La IP la dará el DHCP del aula. NetworkManager se encarga al arrancar.
Objetivos de la práctica
- Entender la diferencia entre configuración imperativa (Ubuntu, Windows) y declarativa (NixOS, Terraform, Kubernetes).
- Conocer las tres ideas centrales de Nix: store inmutable, derivación reproducible, generaciones con rollback atómico.
- Instalar NixOS desde la ISO minimal usando particionado manual y
nixos-install. - Leer y editar
/etc/nixos/configuration.nixpara añadir paquetes, usuarios y servicios. - Aplicar cambios con
nixos-rebuild switchy observar cómo el sistema entero se construye otra vez. - Romper la configuración a propósito y volver atrás con
nixos-rebuild switch --rollbacko desde GRUB. - Usar
nix-shellpara crear entornos efímeros con herramientas que no quieres instalar de forma permanente. - Comparar con Ubuntu: qué te cuesta más, qué te cuesta menos, qué problemas desaparecen.
- Diagnosticar tres fallos típicos: error de sintaxis en configuration.nix, paquete que no existe, sin red durante el rebuild.
- Documentar tu configuración final y entregarla como parte de la ficha técnica.
Parte 0 — Conceptos previos (60 min)
0.1 — El problema que NixOS quiere resolver
Imagina la siguiente escena, que pasa todos los días en oficinas de todo el mundo:
- El servidor de producción lleva tres años funcionando.
- Nadie recuerda exactamente qué cambios se le han hecho.
- Hay que "replicarlo" en otro servidor.
- Resultado: tres semanas de prueba/error, y el nuevo servidor casi es igual al viejo. Casi.
Este problema se llama configuration drift: el estado real del sistema se va alejando con el tiempo de cualquier documentación que tuvieras. Lo causan tres prácticas:
- Hacer cambios con
apt installsin apuntarlo. - Editar archivos a mano sin control de versiones.
- Aplicar parches manuales que el siguiente
apt upgradesobrescribe.
Las soluciones parcheadas al problema son Ansible, Puppet, Chef, Docker… Todas son capas encima de un SO imperativo. NixOS le da la vuelta: el SO entero es el resultado de un archivo declarativo. Si dos máquinas tienen el mismo configuration.nix y la misma versión de Nix, son bit a bit idénticas.
0.2 — Las tres ideas de Nix
1. Store inmutable
Todos los paquetes se instalan en /nix/store/ bajo una ruta que incluye un hash criptográfico. Por ejemplo:
/nix/store/abc123...-firefox-115.0.2/ /nix/store/def456...-firefox-116.0.0/
Los dos Firefox conviven sin pisarse. Nadie sobrescribe nada nunca. Para "actualizar" lo que se hace es cambiar a qué hash apunta el enlace /run/current-system.
2. Derivación reproducible
El hash de cada paquete se calcula a partir de todas sus entradas: fuente, compilador, flags, dependencias, sistema operativo. Si tú y otra persona compiláis el mismo paquete con los mismos parámetros, sale exactamente el mismo hash y los mismos bytes. Esto se llama build reproducible.
3. Generaciones con rollback
Cada vez que aplicas un cambio (nixos-rebuild switch) NixOS crea una nueva generación del sistema. La generación anterior sigue en disco. Si la nueva no arranca o tiene un fallo, eliges la anterior en el GRUB y estás otra vez en el estado de antes. El rollback es atómico: o estás en la generación nueva entera, o en la vieja entera, no en mitad de un upgrade roto.
0.3 — Imperativo vs declarativo, con un ejemplo
| Ubuntu (imperativo) | NixOS (declarativo) |
|---|---|
apt install nginx systemctl enable nginx sed -i 's/.../.../g' /etc/nginx/nginx.conf systemctl restart nginx ufw allow 805 pasos en orden. Si te saltas uno, queda a medias. |
services.nginx.enable = true;
services.nginx.virtualHosts."example" = {
root = "/var/www";
};
networking.firewall.allowedTCPPorts = [ 80 ];
Describes el final. Nix se encarga de cómo.
|
0.4 — Vocabulario mínimo del mundo Nix
| Término | Qué es |
|---|---|
| Nix (el lenguaje) | Lenguaje funcional puro, parecido a JSON con funciones, diseñado solo para describir paquetes y configs. |
| Nix (el gestor) | El programa que evalúa el lenguaje y construye paquetes. Puede instalarse en cualquier Linux/macOS sin NixOS. |
| NixOS | Una distro Linux donde todo el sistema se describe en Nix. |
| nixpkgs | El repositorio gigante de paquetes (~100.000) escritos en Nix. Equivalente a "Debian main". |
| Channel | Una versión de nixpkgs (por ejemplo "nixos-24.05" o "nixos-unstable"). |
| Generation | Una versión congelada del sistema, identificable por número. |
| Flake | Formato moderno (aún opcional) para hacer las builds reproducibles al 100% pinneando dependencias. No lo usaremos hoy. |
Con tus palabras: ¿qué problema soluciona NixOS que apt/dnf/pacman no solucionan, y a qué precio?
Parte 1 — Preparar la VM (15 min)
1.1 — Descargar la ISO
Desde https://nixos.org/download, sección "NixOS: the Linux distribution" → ISO image → Minimal ISO image (64-bit Intel/AMD). Aproximadamente 1 GB.
25.11, 26.05, etc). La vas a necesitar más tarde para rellenar system.stateVersion en tu configuration.nix: ese campo debe coincidir con la versión que usaste al instalar.
1.2 — Crear la VM
| Parámetro | Valor |
|---|---|
| Nombre | NixOS-Lab |
| Tipo | Linux |
| Versión | Linux 5.x or later (64-bit) |
| RAM | 2048 MB (Nix necesita memoria para evaluar) |
| CPUs | 2 vCPU |
| Disco | 20 GB VDI dinámico |
| Sistema | Habilitar EFI |
| Red | Adaptador puente (Intel) |
Parte 2 — Instalar NixOS (60 min)
2.1 — Arrancar y entrar como root
Arranca la VM. Tras el menú, aparece un prompt como [nixos@nixos:~]$. Estás en un Live ISO. Pasa a root:
sudo -i
2.2 — Particionar (UEFI + GPT)
parted /dev/sda -- mklabel gpt parted /dev/sda -- mkpart ESP fat32 1MB 512MB parted /dev/sda -- set 1 esp on parted /dev/sda -- mkpart primary 512MB 100%
Resultado: /dev/sda1 (EFI) y /dev/sda2 (root).
2.3 — Formatear y montar
mkfs.fat -F32 -n boot /dev/sda1 mkfs.ext4 -L nixos /dev/sda2 mount /dev/disk/by-label/nixos /mnt mkdir -p /mnt/boot mount /dev/disk/by-label/boot /mnt/boot
2.4 — Generar la configuración inicial
nixos-generate-config --root /mnt ls /mnt/etc/nixos/ # verás: configuration.nix hardware-configuration.nix
Nix ha detectado tu hardware y ha escrito un esqueleto. Vamos a tocarlo:
nano /mnt/etc/nixos/configuration.nix
2.5 — Editar configuration.nix mínimo
Descomenta o añade estas líneas (déjalas similares a esto, dentro del bloque grande):
{
imports = [ ./hardware-configuration.nix ];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking.hostName = "nixos-lab";
networking.networkmanager.enable = true;
time.timeZone = "Europe/Madrid";
i18n.defaultLocale = "es_ES.UTF-8";
console.keyMap = "es";
users.users.alumno = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
initialPassword = "alumno123";
};
environment.systemPackages = with pkgs; [
vim
git
htop
];
services.openssh.enable = true;
# Pon aquí la versión que apuntaste al descargar la ISO.
# Ejemplo: "25.11", "26.05"... Mírala con `nixos-version` antes de instalar.
system.stateVersion = "25.11";
}
system.stateVersion por la versión que tú descargaste. Si la dejas en una versión distinta a la del ISO, no es un error fatal pero puede activar lógica de migración inadecuada.
{ ... } son atajos, los = son asignaciones, y [ a b c ] son listas (separadas por espacios, no comas). Verlo asusta al principio; en 10 minutos te resulta cómodo.
2.6 — Instalar
nixos-install # pedirá contraseña de root para el sistema instalado reboot
(Antes de que arranque el sistema, retira la ISO del slot del DVD en VirtualBox.)
Parte 3 — Primer arranque y entender lo que has hecho (30 min)
Login con el usuario alumno y la contraseña alumno123. Ejecuta:
cat /etc/os-release nixos-version ls -l /run/current-system # es un symlink a /nix/store/HASH-nixos-system-... readlink /run/current-system nix-store -q --references /run/current-system | head ls /nix/store | wc -l
El último número probablemente sea ya 5.000+ entradas. Cada una es un paquete o una "derivación" en el store inmutable.
3.1 — Generaciones
sudo nix-env --list-generations -p /nix/var/nix/profiles/system
Solo deberías ver una, la 1. Vamos a hacer que aparezca la 2.
Parte 4 — Cambiar el sistema, declarativamente (60 min)
4.1 — Añadir paquetes
Edita /etc/nixos/configuration.nix y en environment.systemPackages añade tree, tmux y firefox:
environment.systemPackages = with pkgs; [ vim git htop tree tmux firefox ];
Aplica:
sudo nixos-rebuild switch
Esto descarga paquetes, los une en una nueva generación y la activa. Comprueba:
which tree sudo nix-env --list-generations -p /nix/var/nix/profiles/system # ahora hay 2 generaciones
4.2 — Habilitar un servicio
Añade Nginx con una página de prueba. En configuration.nix:
services.nginx = {
enable = true;
virtualHosts."hello" = {
default = true;
root = "/var/www";
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
system.activationScripts.miweb = ''
mkdir -p /var/www
echo "<h1>Hola desde NixOS</h1>" > /var/www/index.html
'';
Reaplica:
sudo nixos-rebuild switch curl http://localhost/ # debe responder "Hola desde NixOS"
4.3 — Romper algo a propósito
Edita configuration.nix y cambia services.nginx.enable = true; por services.nginx.enable = "si"; (mal tipo).
sudo nixos-rebuild switch
Nix se queja con un error de tipo y no aplica nada. Tu sistema sigue funcionando con la generación anterior intacta. Esto es lo que distingue a un sistema declarativo: errores en la config no rompen el sistema en marcha.
4.4 — Rollback de verdad
Deja Nginx bien otra vez. Aplica. Ahora simula un cambio "malo": quita Nginx, aplica, y luego decide que querías volver atrás:
sudo nixos-rebuild switch --rollback # vuelves a la generación anterior con un comando
Comprueba con nix-env --list-generations y con un curl localhost/: Nginx vuelve a estar.
¿Qué garantía te da el modelo de generaciones cuando aplicas una actualización del sistema en producción?
Parte 5 — nix-shell: entornos efímeros (45 min)
Una cosa muy potente de Nix es lanzar una shell con paquetes sin instalarlos en el sistema:
nix-shell -p cowsay cowsay "Hola" exit # fuera de la shell, cowsay no existe
Útil para probar herramientas. Y se puede combinar:
nix-shell -p nodejs python3 sqlite # tienes los tres juntos en una sub-shell
Cuando sales, no queda nada instalado. Cuando vuelves a entrar, sale de la caché.
5.1 — Reproducible: un shell.nix
Crea un archivo shell.nix en tu home:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [ pkgs.nodejs pkgs.python3 ];
}
Y desde el mismo directorio:
nix-shell
Cualquiera que clone esa carpeta y tenga Nix tendrá exactamente los mismos node y python. Esto es lo que en Python se intenta con venv, en JS con nvm… aquí es nativo.
Parte 6 — Diagnóstico (30 min)
| Problema | Tu diagnóstico |
|---|---|
nixos-rebuild switch dice "error: undefined variable 'firefoxx'". | |
| El rebuild se queda colgado en "fetching ...". | |
| Has reiniciado y el sistema arranca en una generación antigua sin querer. | |
| El disco se llena de paquetes viejos en /nix/store. | |
| Has añadido un servicio pero no escucha en el puerto. |
- Has hecho un typo en el nombre del paquete. Búscalo con
nix-env -qaP firefox(siempre funciona) o, si tienes flakes activos,nix search nixpkgs firefox. - Sin red. Comprueba
ip ayping 1.1.1.1. Si NetworkManager no está activo, edita configuration.nix y rebuild. - En GRUB elige siempre la generación más reciente (la más arriba). Si quieres marcarla como default, vuelves a hacer
nixos-rebuild switchdesde ella. sudo nix-collect-garbage --delete-older-than 7d.- Mira
journalctl -u nombre.servicey revisanetworking.firewall.allowedTCPPortsen la config.
Ficha técnica
Datos del sistema
Tu configuration.nix final (pega lo más relevante)
Reto opcional
services.xserver.enable = true; y services.xserver.desktopManager.gnome.enable = true; a tu configuration.nix. Reaplica con nixos-rebuild switch y reinicia. Al volver tendrás un sistema con escritorio gráfico completo. Tarda lo suyo en descargar — déjalo correr.
Autoevaluación
Marca lo conseguido
| Hito | Hecho |
|---|---|
| VM con UEFI, NixOS minimal arrancado en live | |
| Particionado manual con parted | |
| configuration.nix inicial editado y nixos-install completado | |
| Primer arranque del sistema instalado, login OK | |
| Paquetes añadidos al systemPackages y aplicados | |
| Nginx levantado con página propia en /var/www | |
| He provocado un error de sintaxis y comprobado que NO rompe el sistema | |
| Rollback con --rollback y comprobado vuelta al estado previo | |
| nix-shell probado con paquetes ad hoc | |
| shell.nix propio creado | |
| Ficha técnica completa con tu configuration.nix | |
| Reto: GNOME instalado declarativamente |
¿En qué tipo de equipo o servidor te imaginas usando NixOS en serio? ¿Y dónde claramente lo descartarías?