Problema

En entornos de virtualización con Proxmox es frecuente montar un recurso NFS y ejecutar contenedores LXC (o Docker dentro de ellos) para servicios multimedia como Jellyfin o Emby. Cuando el contenedor no puede acceder al directorio de configuración alojado en NFS, el proceso se detiene con errores de permission denied o cannot open config file. Al mismo tiempo, tras cambiar el layout de almacenamiento (añadir volúmenes LVM, mover LV, etc.) el host Proxmox puede quedar atrapado en la fase de arranque: muestra los mensajes de LVM y luego queda con una pantalla negra sin login, obligando a un apagado forzado.

El patrón que se repite es:

  1. Montaje NFS con opciones por defecto → UID/GID del cliente no coinciden con los del host.
  2. Contenedores LXC que usan unprivileged UID mapping (100000‑…​) pero el recurso NFS pertenece a un UID/GID diferente.
  3. Cambios en LVM (añadir LV, cambiar nombres) sin actualizar el initramfs o los scripts de arranque, provocando que el volume group pve no se active correctamente.

El resultado es que cualquier aplicación que dependa de archivos en NFS (Emby, Plex, etc.) no arranca, y el propio Proxmox puede quedar inestable al reiniciar.

Causa

1. Mapeo de UID/GID en LXC vs. NFS

Los contenedores unprivileged usan un rango de UID/GID (por defecto 100000‑165535). Cuando el host monta un NFS exportado con UID/GID reales (por ejemplo, 1000 para el usuario media), el contenedor ve esos IDs como 1000, pero internamente los traduce a 101000, 101001, etc. Si el export no permite el root squashing o no está configurado con no_subtree_check,fsid=0, el contenedor termina intentando leer como UID 101000, que no existe en el servidor NFS → error de permisos.

2. Opciones de montaje NFS inadecuadas

Montajes sin nolock, noacl o vers=3 pueden activar mecanismos de bloqueo que el kernel del contenedor no soporta, generando fallos intermitentes. Además, la opción uid=/gid= solo funciona con NFSv4 y solo si el servidor exporta los IDs numéricos.

3. Inconsistencias en LVM después de cambios

Proxmox usa un volume group llamado pve. Cuando se crean o renombran LV sin actualizar /etc/fstab o sin regenerar el initramfs, el initramfs intenta activar pve con metadatos desactualizados. El mensaje “/dev/mapper/pve-root: clean…” aparece, pero el systemd nunca llega al login porque el root filesystem está montado en modo read‑only o el swap falla, dejando la consola sin prompt.

4. Configuración de privileged vs. unprivileged

Marcar el contenedor como privileged elimina el mapeo de UID, pero rompe la seguridad del modelo LXC y, en algunos casos, hace que el kernel del host impida el acceso a NFS por políticas de root_squash.

Solución

Paso 1 – Normalizar el export NFS

En el servidor NFS, edita /etc/exports para que el export sea accesible por el rango de UID/GID que usa Proxmox:

# Ejemplo de export para /srv/media
/srv/media 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash,fsid=0,anonuid=100000,anongid=100000)
  • no_root_squash permite que el UID 0 del cliente sea tratado como 0 en el servidor.
  • anonuid/anongid asignan un UID/GID “anónimo” que coincide con el rango de mapeo de LXC (100000‑…​).
  • Reinicia NFS: systemctl restart nfs-server.

Paso 2 – Montar NFS con opciones compatibles

En el host Proxmox, añade o corrige la línea en /etc/fstab:

192.168.1.10:/srv/media /mnt/media nfs4 rw,vers=4,hard,intr,noacl 0 0
  • vers=4 permite usar anonuid/anongid.
  • noacl evita que ACLs del servidor bloqueen al contenedor.
  • hard,intr garantiza que los procesos esperen a que el servidor responda.

Ejecuta mount -a y verifica con ls -l /mnt/media que los archivos aparecen con UID/GID 100000.

Paso 3 – Ajustar la configuración del LXC

Edita el archivo de configuración del contenedor (/etc/pve/lxc/<ID>.conf):

# Desactivar mapeo si decides usar privileged (no recomendado)
# lxc.idmap = u 0 0 65536
# lxc.idmap = g 0 0 65536

# Si mantienes unprivileged, asegura que el rango coincida
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536

Si el contenedor necesita acceso directo al NFS sin mapeo, cambia unprivileged: 0 a unprivileged: 1 y vuelve a crear el contenedor con pct create. En la mayoría de los casos, mantener el mapeo y usar los anonuid/anongid del paso 1 es suficiente.

Paso 4 – Reparar LVM y el initramfs

  1. Verifica la integridad del VG

    vgscan --mknodes
    vgchange -ay pve
    
  2. Actualiza /etc/fstab si algún LV cambió de nombre o UUID. Usa blkid para obtener los nuevos UUID y reemplázalos.

  3. Regenera el initramfs para que incluya la información actual de LVM:

    update-initramfs -u -k all
    
  4. Revisa los logs de arranque (journalctl -b -1) para detectar fallos de lvm2-monitor o systemd-modules-load.

Paso 5 – Probar el contenedor

Reinicia el contenedor y verifica que el servicio (Emby, Jellyfin, etc.) arranca:

pct start <ID>
pct exec <ID> -- systemctl status emby-server

Si sigue fallando, revisa los permisos dentro del contenedor:

pct exec <ID> -- ls -l /path/to/config

Los archivos deben pertenecer a UID 100000 (o al UID que hayas mapeado).

Cuándo aplicar esta solución

  • Síntomas de permisos: contenedor muestra Permission denied al leer archivos en NFS, o Docker dentro del LXC no levanta.
  • Arranque bloqueado: Proxmox muestra mensajes de LVM y luego pantalla negra sin login.
  • Cambios recientes en almacenamiento: creación/renombrado de LV, migración de discos, o adición de export NFS.
  • No aplica: si el servidor NFS es Windows (SMB) o si usas ZFS como backend en Proxmox, pues el modelo de UID/GID difiere.

Código

# 1. Export NFS con anonuid/anongid
cat <<EOF >> /etc/exports
/srv/media 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash,fsid=0,anonuid=100000,anongid=100000)
EOF
exportfs -ra
systemctl restart nfs-server

# 2. Montar NFS en Proxmox
cat <<EOF >> /etc/fstab
192.168.1.10:/srv/media /mnt/media nfs4 rw,vers=4,hard,intr,noacl 0 0
EOF
mount -a

# 3. Ajustar LXC idmap (ejemplo para ID 101)
cat > /etc/pve/lxc/101.conf <<EOF
arch: amd64
cores: 2
memory: 4096
net0: name=eth0,bridge=vmbr0,ip=dhcp
rootfs: local-lvm:vm-101-disk-0,size=20G
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
mountpoint: /mnt/media,mp0=/mnt/media,mp=/media,ro=0
EOF

# 4. Regenerar initramfs y activar VG
vgscan --mknodes
vgchange -ay pve
update-initramfs -u -k all
reboot

Verificación

  1. NFS: showmount -e <server> y mount | grep /mnt/media. ls -l /mnt/media debe mostrar UID/GID 100000.
  2. LXC: pct exec <ID> -- id debe devolver uid=0(root) gid=0(root) groups=0(root). Dentro del contenedor, stat -c %u /media debe ser 100000.
  3. Servicio: pct exec <ID> -- systemctl is-active emby-serveractive.
  4. Boot: Después del reboot, systemctl status pve-cluster y journalctl -b | grep pve-root deben indicar que el root FS está montado rw y sin errores.

Notas adicionales

  • ACLs: Si el servidor NFS necesita ACLs, habilítalas tanto en el export (no_aclacl) como en el cliente (nfs4,acl). Pero verifica que el kernel del contenedor tenga el módulo fsacl cargado.
  • UID/GID estáticos: En entornos con muchos contenedores, considera reservar rangos de UID/GID por contenedor para evitar colisiones.
  • Snapshots: Antes de tocar LVM, crea un snapshot del LV raíz (lvcreate -s -n pve-root-snap -L 1G pve/root) para poder volver atrás si algo falla.
  • Monitor de arranque: Si el host sigue sin llegar al login, habilita systemd.debug-shell en el kernel (GRUB_CMDLINE_LINUX="systemd.debug-shell"), reinicia y accede con Ctrl+Alt+F9 para inspeccionar el estado del VG.