Páginas

Mostrando entradas con la etiqueta mount. Mostrar todas las entradas
Mostrando entradas con la etiqueta mount. Mostrar todas las entradas

sábado, 3 de octubre de 2026

Backup Manual y Recuperación

FreeBSD 14.5

ZFS FreeBSD Copia de seguridad del servidor tormenta
ZFS FreeBSD Copia de seguridad del cliente solaris

Sistema: solaris y tormenta (FreeBSD 14.5)
Método: Backup manual a disco USB (Modelo B — USB guardado fuera)
Fecha: 2026-10-03

1. Introducción y filosofía

Este documento describe el sistema de backup manual a disco USB implementado en solaris y tormenta. Está diseñado para:

  • Ejecutarse manualmente cuando se conecta el disco USB.
  • Mantener los USB guardados fuera de las máquinas para protección ante ransomware y desastres locales.
  • Ser recuperable tanto para archivos individuales como para el sistema completo.
Filosofía del Modelo B: los USB no están conectados permanentemente. Se conectan solo cuando se va a hacer el backup, y después se guardan en otro lugar. Esto protege contra:
  • Ransomware que cifraría también el USB conectado.
  • Robo o incendio que afectaría a máquina y backup a la vez.
  • Errores humanos que borrarían el backup por accidente.

Estado del sistema

Elementosolaristormenta
Pool origenzrootzroot
Pool destino (USB)zbackupzbk
Dataset destinozbackup/recovery/solariszbk/tormenta
Etiqueta USBZFSBACKUPbackup1tb
Tamaño del pool origen~220 GB~312 GB
Script/root/bin/zfs-backup.sh/root/bin/zfs-backup.sh
Log/var/log/zfs-backup.log/var/log/zfs-backup.log
Retención origen7 snapshots7 snapshots
Retención destino30 snapshots30 snapshots

2. El script zfs-backup.sh

Script único que funciona en ambas máquinas, detectando automáticamente el hostname. Versión 2.4.

Ubicación

/root/bin/zfs-backup.sh

Contenido completo

#!/bin/sh
# zfs-backup.sh - Backup incremental de zroot a pool USB
# Versión: 2.4 (snapshot por dataset + export en error)
# Uso: sh /root/bin/zfs-backup.sh

set -e

# ========== CONFIGURACIÓN SEGÚN MÁQUINA ==========
HOSTNAME=$(hostname -s)
case "$HOSTNAME" in
    solaris)
        SRC_POOL="zroot"
        DST_POOL="zbackup"
        DST_DATASET="zbackup/recovery/solaris"
        USB_DEV="/dev/gpt/ZFSBACKUP"
        RETENTION_SRC=7
        RETENTION_DST=30
        ;;
    tormenta)
        SRC_POOL="zroot"
        DST_POOL="zbk"
        DST_DATASET="zbk/tormenta"
        USB_DEV="/dev/gpt/backup1tb"
        RETENTION_SRC=7
        RETENTION_DST=30
        ;;
    *)
        echo "Hostname no reconocido: $HOSTNAME" >&2
        exit 1
        ;;
esac

SNAP_PREFIX="snap"
SNAP_TODAY="${SNAP_PREFIX}-$(date +%Y%m%d)"
LOG="/var/log/zfs-backup.log"
LOCKFILE="/var/run/zfs-backup.lock"

# ========== VARIABLES DE ESTADO ==========
IMPORTED_BY_US=0

# ========== FUNCIONES ==========
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG"
}

die() {
    log "ERROR: $*"
    if [ "${IMPORTED_BY_US:-0}" -eq 1 ]; then
        log "Exportando pool $DST_POOL antes de salir..."
        zpool export "$DST_POOL" >> "$LOG" 2>&1 || log "Aviso: no se pudo exportar"
    fi
    rm -f "$LOCKFILE"
    exit 1
}

# ========== BLOQUEO ==========
if [ -f "$LOCKFILE" ]; then
    PID=$(cat "$LOCKFILE" 2>/dev/null)
    if kill -0 "$PID" 2>/dev/null; then
        echo "Ya hay una ejecución en curso (PID $PID)"
        exit 0
    fi
    rm -f "$LOCKFILE"
fi
echo $$ > "$LOCKFILE"

log "=========================================="
log "Iniciando backup en $HOSTNAME"
log "=========================================="

# ========== VERIFICAR POOL USB ==========
if ! zpool list "$DST_POOL" >/dev/null 2>&1; then
    log "Pool $DST_POOL no está importado. Intentando importar..."
    if [ ! -e "$USB_DEV" ]; then
        die "Disco USB $USB_DEV no encontrado. ¿Está conectado?"
    fi
    if ! zpool import "$DST_POOL" 2>>"$LOG"; then
        die "No se pudo importar el pool $DST_POOL"
    fi
    log "Pool $DST_POOL importado correctamente"
    IMPORTED_BY_US=1
else
    log "Pool $DST_POOL ya estaba importado"
    IMPORTED_BY_US=0
fi

# ========== CREAR SNAPSHOT DE HOY (dataset por dataset) ==========
log "Creando snapshot $SNAP_TODAY en todos los datasets (los que falten)..."

CREATED=0
SKIPPED=0
FAILED=0
for ds in $(zfs list -H -o name -r "$SRC_POOL" 2>/dev/null); do
    if zfs list -t snapshot "$ds@$SNAP_TODAY" >/dev/null 2>&1; then
        SKIPPED=$((SKIPPED + 1))
    else
        if zfs snapshot "$ds@$SNAP_TODAY" >> "$LOG" 2>&1; then
            CREATED=$((CREATED + 1))
        else
            log "  → error al crear $ds@$SNAP_TODAY"
            FAILED=$((FAILED + 1))
        fi
    fi
done
log "Snapshots: creados=$CREATED, ya existían=$SKIPPED, fallos=$FAILED"

if [ "$FAILED" -gt 0 ]; then
    log "AVISO: hubo $FAILED fallos al crear snapshots (se continúa)"
fi

# ========== DETECTAR ÚLTIMA SNAPSHOT EN DESTINO ==========
LAST_DST_SNAP=$(zfs list -t snapshot -H -o name -r "$DST_DATASET" 2>/dev/null \
    | grep '@snap-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$' \
    | sort -r \
    | head -1 \
    | sed 's/.*@//')

if [ -z "$LAST_DST_SNAP" ]; then
    log "No hay snapshots previas en destino. Envío COMPLETO."
    zfs send -Rwcv "$SRC_POOL@$SNAP_TODAY" \
        | zfs receive -Fsuv -x mountpoint "$DST_DATASET" >> "$LOG" 2>&1 \
        || die "Error en el envío completo"

elif [ "$LAST_DST_SNAP" = "$SNAP_TODAY" ]; then
    log "Última snapshot en destino: $LAST_DST_SNAP"
    log "La snapshot $SNAP_TODAY ya está replicada. Nada que enviar."

elif ! zfs list -t snapshot "$SRC_POOL@$LAST_DST_SNAP" >/dev/null 2>&1; then
    log "AVISO: $LAST_DST_SNAP no existe en origen. Envío COMPLETO."
    zfs send -Rwcv "$SRC_POOL@$SNAP_TODAY" \
        | zfs receive -Fsuv -x mountpoint "$DST_DATASET" >> "$LOG" 2>&1 \
        || die "Error en el envío completo"

else
    log "Enviando incremental desde $LAST_DST_SNAP hasta $SNAP_TODAY"
    zfs send -Rwcv -i "$SRC_POOL@$LAST_DST_SNAP" "$SRC_POOL@$SNAP_TODAY" \
        | zfs receive -Fsuv -x mountpoint "$DST_DATASET" >> "$LOG" 2>&1 \
        || die "Error en el envío incremental"
fi

log "Envío completado correctamente"

# ========== FUNCIÓN DE RETENCIÓN ==========
apply_retention() {
    local root="$1"
    local label="$2"
    local ret="$3"

    log "Aplicando retención de $ret snapshots en $label..."

    zfs list -t snapshot -H -o name -r "$root" 2>/dev/null \
        | grep '@snap-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$' \
        | sort -t@ -k1,1 -k2,2r \
        | awk -F@ -v r="$ret" '
            {
                ds = $1
                if (ds != prev_ds) { count = 0; prev_ds = ds }
                count++
                if (count > r) print $0
            }' \
        | while read snap; do
            log "Borrando $snap"
            zfs destroy "$snap" >> "$LOG" 2>&1 || log "  → error al borrar"
        done

    log "Retención en $label aplicada"
}

# ========== RETENCIÓN EN DESTINO (30 snapshots) ==========
apply_retention "$DST_DATASET" "destino" "$RETENTION_DST"

# ========== RETENCIÓN EN ORIGEN (7 snapshots) ==========
apply_retention "$SRC_POOL" "origen" "$RETENTION_SRC"

# ========== EXPORTAR POOL ==========
if [ "$IMPORTED_BY_US" -eq 1 ]; then
    log "Exportando pool $DST_POOL"
    zpool export "$DST_POOL" >> "$LOG" 2>&1 || log "Aviso: no se pudo exportar"
    log "Ya puedes desconectar el USB de forma segura"
fi

log "Backup completado con éxito"
log "=========================================="
rm -f "$LOCKFILE"

Características clave

ElementoDescripción
Detección automáticaUsa el hostname para elegir el pool y dataset correctos
Snapshot dataset por datasetEvita el fallo atómico de zfs snapshot -r
Detección de sincronizaciónSi ya está todo replicado, no envía nada
Incremental automáticoDetecta la última snapshot en destino y envía solo diferencias
Fallback a full sendSi no hay base común, hace envío completo automáticamente
Retención independiente7 snapshots en origen, 30 en destino
Export automáticoSi el script importó el USB, lo exporta al terminar
Logging completoTodo se registra en /var/log/zfs-backup.log
LockfileEvita ejecuciones simultáneas

3. Ejecución manual paso a paso

Cuándo ejecutar: semanalmente (recomendado domingo por la tarde), o siempre que haya cambios importantes que se quieran respaldar.

Paso 1 — Conectar el USB

Conectar el disco USB (ZFSBACKUP en solaris, backup1tb en tormenta) a la máquina correspondiente. Esperar unos segundos a que el sistema lo detecte.

ls -la /dev/gpt/ZFSBACKUP    # En solaris
ls -la /dev/gpt/backup1tb    # En tormenta

Debe aparecer el device node. Si no aparece, probar con otro puerto USB o revisar dmesg:

dmesg | tail -20

Paso 2 — Ejecutar el script

sh /root/bin/zfs-backup.sh
Importante: NO ejecutar el script si no se está seguro de que el USB está conectado. Si no lo está, el script fallará limpiamente sin tocar nada.

Paso 3 — Verificar el resultado

tail -30 /var/log/zfs-backup.log

Debe verse al final:

[XX:XX:XX] Backup completado con éxito
[XX:XX:XX] ==========================================

Paso 4 — Desconectar el USB

Si el script importó el pool, lo habrá exportado automáticamente. Se verá en el log:

[XX:XX:XX] Ya se puede desconectar el USB de forma segura

Verificar que el pool está exportado:

zpool list

El pool de backup (zbackup o zbk) no debe aparecer en la lista. Si aparece, exportarlo manualmente antes de desconectar:

zpool export zbackup    # En solaris
zpool export zbk        # En tormenta

sync

Paso 5 — Guardar el USB en lugar seguro

Una vez exportado y sincronizado, se puede retirar el cable USB y guardarlo donde corresponda (fuera de casa, caja fuerte, casa de un familiar, etc.).

¡Backup completado! El proceso completo tarda típicamente entre 1 y 15 minutos dependiendo de cuántos datos hayan cambiado desde el último backup.

4. Interpretación del log

Ejemplo de ejecución exitosa (con cambios)

[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Iniciando backup en solaris
[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Pool zbackup no está importado. Intentando importar...
[2026-10-03 18:30:02] Pool zbackup importado correctamente
[2026-10-03 18:30:02] Creando snapshot snap-20261003 en todos los datasets (los que falten)...
[2026-10-03 18:30:02] Snapshots: creados=18, ya existían=0, fallos=0
[2026-10-03 18:30:03] Última snapshot en destino: snap-20261002
[2026-10-03 18:30:03] Enviando incremental desde snap-20261002 hasta snap-20261003
[2026-10-03 18:32:15] Envío completado correctamente
[2026-10-03 18:32:15] Aplicando retención de 30 snapshots en destino...
[2026-10-03 18:32:15] Retención en destino aplicada
[2026-10-03 18:32:15] Aplicando retención de 7 snapshots en origen...
[2026-10-03 18:32:15] Retención en origen aplicada
[2026-10-03 18:32:15] Exportando pool zbackup
[2026-10-03 18:32:16] Ya puedes desconectar el USB de forma segura
[2026-10-03 18:32:16] Backup completado con éxito
[2026-10-03 18:32:16] ==========================================

Ejemplo de ejecución sin cambios

[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Iniciando backup en solaris
[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Pool zbackup ya estaba importado
[2026-10-03 18:30:00] Creando snapshot snap-20261003 en todos los datasets (los que falten)...
[2026-10-03 18:30:00] Snapshots: creados=18, ya existían=0, fallos=0
[2026-10-03 18:30:00] Última snapshot en destino: snap-20261003
[2026-10-03 18:30:00] La snapshot snap-20261003 ya está replicada. Nada que enviar.
[2026-10-03 18:30:00] Envío completado correctamente
[2026-10-03 18:30:00] Aplicando retención de 30 snapshots en destino...
[2026-10-03 18:30:00] Retención en destino aplicada
[2026-10-03 18:30:00] Aplicando retención de 7 snapshots en origen...
[2026-10-03 18:30:00] Retención en origen aplicada
[2026-10-03 18:30:00] Backup completado con éxito
[2026-10-03 18:30:00] ==========================================

Ejemplo de error (USB no conectado)

[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Iniciando backup en solaris
[2026-10-03 18:30:00] ==========================================
[2026-10-03 18:30:00] Pool zbackup no está importado. Intentando importar...
[2026-10-03 18:30:00] ERROR: Disco USB /dev/gpt/ZFSBACKUP no encontrado. ¿Está conectado?
Este error es normal si se ejecuta el script sin el USB conectado. No corrompe nada. Simplemente conectar el USB y volver a ejecutar.

5. Política de retención

El script aplica automáticamente dos políticas distintas:

UbicaciónSnapshots conservadosRazón
Origen (zroot)7Liberar espacio en el NVMe. Solo se necesitan los últimos días para incrementales.
Destino (USB)30Histórico más largo. El USB tiene más espacio y es el "archivo".

Ajustar la retención

Si se quieren cambiar los valores, editar el script:

ee /root/bin/zfs-backup.sh

Buscar las líneas:

RETENTION_SRC=7
RETENTION_DST=30

Y modifícalas a los valores se preferencia. Por ejemplo, para guardar más histórico en el USB:

RETENTION_SRC=7
RETENTION_DST=60
Espacio: cada snapshot diaria ocupa entre 50 MB y varios GB según lo que cambie. Con 30 snapshots en destino, asegurarse de que el USB tiene espacio suficiente (consultar con zpool list).

6. Recuperación de archivos individuales

Escenario: se ha borrado un archivo por error o se quiere recuperar una versión anterior de algo.

Paso 1 — Conectar el USB y localizar el snapshot

# Conectar el USB de backup
zpool import zbackup        # En solaris
zpool import zbk            # En tormenta

# Ver snapshots disponibles
zfs list -t snapshot -r zbackup/recovery/solaris | grep 'snap-2026'

Paso 2 — Montar el snapshot en un punto temporal

mkdir -p /mnt/snap
mount -t zfs zbackup/recovery/solaris/home/carlos@snap-20261002 /mnt/snap

Ahora /mnt/snap contiene el contenido de /home/carlos tal como estaba en esa fecha.

Paso 3 — Buscar y copiar el archivo

# Ver qué hay
ls -la /mnt/snap/

# Copiar el archivo deseado
cp /mnt/snap/documento.txt /home/carlos/documento_recuperado.txt

Paso 4 — Desmontar y exportar

umount /mnt/snap
rmdir /mnt/snap

zpool export zbackup        # En solaris
zpool export zbk            # En tormenta

sync
Ventaja sobre el método .gz: con el backup ZFS solo montas el snapshot y accedes a los archivos directamente. No hay que descomprimir 300 GB para sacar un documento.

7. Recuperación completa del sistema

Escenario: el NVMe del sistema ha fallado o necesitas reinstalar FreeBSD desde cero.

ATENCIÓN: Este procedimiento borra todo el contenido del disco actual. Asegurarse de tener el backup antes de empezar.

Paso 1 — Arrancar desde USB de FreeBSD

Insertar el USB de instalación, arrancar la máquina desde él, y elegir "Shell" en lugar de instalar.

Paso 2 — Identificar discos

geom disk list
camcontrol devlist

Paso 3 — Preparar el disco destino

gpart destroy -F nda0
gpart create -s gpt nda0
gpart add -t efi -a 1m -s 260m -l EFI nda0
gpart add -t freebsd-boot -a 1m -s 512k -l BOOT nda0
gpart add -t freebsd-swap -a 1m -s 16g -l SWAP nda0
gpart add -t freebsd-zfs -a 1m -l ZFS nda0
newfs_msdos -F 32 -c 1 /dev/nda0p1

Paso 4 — Crear el pool zroot

zpool create -o ashift=12 \
             -O compression=lz4 \
             -O atime=off \
             -O mountpoint=none \
             -R /mnt \
             zroot /dev/gpt/ZFS

Paso 5 — Importar el USB de backup

zpool import zbackup        # En solaris
zpool import zbk            # En tormenta

Paso 6 — Restaurar el sistema

zfs send -Rwcv zbackup/recovery/solaris@snap-20261003 \
    | zfs receive -Fduv zroot

Paso 7 — Configurar el bootfs

zpool set bootfs=zroot/ROOT/default zroot
zpool get bootfs zroot

Paso 8 — Copiar el cargador UEFI

mkdir -p /mnt2
mount_msdosfs /dev/nda0p1 /mnt2
mkdir -p /mnt2/efi/boot
cp /mnt/zroot/ROOT/default/boot/loader.efi /mnt2/efi/boot/bootx64.efi
umount /mnt2
rmdir /mnt2

Paso 9 — Ajustar propiedades de montaje

zfs set mountpoint=/ zroot/ROOT/default
zfs set mountpoint=/home zroot/home
zfs set mountpoint=/usr zroot/usr
zfs set mountpoint=/var zroot/var
zfs set mountpoint=/tmp zroot/tmp

zpool set altroot= zroot
zpool set cachefile=/boot/zfs/zpool.cache zroot

Paso 10 — Exportar y reiniciar

zpool export zbackup
zpool export zbk

reboot

Paso 11 — Verificar

freebsd-version
zpool status zroot
zfs list -r zroot | head -20

8. Recuperación del dataset cifrado

El dataset zroot/nfsv4/secifrado en tormenta está cifrado con ZFS native encryption.

Guardar la clave en al menos 3 sitios distintos:
  • Gestor de contraseñas (Bitwarden, KeePass, etc.).
  • Papel en caja fuerte.
  • USB de emergencia separado del USB de backup.

Ver el contenido de la clave

base64 /etc/zfs/secifrado.key

Restaurar la clave

echo 'TU_CLAVE_EN_BASE64' | base64 -d > /etc/zfs/secifrado.key
chmod 400 /etc/zfs/secifrado.key
chown root:wheel /etc/zfs/secifrado.key
ls -la /etc/zfs/secifrado.key

Montar el dataset cifrado

zfs mount zroot/nfsv4/secifrado
ls -la /nfsv4/secifrado/
Recomendación: una vez al año, haz una prueba real de recuperación del dataset cifrado en una máquina de prueba.

9. Checklist y rutinas

Rutina semanal (domingo)

  • [ ] Conectar USB ZFSBACKUP a solaris
  • [ ] Ejecutar sh /root/bin/zfs-backup.sh
  • [ ] Verificar log: tail -20 /var/log/zfs-backup.log
  • [ ] Confirmar "Backup completado con éxito"
  • [ ] Desconectar USB y guardarlo en lugar seguro
  • [ ] Repetir con USB backup1tb en tormenta

Rutina mensual

  • [ ] Verificar snapshots recientes en los USB
  • [ ] Comprobar espacio disponible: zpool list
  • [ ] Revisar el log en busca de errores: grep "ERROR" /var/log/zfs-backup.log

Rutina semestral

  • [ ] Prueba de restauración de un archivo aleatorio.
  • [ ] Verificar integridad del pool USB: zpool scrub zbackup
  • [ ] Comprobar que las claves de cifrado siguen accesibles.

Apéndice A — Comandos útiles

Ver estado de los pools

zpool list
zpool status
zpool status -v

Ver snapshots

# Todos los snapshots del pool
zfs list -t snapshot -r zroot

# Solo los snapshots diarios (formato snap-YYYYMMDD)
zfs list -t snapshot -r zroot | grep 'snap-2026'

# Contar snapshots por dataset
zfs list -t snapshot -r zroot | awk -F@ '{print $1}' | sort | uniq -c

Comprobar integridad

zpool scrub zroot
zpool scrub zbackup
zpool status

Ver procesos de backup en curso

ps aux | grep -E "zfs (send|receive)" | grep -v grep
tmux ls

Reconectar a una sesión tmux

tmux attach -t backup_usb

Apéndice B — Solución de problemas

Error: "Pool zbackup no está importado"

ls -la /dev/gpt/ZFSBACKUP
zpool import zbackup
sh /root/bin/zfs-backup.sh

Error: "cannot create snapshot ... dataset already exists"

Causa: alguno de los datasets ya tiene la snapshot de hoy. La versión 2.4 del script ya maneja esto dataset por dataset.

Error: "cannot send ... encrypted dataset"

Causa: falta el flag -w en zfs send.

Solución: usar -Rwcv en lugar de -Rcv.

El USB no se puede exportar (pool is busy)

lsof | grep zbackup
fuser -m /zbackup

zfs unmount -a
zpool export -f zbackup

Backup incompleto o corrupto

zpool scrub zbackup
zpool status zbackup

Apéndice C — Glosario

TérminoSignificado
PoolConjunto de discos gestionados por ZFS como una unidad
DatasetSistema de archivos dentro de un pool
SnapshotImagen inmutable de un dataset en un momento concreto
Full sendEnvío completo de un dataset a otro pool
Incremental sendEnvío solo de los cambios desde una snapshot base
RetenciónNúmero de snapshots que se conservan antes de borrar las más antiguas
ashiftTamaño de sector usado por ZFS (12 = 4096 bytes)
-w (raw)Envío de bloques cifrados sin descifrar
BEBoot Environment — entorno de arranque de FreeBSD
tmux

Multiplexor de terminal (permite sesiones persistentes)

 

FreeBSD es genial!.

Realizar copia de seguridad del cliente solaris en disco USB

ZFS FreeBSD Copia de seguridad del servidor tormenta
Backup Manual y Recuperación

FreeBSD14.5

1. Identificar discos

geom disk list
camcontrol devlist
gpart show

En solaris, el disco USB suele aparecer como da0 o da1. Verificar con geom disk list cuál es el correcto (etiqueta ZFSBACKUP).

2. Comprobaciones previas (antes de destruir nada)

¿Tiene particiones?

gpart show da0

¿Tiene restos de ZFS?

zpool import | grep -B2 -A5 da0

¿Está montado en algún sitio?

mount | grep da0

3. Plan resumido

ComandoQué hace
gpart destroy -F da0Borra particiones
zpool labelclear -f /dev/da0Borra restos ZFS
gpart create -s gpt da0Tabla GPT nueva
gpart add -t freebsd-zfs -l ZFSBACKUP da0Partición ZFS
zpool create -o ashift=12 ... zbackup /dev/gpt/ZFSBACKUPPool zbackup
zfs create -o mountpoint=none zbackup/recovery/solarisDataset destino
zfs snapshot -r zroot@snap-$(date +%Y%m%d)Snapshot del sistema
zfs send -Rwcv ... | zfs receive -Fsuv ...Envío local (en tmux)
zpool export zbackupCerrar limpiamente

4. Preparar el disco

gpart destroy -F da0
# → da0 destroyed

Borrar cualquier resto de ZFS (aunque no haya, por asegurar)

zpool labelclear -f /dev/da0 2>/dev/null

Crear tabla GPT nueva

gpart create -s gpt da0
# → da0 created

Crear partición ZFS ocupando todo el disco

gpart add -t freebsd-zfs -l ZFSBACKUP da0
# → da0p1 added

Verificar

gpart show da0
# →       40  3907029088  da0  GPT  (2T)
# →       40  3907029088    1  freebsd-zfs  (2T)

5. Crear el pool zbackup

Los discos modernos suelen tener sectores de 4K, pero muchos discos USB reportan 512B. Es crítico crear el pool con ashift=12 (4096 bytes) para evitar problemas de rendimiento.

Ver ashift que ZFS detectaría por defecto

diskinfo -v da0 | grep -i "sector size"

Si dice 512, hay que forzar ashift=12 al crear el pool.

zpool create -o ashift=12 \
             -O compression=lz4 \
             -O atime=off \
             -O xattr=sa \
             -O relatime=on \
             -O mountpoint=none \
             zbackup /dev/gpt/ZFSBACKUP

Banderas

  • ashift=12 → sectores 4K (crítico para rendimiento en discos modernos).
  • compression=lz4 → compresión ligera y rápida.
  • atime=off → no actualizar tiempo de acceso (más rápido).
  • xattr=sa → atributos extendidos en el inodo.
  • relatime=on → atime solo cuando sea útil.
  • mountpoint=none → no montar automáticamente.

Verificar

zpool status zbackup
zpool list zbackup
zfs list

Crear dataset destino

zfs create -o mountpoint=none zbackup/recovery
zfs create -o mountpoint=none zbackup/recovery/solaris
zfs list -r zbackup

Salida esperada:

zbackup                     XXXG   XXXG    96K  none
zbackup/recovery            XXXG   XXXG    96K  none
zbackup/recovery/solaris    XXXG   XXXG    96K  none

Pool zbackup creado correctamente:

DatoValor
Poolzbackup
Tamaño~2 TB
Dataset destinozbackup/recovery/solaris (listo)
zroot a respaldar~220 G

6. Crear snapshot del sistema

zfs snapshot -r zroot@snap-$(date +%Y%m%d)

Verificar

zfs list -t snapshot -r zroot | grep snap-$(date +%Y%m%d) | wc -l

El resultado depende del número de datasets del sistema. En solaris actual: ~30.

Nota para el futuro: si un script creó el snapshot en un solo dataset sin usar -r, o si otro proceso lo creó antes para otro propósito, puede haber conflictos. Cuando se monte el cron para backups automáticos, usar date +%Y%m%d-%H%M%S para evitar colisiones si se ejecuta dos veces el mismo día.
zfs snapshot -r zroot@snap-$(date +%Y%m%d-%H%M%S)

7. Lanzar el envío en tmux

Entrar en tmux

tmux new -s backup_usb

Comando de envío (dentro de tmux)

zfs send -Rwcv zroot@snap-$(date +%Y%m%d) \
  | zfs receive -Fsuv -x mountpoint zbackup/recovery/solaris

Banderas explicadas

FlagSignificado
-RRecursivo: envía zroot y todos sus hijos
-wRaw: envía los bloques cifrados tal cual (necesario si hay datasets cifrados)
-cCompresión nativa ZFS (lz4)
-vVerbose: muestra progreso por dataset
-FFuerza rollback en destino si hay divergencias
-sGuarda token de resume en /var/tmp/ (permite reanudar si se corta)
-uNo monta los datasets recibidos
-x mountpointNo replica los mountpoints del origen
Importante sobre -w: aunque solaris no tiene datasets cifrados actualmente, el -w es inofensivo si no hay cifrado. Mantener el mismo script/comando que en tormenta para consistencia y por si en el futuro se añade cifrado.

8. Salir de tmux sin matar el proceso

Ctrl+b  d

9. Monitorizar (en otra terminal)

Ver datasets llegando en tiempo real

watch -n 10 'zfs list -r zbackup/recovery/solaris | head -30'

Ver velocidad de escritura al USB

zpool iostat zbackup 5

Ver espacio consumido

watch -n 30 'zfs list zbackup'

10. Verificar tras el envío

Volver a la sesión tmux

tmux attach -t backup_usb

Si ya terminó, se verá el real Xm Ys del comando. Entonces:

Contar snapshots origen vs destino

zfs list -t snapshot -r zroot | wc -l
zfs list -t snapshot -r zbackup/recovery/solaris | wc -l

Deben coincidir.

Verificar datasets replicados

zfs list -r zbackup/recovery/solaris | head -30

Espacio usado

zfs list zbackup
zpool list zbackup

11. Si algo falla durante el envío

¿Sigue algún proceso zfs vivo?

ps aux | grep -E "zfs (send|receive)" | grep -v grep

Si aparece algo, sigue corriendo. Esperar y dejarlo terminar.

¿En qué estado está el destino?

zfs list zbackup
zfs list -r zbackup/recovery/solaris | head -20

Se verá si quedó un dataset a medias (zbackup/recovery/solaris con datos parciales).

¿Hay un token de resume guardado?

ls -la /var/tmp/ | grep -i zfs
ls -la / | grep -i zfs
El token de resume solo existe si se usó -s en el zfs receive. Si no se usó, no hay reanudación posible: hay que empezar de cero.

¿El proceso murió? Limpiar el destino parcial

zfs destroy -r zbackup/recovery/solaris
zfs create -o mountpoint=none zbackup/recovery/solaris
zfs list -r zbackup/recovery

Relanzar con -s para permitir resume

tmux new -s backup_usb

Dentro de tmux:

zfs send -Rwcv zroot@snap-20261002 \
  | zfs receive -Fsuv -x mountpoint zbackup/recovery/solaris
El flag -s en zfs receive guarda un token de reanudación en /var/tmp/. Si se vuelve a cortar, se podrá reanudar con:
zfs send -t $(ls /var/tmp/zfs_*.resume 2>/dev/null | head -1)

Salir de tmux con Ctrl+b d antes de cerrar SSH. No cerrar la sesión SSH hasta que tmux esté desconectado.

12. Exportar el pool y desconectar el USB

Verificar que no hay nada escribiendo

zpool status zbackup
lsof | grep zbackup 2>/dev/null

Exportar limpiamente

zpool export zbackup

Y por último

sync

Ya se puede retirar el cable USB.

13. Tiempo estimado

Velocidad USB~220 GB
80 MB/s~45 min
120 MB/s~30 min
200 MB/s~18 min
400 MB/s~9 min

Con el chip ASMT USB 3.0 + disco SATA: ~15-30 min si es SSD, ~40-60 min si es HDD.

Recordatorio: para poder cerrar la sesión SSH sin que se corte el envío, primero entrar en tmux con tmux new -s backup_usb, lanzar el envío, y salir con Ctrl+b d.
Recomendación adicional: poner una etiqueta al disco físico con rotulador o adhesivo:
  • Backup Solaris
  • snap-20261002
  • zbackup pool

14. Restaurar archivos de configuración

No requiere reiniciar. Solo copia los archivos desde el snapshot.

Paso 1: Montar el snapshot

mkdir -p /mnt/snap
mount -t zfs zroot/ROOT/default@snap-14.4-RELEASE-p8-casa.lan-2026-28-sept-2026 /mnt/snap

Paso 2: Comparar qué cambió

diff /etc/pf.conf       /mnt/snap/etc/pf.conf
diff /etc/rc.conf       /mnt/snap/etc/rc.conf
diff /etc/sysctl.conf   /mnt/snap/etc/sysctl.conf
diff /boot/loader.conf  /mnt/snap/boot/loader.conf

Paso 3: Backup de los actuales

cp /etc/pf.conf       /etc/pf.conf.broken-$(date +%Y%m%d)
cp /etc/rc.conf       /etc/rc.conf.broken-$(date +%Y%m%d)
cp /etc/sysctl.conf   /etc/sysctl.conf.broken-$(date +%Y%m%d)
cp /boot/loader.conf  /boot/loader.conf.broken-$(date +%Y%m%d)

Paso 4: Restaurar desde el snapshot

cp /mnt/snap/etc/pf.conf       /etc/pf.conf
cp /mnt/snap/etc/rc.conf       /etc/rc.conf
cp /mnt/snap/etc/sysctl.conf   /etc/sysctl.conf
cp /mnt/snap/boot/loader.conf  /boot/loader.conf

Paso 5: Desmontar y probar

umount /mnt/snap
rmdir /mnt/snap

# Recargar pf (sin reiniciar)
pfctl -f /etc/pf.conf

# Ver rutas
netstat -rn

# Probar red
ping -c 3 192.168.88.1
ping -c 3 8.8.8.8
ping -c 3 google.com

Paso 6: Si funciona, reiniciar para aplicar loader.conf y sysctl.conf

shutdown -r now

15. Rollback completo

Requiere arrancar en modo monousuario. No se puede hacer con el dataset montado.

Paso 1: Crear snapshot de seguridad del estado actual

Antes de tocar nada, para poder volver si algo falla:

zfs snapshot -r zroot@before-rollback-$(date +%Y%m%d-%H%M)

Paso 2: Reiniciar en modo monousuario

shutdown -r now

En el menú de arranque de FreeBSD, pulsar 2 (Boot Single User).

Paso 3: Preparar el sistema

zfs set readonly=off zroot
zfs mount -a

Paso 4: Rollback

Esto destruye los snapshots posteriores a este (incluido el de before-rollback).
zfs rollback -R zroot/ROOT/default@snap-14.4-RELEASE-p8-casa.lan-2026-28-sept-2026

Paso 5: Salir del modo monousuario y reiniciar

exit

O directamente:

reboot

Qué se pierde con el rollback

ElementoEstado
pf.confVuelve al estado del snapshot
loader.confVuelve al estado del snapshot
sysctl.confVuelve al estado del snapshot
/etc/rc.confEstado del snapshot
Archivos en /home/carlosNO se pierden (dataset separado)
Archivos en /varNO se pierden (dataset separado, si no se hace rollback ahí)
Solo afecta a zroot/ROOT/default (el sistema base). Los datos personales en zroot/home/carlos no se tocan.

16. Uso del script automatizado

Solaris tiene instalado el script /root/bin/zfs-backup.sh que automatiza todo el proceso.

Ejecución manual (modelo B: USB guardado fuera)

# 1. Conectar el USB ZFSBACKUP a solaris
# 2. Ejecutar:
sh /root/bin/zfs-backup.sh

# 3. Ver el resultado
tail -20 /var/log/zfs-backup.log

# 4. Cuando termine, el script exporta el pool automáticamente
# 5. Desconectar el USB y guardarlo en lugar seguro

Qué hace el script automáticamente

  • Detecta que está en solaris y usa zbackup/zbackup/recovery/solaris/ZFSBACKUP.
  • Importa el pool zbackup si no está importado.
  • Crea el snapshot zroot@snap-YYYYMMDD (dataset por dataset, sin fallos atómicos).
  • Detecta la última snapshot en destino y envía solo el incremental.
  • Aplica retención: 7 snapshots en origen, 30 en destino.
  • Exporta el pool al terminar (para poder desconectar el USB).
  • Registra todo en /var/log/zfs-backup.log.

Frecuencia recomendada

Semanal (domingo por la tarde). Total: 5-15 minutos por backup.

17. Errores comunes a evitar

  • Usar zfs send -Rcv sin -w → falla si hay datasets cifrados.
  • Olvidar -s en zfs receive → no hay reanudación posible si se corta.
  • Cerrar la sesión SSH sin tmux → el envío muere al desconectar.
  • No guardar la clave de cifrado fuera del backup → backup inútil si se pierde.
  • Usar zfs destroy sin -n primero → riesgo de borrar snapshots con dependencias.
  • Ejecutar el script de retención sin verificar → puede borrar snapshots indiscriminadamente.
  • Importar el mismo pool en dos máquinas simultáneamente → corrompe metadatos.
  • Desconectar el USB sin zpool export → riesgo de corrupción.

18. Checklist final

  • [ ] Disco USB identificado y preparado
  • [ ] Pool zbackup creado con ashift=12
  • [ ] Dataset zbackup/recovery/solaris creado
  • [ ] Snapshot del sistema creado (zfs snapshot -r)
  • [ ] Envío lanzado dentro de tmux
  • [ ] Proceso monitorizado hasta el final
  • [ ] Verificado: snapshots origen vs destino coinciden
  • [ ] Pool exportado limpiamente (zpool export zbackup)
  • [ ] USB desconectado y guardado en lugar seguro
  • [ ] Clave de cifrado guardada en al menos 2 sitios distintos (si aplica)

19. Dónde guardar el USB

UbicaciónProtección
❌ Junto a la máquinaNinguna (robo/incendio afecta a ambos)
⚠️ Otra habitación de la casaProtección baja
✅ Otra planta / garaje / trasteroProtección media
✅✅ Casa de un familiar / amigoProtección alta
✅✅✅ Caja de seguridad del bancoProtección máxima

Recomendación: caja fuerte pequeña en casa + copia secundaria en casa de un familiar.

20. Verificaciones periódicas (cada 3-6 meses)

# 1. Conectar el USB ZFSBACKUP a solaris
# 2. Importar el pool
zpool import zbackup

# 3. Verificar el pool
zpool status zbackup

# 4. Contar snapshots en destino
zfs list -t snapshot -r zbackup/recovery/solaris | grep 'snap-2026' | wc -l

# 5. Ver las más recientes
zfs list -t snapshot -r zbackup/recovery/solaris | grep 'snap-2026' | sort | tail -5

# 6. Exportar
zpool export zbackup

Si todo está en orden, los datos son recuperables.

FreeBSD es genial!.

viernes, 2 de octubre de 2026

Realizar copia de seguridad del servidor tormenta en disco USB

ZFS FreeBSD Copia de seguridad del cliente solaris
Backup Manual y Recuperación

FreeBSD 14.5

1. Identificar discos

geom disk list
camcontrol devlist
gpart show

2. Comprobaciones previas (antes de destruir nada)

¿Tiene particiones?

gpart show da1

¿Tiene restos de ZFS?

zpool import | grep -B2 -A5 da1

¿Está montado en algún sitio?

mount | grep da1

3. Plan resumido

ComandoQué hace
gpart destroy -F da1Borra particiones
zpool labelclear -f /dev/da1Borra restos ZFS
gpart create -s gpt da1Tabla GPT nueva
gpart add -t freebsd-zfs -l backup1tb da1Partición ZFS
zpool create -o ashift=12 ... zbk /dev/gpt/backup1tbPool zbk
zfs create -o mountpoint=none zbk/tormentaDataset destino
zfs snapshot -r zroot@snap-$(date +%Y%m%d)Snapshot del sistema
zfs send -Rwcv ... | zfs receive -Fsuv ...Envío local (en tmux)
zpool export zbkCerrar limpiamente

4. Preparar el disco

gpart destroy -F da1
# → da1 destroyed

Borrar cualquier resto de ZFS (aunque no haya, por asegurar)

zpool labelclear -f /dev/da1 2>/dev/null

Crear tabla GPT nueva

gpart create -s gpt da1
# → da1 created

Crear partición ZFS ocupando todo el disco

gpart add -t freebsd-zfs -l backup1tb da1
# → da1p1 added

Verificar

gpart show da1
# →       40  1953525088  da1  GPT  (932G)
# →       40  1953525088    1  freebsd-zfs  (932G)

5. Crear el pool zbk

Los discos modernos suelen tener sectores de 4K, pero muchos discos USB reportan 512B. Es crítico crear el pool con ashift=12 (4096 bytes) para evitar problemas de rendimiento.

Ver ashift que ZFS detectaría por defecto

diskinfo -v da1 | grep -i "sector size"

Si dice 512, hay que forzar ashift=12 al crear el pool.

zpool create -o ashift=12 \
             -O compression=lz4 \
             -O atime=off \
             -O xattr=sa \
             -O relatime=on \
             -O mountpoint=none \
             zbk /dev/gpt/backup1tb

Banderas

  • ashift=12 → sectores 4K (crítico para rendimiento en discos modernos).
  • compression=lz4 → compresión ligera y rápida.
  • atime=off → no actualizar tiempo de acceso (más rápido).
  • xattr=sa → atributos extendidos en el inodo.
  • relatime=on → atime solo cuando sea útil.
  • mountpoint=none → no montar automáticamente.

Verificar

zpool status zbk
zpool list zbk
zfs list

Crear dataset destino

zfs create -o mountpoint=none zbk/tormenta
zfs list -r zbk

Salida esperada:

zbk           XXXG   XXXG    96K  none
zbk/tormenta   96K   XXXG    96K  none

Pool zbk creado correctamente:

DatoValor
Poolzbk
Tamaño928 G
Disponible899 G
Dataset destinozbk/tormenta (listo)
zroot a respaldar312 G

6. Crear snapshot del sistema

zfs snapshot -r zroot@snap-$(date +%Y%m%d)

Verificar

zfs list -t snapshot -r zroot | grep snap-$(date +%Y%m%d) | wc -l

El resultado depende del número de datasets del sistema. En tormenta actual: ~48.

Nota para el futuro: si un script creó el snapshot en un solo dataset sin usar -r, o si otro proceso lo creó antes para otro propósito, puede haber conflictos. Cuando se monte el cron para backups automáticos, usar date +%Y%m%d-%H%M%S para evitar colisiones si se ejecuta dos veces el mismo día.
zfs snapshot -r zroot@snap-$(date +%Y%m%d-%H%M%S)

7. Lanzar el envío en tmux

Entrar en tmux

tmux new -s backup_usb

Comando de envío (dentro de tmux)

zfs send -Rwcv zroot@snap-$(date +%Y%m%d) \
  | zfs receive -Fsuv -x mountpoint zbk/tormenta

Banderas explicadas

FlagSignificado
-RRecursivo: envía zroot y todos sus hijos
-wRaw: envía los bloques cifrados tal cual (necesario si hay datasets cifrados como zroot/nfsv4/secifrado)
-cCompresión nativa ZFS (lz4)
-vVerbose: muestra progreso por dataset
-FFuerza rollback en destino si hay divergencias
-sGuarda token de resume en /var/tmp/ (permite reanudar si se corta)
-uNo monta los datasets recibidos
-x mountpointNo replica los mountpoints del origen
Importante sobre -w: el dataset zroot/nfsv4/secifrado está cifrado con ZFS native encryption. Con zfs send -Rcv (sin -w) el envío falla. Siempre usar -Rwcv.

8. Cifrado: consideraciones

El flag -w envía el dataset cifrado tal cual (raw). Ventaja: funciona, conserva el cifrado, es rápido. Inconveniente: en destino el dataset también estará cifrado y necesitarás la clave para montarlo.

¿Qué se necesita para recuperarlo?

La passphrase o keyfile utilizada para cifrar zroot/nfsv4/secifrado. Sin ella, el backup es inútil.

GUARDAR LA PASSPHRASE/KEYFILE
Si se pierde la clave, se pierden los datos y el backup. Guardarla en:
  • Un gestor de contraseñas (Bitwarden, KeePass, etc.)
  • Un archivo en un USB que no sea el mismo del backup
  • Papel impreso en un lugar seguro

Comprobar qué método de cifrado se utilizó

zfs get encryption,keyformat,keylocation zroot/nfsv4/secifrado

# NAME                       PROPERTY     VALUE                        SOURCE
# zroot/nfsv4/secifrado      encryption   aes-256-gcm                  -
# zroot/nfsv4/secifrado      keyformat    raw                          -
# zroot/nfsv4/secifrado      keylocation  file:///etc/zfs/secifrado.key

Si dice keyformat=passphrase, se necesita esa passphrase.
Si dice keyformat=raw con keylocation=file:///..., es necesario ese archivo.

Ver el contenido (para copiarlo en un gestor de contraseñas)

Convertir a base64 para poder copiarlo como texto:

base64 /etc/zfs/secifrado.key

9. Salir de tmux sin matar el proceso

Ctrl+b  d

10. Monitorizar (en otra terminal)

Ver datasets llegando en tiempo real

watch -n 10 'zfs list -r zbk/tormenta | head -30'

Ver velocidad de escritura al USB

zpool iostat zbk 5

Ver espacio consumido

watch -n 30 'zfs list zbk'

11. Verificar tras el envío

Volver a la sesión tmux

tmux attach -t backup_usb

Si ya terminó, se verá el real Xm Ys del comando. Entonces:

Contar snapshots origen vs destino

zfs list -t snapshot -r zroot | wc -l
zfs list -t snapshot -r zbk/tormenta | wc -l

Deben coincidir (probablemente ~300+).

Verificar datasets replicados

zfs list -r zbk/tormenta | head -30

Espacio usado

zfs list zbk
zpool list zbk

12. Si algo falla durante el envío

¿Sigue algún proceso zfs vivo?

ps aux | grep -E "zfs (send|receive)" | grep -v grep

Si aparece algo, sigue corriendo. Esperar y dejarlo terminar.

¿En qué estado está el destino?

zfs list zbk
zfs list -r zbk/tormenta | head -20

Se verá si quedó un dataset a medias (zbk/tormenta con datos parciales).

¿Hay un token de resume guardado?

ls -la /var/tmp/ | grep -i zfs
ls -la / | grep -i zfs
El token de resume solo existe si se usó -s en el zfs receive. Si no se usó, no hay reanudación posible: hay que empezar de cero.

¿El proceso murió? Limpiar el destino parcial

zfs destroy -r zbk/tormenta
zfs create -o mountpoint=none zbk/tormenta
zfs list -r zbk

Relanzar con -s para permitir resume

tmux new -s backup_usb

Dentro de tmux:

zfs send -Rwcv zroot@snap-20260930 \
  | zfs receive -Fsuv -x mountpoint zbk/tormenta
El flag -s en zfs receive guarda un token de reanudación en /var/tmp/. Si se vuelve a cortar, se podrá reanudar con:
zfs send -t $(ls /var/tmp/zfs_*.resume 2>/dev/null | head -1)

Salir de tmux con Ctrl+b d antes de cerrar SSH. No cerrar la sesión SSH hasta que tmux esté desconectado.

13. Exportar el pool y desconectar el USB

Verificar que no hay nada escribiendo

zpool status zbk
lsof | grep zbk 2>/dev/null

Exportar limpiamente

zpool export zbk

Y por último

sync

Ya se puede retirar el cable USB.

14. Tiempo estimado

Velocidad USB312 GB
80 MB/s~1.1 h
120 MB/s~43 min
200 MB/s~26 min
400 MB/s~13 min

Con el chip ASMT USB 3.0 + disco SATA: ~20–45 min si es SSD, ~50–80 min si es HDD.

Recordatorio: para poder cerrar la sesión SSH sin que se corte el envío, primero entrar en tmux con tmux new -s backup_usb, lanzar el envío, y salir con Ctrl+b d.
Recomendación adicional: poner una etiqueta al disco físico con rotulador o adhesivo:
  • Backup Tormenta
  • snap-20260930
  • zbk pool

15. Restaurar archivos de configuración

No requiere reiniciar. Solo copia los archivos desde el snapshot.

Paso 1: Montar el snapshot

mkdir -p /mnt/snap
mount -t zfs zroot/ROOT/default@snap-14.4-RELEASE-p8-casa.lan-2026-28-sept-2026 /mnt/snap

Paso 2: Comparar qué cambió

diff /etc/pf.conf       /mnt/snap/etc/pf.conf
diff /etc/rc.conf       /mnt/snap/etc/rc.conf
diff /etc/sysctl.conf   /mnt/snap/etc/sysctl.conf
diff /boot/loader.conf  /mnt/snap/boot/loader.conf

Paso 3: Backup de los actuales

cp /etc/pf.conf       /etc/pf.conf.broken-$(date +%Y%m%d)
cp /etc/rc.conf       /etc/rc.conf.broken-$(date +%Y%m%d)
cp /etc/sysctl.conf   /etc/sysctl.conf.broken-$(date +%Y%m%d)
cp /boot/loader.conf  /boot/loader.conf.broken-$(date +%Y%m%d)

Paso 4: Restaurar desde el snapshot

cp /mnt/snap/etc/pf.conf       /etc/pf.conf
cp /mnt/snap/etc/rc.conf       /etc/rc.conf
cp /mnt/snap/etc/sysctl.conf   /etc/sysctl.conf
cp /mnt/snap/boot/loader.conf  /boot/loader.conf

Paso 5: Desmontar y probar

umount /mnt/snap
rmdir /mnt/snap

# Recargar pf (sin reiniciar)
pfctl -f /etc/pf.conf

# Ver rutas
netstat -rn

# Probar red
ping -c 3 192.168.88.1
ping -c 3 8.8.8.8
ping -c 3 google.com

Paso 6: Si funciona, reiniciar para aplicar loader.conf y sysctl.conf

shutdown -r now

16. Rollback completo

Requiere arrancar en modo monousuario. No se puede hacer con el dataset montado.

Paso 1: Crear snapshot de seguridad del estado actual

Antes de tocar nada, para poder volver si algo falla:

zfs snapshot -r zroot@before-rollback-$(date +%Y%m%d-%H%M)

Paso 2: Reiniciar en modo monousuario

shutdown -r now

En el menú de arranque de FreeBSD, pulsar 2 (Boot Single User).

Paso 3: Preparar el sistema

zfs set readonly=off zroot
zfs mount -a

Paso 4: Rollback

Esto destruye los snapshots posteriores a este (incluido el de before-rollback).
zfs rollback -R zroot/ROOT/default@snap-14.4-RELEASE-p8-casa.lan-2026-28-sept-2026

Paso 5: Salir del modo monousuario y reiniciar

exit

O directamente:

reboot

Qué se pierde con el rollback

ElementoEstado
pf.confext_if="wlan0" (vuelve atrás)
loader.confSin hw.em.eee_setting=1
sysctl.confSin dev.em.0.eee_control=0
/etc/rc.confEstado del snapshot
Archivos en /home/carlosNO se pierden (dataset separado)
Archivos en /varNO se pierden (dataset separado, si no se hace rollback ahí)
Solo afecta a zroot/ROOT/default (el sistema base). Los datos personales en zroot/home/carlos no se tocan.

17. Errores comunes a evitar

  • Usar zfs send -Rcv sin -w → falla si hay datasets cifrados.
  • Olvidar -s en zfs receive → no hay reanudación posible si se corta.
  • Cerrar la sesión SSH sin tmux → el envío muere al desconectar.
  • No guardar la clave de cifrado fuera del backup → backup inútil si se pierde.
  • Usar zfs destroy sin -n primero → riesgo de borrar snapshots con dependencias.
  • Ejecutar el script de retención sin verificar → puede borrar snapshots indiscriminadamente.

18. Checklist final

  • [ ] Disco USB identificado y preparado
  • [ ] Pool zbk creado con ashift=12
  • [ ] Dataset zbk/tormenta creado
  • [ ] Snapshot del sistema creado (zfs snapshot -r)
  • [ ] Envío lanzado dentro de tmux
  • [ ] Proceso monitorizado hasta el final
  • [ ] Verificado: snapshots origen vs destino coinciden
  • [ ] Pool exportado limpiamente (zpool export zbk)
  • [ ] USB desconectado y guardado en lugar seguro
  • [ ] Clave de cifrado guardada en al menos 2 sitios distintos
FreeBSD es genial!.

martes, 10 de marzo de 2026

Formatear y montar dispositivo USB exFAT en FreeBSD 14.3

Fuente:

https://docs.freebsd.org/en/books/handbook/filesystems/

En FreeBSD 14.3, el sistema no tiene soporte nativo para exFAT en el kernel. Para el montaje de un disco USB exFAT (/dev/da0 o /dev/da0p1 /dev/da0s1), se necesita utilizar FUSE y el puerto fusefs-exfat.

Instalar los paquetes necesarios

pkg install fusefs-libs fusefs-exfat

pkg info | grep -i exfat
exfat-utils-1.4.0_1    Utilities to create, check, label and dump exFAT filesystem
fusefs-exfat-1.4.0_1   Full-featured exFAT FS implementation as a FUSE module

Cargar el módulo FUSE

kldload fusefs

Para cargar siempre al inicio

sysrc kld_list+="fusefs"

Identificar correctamente el dispositivo

dmesg
da0 at umass-sim0 bus 0 scbus1 target 0 lun 0
da0: <ASMT USB 3.0 TOSATA 0> Fixed Direct Access SPC-4 SCSI device
da0: Serial Number 0000000000A3
da0: 400.000MB/s transfers
da0: 38166MB (78165360 512 byte sectors)
da0: quirks=0x2

Particionar /dev/da0 desde FreeBSD 14.3

Desmontar si está montado (por seguridad)

umount /dev/da0p1 2>/dev/null || true 

Formatear dispositivo /dev/da0

Borrar todo y crear tabla GPT (destructivo)

sudo gpart destroy -F da0
da0 destroyed

gpart create -s gpt da0 
da0 created

Agregar una partición que ocupe todo el disco con el tipo ms-basic-data que Windows/macOS reconocen como exFAT

gpart add -t ms-basic-data -l "MiSSD" da0
da0p1 added

Formatear la partición (da0p1)

mkexfatfs /dev/da0p1
mkexfatfs 1.4.0
Creating... done.
Flushing... done.
File system created successfully.

Crear punto de montaje y montar la particion

mkdir /mnt/usb
mount.exfat /dev/da0p1 /mnt/usb
FUSE exfat 1.4.0 (libfuse2)

Mostrar espacio libre en disco

df -h /mnt/usb 
Filesystem    Size   Used   Avail Capacity  Mounted on
/dev/da0p1     37G   1.6M     37G     0%    /mnt/usb

Listar las particiones

gpart show da0
=>      40  78165280  da0  GPT  (37G)
        40  78165280    1  ms-basic-data  (37G)

El dispositivo real suele ser

/dev/da0p1 (GPT con letra p)
/dev/da0s1 (MBR/slice con letra s)

Es importante desmontar antes de desconectar

umount /mnt/usb
FreeBSD es genial!.

jueves, 26 de febrero de 2026

mount FreeBSD Cifrado ZFS desde liveCD y encontrar partición root

Fuente:

https://klarasystems.com/articles/manipulating-a-pool-from-the-rescue-system/
 mkdir /tmp/mountado
 geli attach /dev/nda0p4
 zpool import -f -R /tmp/montado zroot
 zfs list zroot
 NAME                            USED  AVAIL  REFER  MOUNTPOINT
zroot                            223G   211G    96K  /zroot
zroot/ROOT                      82.9G   211G    96K  none
zroot/ROOT/14.3-RELEASE-p8         8K   211G  21.1G  /
zroot/ROOT/default              82.9G   211G  21.3G  /
zroot/cache                     3.04G   211G    96K  /zroot/cache
zroot/cache/ccache              3.04G   211G  3.04G  /var/cache/ccache
zroot/home                      75.3G   211G    96K  /home
zroot/home/carlos               75.3G   211G  67.4G  /home/carlos
zroot/reserved                  50.0G   261G    96K  /zroot/reserved
zroot/tmp                        320K   211G   180K  /tmp
zroot/usr                       9.89G   211G    96K  /usr
zroot/usr/ports                 6.99G   211G  2.91G  /usr/ports
zroot/usr/src                   2.90G   211G  2.63G  /usr/src
zroot/var                       1.61G   211G    96K  /var
zroot/var/audit                   96K   211G    96K  /var/audit
zroot/var/crash                 1.60G   211G  1.60G  /var/crash
zroot/var/log                   3.11M   211G  2.00M  /var/log
zroot/var/mail                   356K   211G   260K

Propiedad canmount de zroot/ROOT/default

zfs get mountpoint,canmount,mounted zroot/ROOT/default
NAME                PROPERTY    VALUE       SOURCE
zroot/ROOT/default  mountpoint  /           local
zroot/ROOT/default  canmount    noauto      local
zroot/ROOT/default  mounted     yes         -

¿Qué hace canmount=noauto?

La propiedad canmount en ZFS controla si un dataset puede ser montado. Tiene tres valores posibles:

on - El dataset se monta automáticamente cuando es necesario (por ejemplo, al importar el pool o al ejecutar zfs mount -a).

off - El dataset no puede ser montado en absoluto.

noauto - El dataset no se monta automáticamente por operaciones generales del sistema (como zfs mount -a o la importación del pool), pero puede ser montado manualmente con zfs mount. Es un estado intermedio que lo hace "disponible pero no automático".

Montar zroot/ROOT/default con el comando mount

 zfs mount zroot/ROOT/default

Despues de finalizar los cambios exportar el zpool

zpool export zroot

Reiniciar y arrancar desde el disco duro NVMe (nda0)

 shutdown -r now
FreeBSD es genial!.

martes, 16 de diciembre de 2025

Cifrado por Envoltorio (túnel) del tráfico NFSv4 con Wireguard FreeBSD 14.3

Implementar cifrado por envoltorio (Wireguard) y proteger conexiones NFS entre un servidor y su(s) cliente(s).

Objetivos:

NFSv4 puro y limpio (solo puerto 2049).
Acceso exclusivo a través del túnel WireGuard (cifrado punto a punto).
Imposible acceder a los recursos desde la LAN física (bloqueado por PF).
Montajes persistentes y estables en el cliente.
Todo seguro, mínimo y sin componentes innecesarios corriendo.

Cómo implementar el cifrado por envoltorio: WireGuard

El servidor NFSv4 corre FreeBSD 14.3 ZFS, red 192.168.88.0/24, dominio local.com, nombre de host tormenta.local.com, dirección IP 192.168.88.160, interfaz re0, cortafuegos PF.

El cliente es un portátil con sistema operativo FreeBSD 14.3 ZFS, dirección IP 192.168.88.51, nombre de host solaris.local.com, interfaz de red em0. El archivo /etc/exports actual

V4: /nfsv4 -tls
/nfsv4/dellhome     -maproot=root -network 192.168.88.0/24 
/nfsv4/poolrecovery -maproot=root -network 192.168.88.0/24 
/nfsv4/docs         -maproot=root -network 192.168.88.0/24 
/nfsv4/confsolaris  -maproot=root -network 192.168.88.0/24 
/nfsv4/conftormenta -maproot=root -network 192.168.88.0/24
root@tormenta:~ # zfs list | grep /nfsv4 
zroot/nfsv4 103G 212G 7.80G /nfsv4 
zroot/nfsv4/confsolaris 283M 212G 4.76M /nfsv4/confsolaris 
zroot/nfsv4/conftormenta 916K 212G 852K /nfsv4/conftormenta 
zroot/nfsv4/dellhome 56.6G 212G 56.6G /nfsv4/dellhome 
zroot/nfsv4/docs 7.80G 212G 7.80G /nfsv4/docs 
zroot/nfsv4/poolrecovery 1.88G 212G 1.88G /nfsv4/poolrecovery 

La idea es crear un túnel VPN punto a punto entre el servidor (tormenta.local.com, 192.168.88.160) y el cliente (solaris.local.com, 192.168.88.51). De esta forma, el tráfico NFS se enruta exclusivamente a través del túnel encriptado de WireGuard, y configurar el servidor NFS para que solo escuche en la IP del túnel (evitando accesos directos por la LAN).

Forzar el cifrado para NFS, ya que ambos hosts están en la misma red LAN (192.168.88.0/24). Usar IPs privadas para el túnel: 10.66.66.1/32 para el servidor y 10.66.66.2/32 para el cliente. No es necesario forwarding ni NAT, ya que es un túnel simple para cifrar el tráfico local.

Verificar que no haya conflictos con reglas PF existentes. Si se usa NFSv4 puro, no se necesita rpcbind ni mountd, lo que simplifica las cosas


Detener servicios TLS

root@tormenta:/home/carlos # service tlsservd status
tlsservd is running as pid 1278.
root@tormenta:/home/carlos # service tlsservd stop
Stopping tlsservd.
Waiting for PIDS: 1278.

root@solaris:~# service tlsclntd status
tlsclntd is running as pid 1596.
root@solaris:~# service tlsclntd stop
Stopping tlsclntd.
Waiting for PIDS: 1596, 1596.

Desactivar TLS

root@tormenta:/home/carlos # sysrc tlsservd_enable="NO"
tlsservd_enable: YES -> NO

root@solaris:~# sysrc tlsclntd_enable="NO"
tlsclntd_enable: YES -> NO

Instalar wireguard-tools en el servidor tormenta y el cliente solaris

pkg install wireguard-tools
sysrc wireguard_enable="YES"
sysrc wireguard_interfaces="wg0"

En el servidor tormenta Generar claves privadas y públicas

mkdir /usr/local/etc/wireguard
cd /usr/local/etc/wireguard

umask 077
wg genkey | tee server_priv.key | wg pubkey > server_pub.key
wg genkey | tee client_priv.key | wg pubkey > client_pub.key

ls -l /usr/local/etc/wireguard
-rw-------  1 root wheel  45 Dec 11 18:28 client_priv.key
-rw-r--r--  1 root wheel  45 Dec 11 18:28 client_pub.key
-rw-------  1 root wheel  45 Dec 11 18:27 server_priv.key
-rw-r--r--  1 root wheel  45 Dec 11 18:27 server_pub.key

Esto genera claves para servidor y cliente

Transferir las claves al cliente solaris (IP 192.168.88.51), usando scp

scp root@tormenta:/usr/local/etc/wireguard/client_priv.key /usr/local/etc/wireguard/client_priv.key
scp root@tormenta:/usr/local/etc/wireguard/client_pub.key /usr/local/etc/wireguard/client_pub.key

Asegurar permisos estrictos (chmod 600 *.key)

cd /usr/local/etc/wireguard/
chmod 600 *.key

ls -l /usr/local/etc/wireguard/
-rw-------  1 root wheel  45 Dec 11 18:30 client_priv.key
-rw-------  1 root wheel  45 Dec 11 18:31 client_pub.key

Configurar WireGuard en el servidor tormenta

Archivo /usr/local/etc/wireguard/wg0.conf

###########################################
[Interface]
Address = 10.66.66.1/32
PrivateKey = <contenido de server_priv.key>
ListenPort = 51820

[Peer]
PublicKey = <contenido de client_pub.key>
AllowedIPs = 10.66.66.2/32

Reemplazar las claves por las claves reales

[Interface]
Address = 10.66.66.1/32
PrivateKey = oPtSkHSk8zNe9d3Z6gExZro9Cf8BELoahgZDsrc/7mk=
ListenPort = 51820

# conexion con clientes
[Peer]
PublicKey = tuu6a6EAPrQTC0tPatWJx2qcS6fEPcg4Z0u/8vY1pTs= 
AllowedIPs = 10.66.66.2/32
###########################################

Habilitar e iniciar el servicio

sysrc wireguard_interfaces="wg0"
sysrc wireguard_enable="YES"
service wireguard start
|

Acvitar desactivar interfaz wg0

wg-quick up wg0
wg-quick down wg0

Comprobar con wg show, debería mostrar la interfaz wg0 levantada

root@tormenta:/home/carlos # wg show
interface: wg0
  public key: UYbDhuNsq0geqJdsVKThSnNLzdc2oHWgUT8Gb0G3VXU=
  private key: (hidden)
  listening port: 51820

peer: tuu6a6EAPrPTC0tPatWJx2qcS6fEPcg4Z0u/8vY1pTs=
  allowed ips: 10.66.66.2/32

Configurar WireGuard en el cliente (solaris)

Archivo /usr/local/etc/wireguard/wg0.conf
###########################################
[Interface]
Address = 10.66.66.2/32
PrivateKey = <contenido de client_priv.key>

[Peer]
PublicKey = <contenido de server_pub.key>
AllowedIPs = 10.66.66.1/32
Endpoint = 192.168.88.160:51820

Reemplazar con las claves reales

[Interface]
Address = 10.66.66.2/32
PrivateKey = sAvZnwh/8xrLLNTxBu75UfvUPB/AhFQTJsUGqYTfUU0=

[Peer]
PublicKey = UYbDhuNsq0geqWdsVKXhSnNLzdc2oHWgUT8Zb0G3VXU=
AllowedIPs = 10.66.66.1/32
Endpoint = 192.168.88.160:51820
###########################################
sysrc wireguard_interfaces="wg0"
sysrc wireguard_enable="YES"
service wireguard start

Levantar interfaz wg0

# wg-quick up wg0
[#] ifconfig wg create name wg0
[#] wg setconf wg0 /dev/stdin
[#] ifconfig wg0 inet 10.66.66.2/32 alias
[#] ifconfig wg0 mtu 1420
[#] ifconfig wg0 up
[#] route -q -n add -inet 10.66.66.1/32 -interface wg0
[+] Backgrounding route monitor

Comprobar wg show debería mostrar el peer conectado.

wg show
interface: wg0
  public key: tuu6a6EAPrPTC0tPatWJx2qcS6fEPcg4Z0u/8vY1pTs=
  listening port: 26481

peer: UYbDhuNsq0geqWdsVKThSnNLzdc2oHWgUT8Gb0G3VXU=
  endpoint: 192.168.88.160:51820
  allowed ips: 10.66.66.1/32
  

Reglas cortafuegos PF (tormenta)

# Regla PF Wireguard antes Anti-spoofing + bogons - permite solo desde el cliente
pass in quick on $lan_if proto udp from 192.168.88.51 to 192.168.88.160 port 51820 keep state
# permite todo dentro del tunel
pass in quick on wg0 keep state # <-- esta es la importante <-p>

Recargar PF

service pf reload 
pfctl -f /etc/pf.conf

Verificar ping, desde el cliente solaris

root@solaris:~# ping 10.66.66.1
PING 10.66.66.1 (10.66.66.1): 56 data bytes
64 bytes from 10.66.66.1: icmp_seq=0 ttl=64 time=0.463 ms
64 bytes from 10.66.66.1: icmp_seq=1 ttl=64 time=0.524 ms

--- 10.66.66.1 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.463/0.494/0.524/0.031 ms

Verificar ping, desde el servidor tormenta

root@tormenta:~# ping -c2 10.66.66.2
PING 10.66.66.2 (10.66.66.2): 56 data bytes
64 bytes from 10.66.66.2: icmp_seq=0 ttl=64 time=0.429 ms
64 bytes from 10.66.66.2: icmp_seq=1 ttl=64 time=0.526 ms

--- 10.66.66.2 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.429/0.478/0.526/0.049 ms

ping bidireccional exitoso.

Configurar el cortafuegos PF en el servidor (tormenta)

Para permitir el tráfico WireGuard (UDP puerto 51820), agregar reglas a /etc/pf.conf. Asume que ya tienes PF configurado.

pass in quick on re0 proto udp from 192.168.88.51 to 192.168.88.160 port 51820 keep state

Recargar PF

service pf reload
pfctl -p /etc/pf.conf

Configurar NFSv4 para que solo escuche en la IP del túnel


En el servidor (tormenta), asegurar NFSv4 puro en /etc/rc.conf

nsf_server_enable="YES"
nfsv4_server_enable="YES"
nfs_server_flags="-h 10.66.66.1" # Bind sólo a la IP del túnel
nfsuserd_enable="YES" # necesario si se usa dominio

Iniciar servicios

service nfsd start
service nfsuserd start

Es es para que nfsd sólo escuche en 10.66.66.1, (no en 192.168.88.160).

Deshabilitar rpcbind_enable y mountd_enable, no son necesarios para NFSv4 puro.

Realizar los cambios en /etc/exports para restringir accesos sólo al cliente del túnel
(cambiar de red a host -network a -host).

############################################
V4: /nfsv4
/nfsv4/dellhome -maproot=root 10.66.66.2
/nfsv4/poolrecovery -maproot=root 10.66.66.2
/nfsv4/docs -maproot=root 10.66.66.2
/nfsv4/confsolaris -maproot=root 10.66.66.2
/nfsv4/conftormenta -maproot=root 10.66.66.2
############################################

Esto permite solo desde 10.66.66.2 (el cliente vía túnel).

Reiniciar NFS y nfsuserd

service nfsd restart
service nfsuserd restart

Montar NFS en el cliente (solaris) a través del tŕunel


En el cliente montar usando la IP del túnel del servidor, por ejemplo:

mount -t nfs -o nfsv4 10.66.66.1:/docs /mnt/docs

Para montajes persistentes, se utiliza /etc/fstab

10.66.66.1:/poolrecovery     /nisc4    nfs     rw,nfsv4,noatime,bg    0  	0
10.66.66.1:/confsolaris      /nics4    nfs     rw,nfsv4,noatime,bg	  0  	0
10.66.66.1:/conftormenta     /nits4    nfs     rw,nfsv4,noatime,bg	  0  	0
10.66.66.1:/docs             /nids4    nfs     rw,nfsv4,noatime,bg    0  	0
10.66.66.1:/dellhome 	     /nihs4    nfs     ro,nfsv4,noatime,bg	  0  	0

Consideraciones adicionales

Asi queda el archivo /etc/rc.conf (solaris)

$ gsed -e '/^#/d' -e '/^\s*$/d'

syslogd_flags="-ss"
clear_tmp_enable="YES"
hostname="solaris.local.com"
gateway_enable="NO"
ifconfig_em0="inet 192.168.88.51 netmask 255.255.255.0"
defaultrouter="192.168.88.1"
background_dhclient=YES
defaultroute_delay=3
defaultroute_carrier_delay=3
sshd_enable="NO"
ntpd_enable="YES"
ntpd_sync_on_start="YES"
powerd_enable="YES"
powerd_flags="-n hadp"
loader_conf_files="/boot/loader.conf /boot/loader.conf.local"
boot_efi_enable="YES"
webcamd_enable="YES"
moused_port=/dev/ums0
moused_enable="YES"
dumpdev="NO"
zfs_enable="YES"
dbus_enable="YES"
kld_list="i915kms"
nfs_client_enable="YES"
nfsuserd_enable="YES"
nfsv4_client_enable="YES"
nfsv4_domain="local.com"
tlsclntd_enable="NO"
hostid_enable="YES"
hostid_file="/etc/hostid"
autofs_enable="YES"
devd_enable="YES"
devfs_system_ruleset="system"
pf_enable="NO"
pf_rules="/etc/pf.conf"
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
pflog_flags=""
wireguard_enable="YES"
wireguard_interface="wg0"
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
lightdm_enable="YES"
zerotier_enable="YES"
vm_dir="zfs:zroot/vm"
vm_list=""
vm_delay="3"
poudriered_enable="YES"
nginx_enable="YES"
memcached_enable="YES"
memcached_flags="-l localhost -m 8192"
jackett_enable="YES"
linux_enable="NO"
ubuntu_enable="YES"
Asi queda /etc/pf.conf
lan_if   = "re0"
lan_net  = "192.168.88.0/24"
lan_ip   = "192.168.88.160"  
ssh_port     = "{ 22 }"
vpn_if="wg0"

set block-policy return         # responde ICMP/TCP-RST a paquetes bloqueados
set ruleset-optimization none   # en FreeBSD 14 no usa "basic" ni "high-latency"
set skip on lo0

match in all scrub (no-df random-id max-mss 1440)
table <bruteforce> persist       # aquí meterá sshguard, pf-badhost, etc.

pass in quick on $lan_if from $lan_net to $lan_ip keep state
pass in quick on $lan_if proto udp from 192.168.88.51 to 192.168.88.160 port 51820 keep state
pass in quick on wg0 keep state # <-- esta es la importante

block in quick on ! $lan_if from $lan_net to any
block in quick on ! $lan_if from 192.168.0.0/16 to any
block in quick on ! $lan_if from 172.16.0.0/12 to any
block in quick on ! $lan_if from 10.0.0.0/8 to any
block in quick from any to { 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, ::/128, 0.0.0.0/8 }
block in quick from <bruteforce>

pass quick on lo0all
pass out quick inet keep state
pass in on $lan_if inet proto icmp from $lan_net to $lan_ip icmp-type echoreq keep state
pass out on $lan_if inet proto icmp from $lan_ip to $lan_net icmp-type echorep keep state
pass in on $lan_if proto tcp from $lan_net to $lan_ip port $ssh_port flags S/SFRA keep state
pass quick on $lan_if proto { tcp udp } from $lan_net to $lan_ip port 53
pass out proto udp from any to port 123 keep state
block log all

Asi queda /etc/exports

$ gsed -e '/^#/d' -e '/^\s*$/d' /etc/exports
V4: /nfsv4
/nfsv4/dellhome		-maproot=root 10.66.66.2
/nfsv4/poolrecovery 	-maproot=root 10.66.66.2
/nfsv4/docs 		-maproot=root 10.66.66.2
/nfsv4/confsolaris 	-maproot=root 10.66.66.2
/nfsv4/conftormenta 	-maproot=root 10.66.66.2

Commprobaciones finales En el servidor tormenta no debe aparecer rpcbind ni statd

root@tormenta:/etc # ps aux | grep -E "(statd|rpcbind|nfs)"
root    1192   0.0  0.0 14140  2380  -  Is   09:34      0:00.00 nfsuserd: master (nfsuserd)
root    1194   0.0  0.0 14140  2384  -  I    09:34      0:00.02 nfsuserd: server (nfsuserd)
root    1195   0.0  0.0 14140  2384  -  S    09:34      0:00.02 nfsuserd: server (nfsuserd)
root    1196   0.0  0.0 14140  2380  -  I    09:34      0:00.00 nfsuserd: server (nfsuserd)
root    1197   0.0  0.0 14140  2384  -  I    09:34      0:00.01 nfsuserd: server (nfsuserd)
root    2398   0.0  0.0 13756  2472  -  Ss   12:23      0:00.01 nfsd: master (nfsd)
root    2399   0.0  0.0 13756  2756  -  S    12:23      0:00.08 nfsd: server (nfsd)

En el cliente solaris remontar directorios

root@solaris:~# umount /nisc4 /nics4 /nits4 /nids4 /nihs4
root@solaris:~# mount -a

root@solaris:~# mount | grep 10.66.66.1
10.66.66.1:/poolrecovery on /nisc4 (nfs, noatime, nfsv4acls)
10.66.66.1:/confsolaris on /nics4 (nfs, noatime, nfsv4acls)
10.66.66.1:/conftormenta on /nits4 (nfs, noatime, nfsv4acls)
10.66.66.1:/docs on /nids4 (nfs, noatime, nfsv4acls)

NFSv4 puro, solo puerto 2049 a través del túnel WireGuard, sin dependencias de rpcbind ni demonios extra.

FreeBSD es genial!.

viernes, 26 de julio de 2024

Recursos Compartidos con Samba FreeBSD

Samba FreeBSD

SAMBA es un conjunto de programas originalmente creados por Andrew Tridgell y mantenidos en la actualizad por The SAMBA Team, bajo licencia Pública General GNU e implementado por sistemas basados en UNIX.

En el servidor

pkg install samba416
sysrc samba_server_enable="YES"

Crear conjunto de datos

zfs create zroot/usr/backup/dellhome
zfs create zroot/usr/backup/poolrecovery
zfs create zroot/usr/backup/publico
zfs create zroot/usr/backup/docs
zfs create zroot/usr/backup/codigo

El directorio público será propiedad del usuario y grupo nobody

chown nobody:nobody /usr/backup/publico

Archivo de configuracion

[global]
	unix charset 		= UTF-8
	workgroup 		= CORP
    	client min protocol 	= SMB3
    	server string 		= Samba Server Version %v en %L
	hosts allow 		= 127., 192.168.88., 10.10.10.
	netbios name 		= servidor
	security 		= user
    	passdb backend          = tdbsam
	load printers 		= no
    	domain master 		= yes
	guest account		= nobody
	printable		= no
	hide dot files		= yes
	log level		= 1 auth:5
	log file		= /var/log/samba/%m.log
	max log size 		= 10000
	deadtime 		= 60
	create mask 		= 0644
	directory mask 		= 0755
	map to guest 		= never
	wins support 		= yes 	 	 	
	interfaces 		= re0, 127.0.0.1, 192.168.88.160/24, 10.10.10.1/24
    bind interfaces only 	= yes 
	
[dellhome]
	comment		= FreeBSD
	path 		= /samba/dellhome
	public 		= no
	browseable 	= yes
	writeable 	= yes
	write list 	= carlos

[codigo]
	comment 	= Scripts
	path 		= /samba/codigo
	public 		= no
	read only 	= yes
	browseable 	= yes  	
	valid users 	= carlos
	write list 	= carlos

[poolrecovery]
	path 		= /samba/poolrecovery
	public 		= no
	writeable 	= yes
    	browseable	= yes
	guest ok 	= no
	valid users 	= carlos

[docs]
	comment		= Documentos
	path 		= /samba/docs
	public 		= no
	writeable 	= yes
	browseable 	= yes
    	valid users 	= @administradores

[public]
	comment		= Publico
	path		= /samba/publico
	public 		= yes
	writeable	= yes
	browseable	= yes
	guest ok	= yes

Que los permisos del sistema de archivos en /samba/publico sean seguros

chown -R nobody:nobody /samba/publico 

guest ok

Permite o no el acceso como usuario invitado, el valor puede ser Yes o No.

public

Define si se permite el acceso como usuario invitado, el valor puede ser Yes o No.

browseable

Permite o no mostrar este recurso en las listas de recursos compartidos, el valor puede ser Yes o No.

writable

Permite o no la escritura, es la opción opuesta a read only. El valor puede ser Yes o No. writable = Yes es lo mismo que read only = No y viceversa.

valid users

Define los usuarios o grupos, que podrán acceder al recurso compartido. Los valores pueden ser nombres de usuarios separados por comas o nombre de grupos precedido de @. Ejemplo: user1, user2, @contabilidad @administradores.

write list

Define que usuarios o grupos pueden acceder con permiso de escritura. Los valores pueden ser nombres de usuarios separados por comas o bien nombre de grupos precedidos de @. Ejemplo: user1, user2 , @contabilidad, @administradores.

admin users

Define usuarios o grupos que pueden acceder con permisos administrativos para el recurso. Pueden acceder realizando todas las operaciones como super-usuario. Los valores pueden ser nombres de usuarios separados por comas o bien nombre de grupos precedidos por una @. Ejemplo: user1, user2, @finanzas, @administradores.

directory mask

Define qué permisos en el sistema tendrán los subdirectorios creados dentro del recurso.

create mask

Define que permisos en el sistema tendrán los nuevos archivos creados dentro del recurso.

Iniciar el servicio SAMBA

service samba_server start

Reglas cortafuegos PF permitir tráfico samba

Como servidor es necesario abrir los puertos 137/udp, 138/udp, 139/tcp y 445/tcp

# /etc/pf.conf
...
pass in on $int_if proto { tcp, udp } from { 10.10.10.0/24, 192.168.88.0/24 } \
to $samba_ip port { 139, 445 }
pass in on $int_if proto udp from { 10.10.10.0/24, 192.168.88.0/24 } \
to $samba_ip port { 137, 138 }
...

Agregar usuario carlos a Samba

pdbedit -a carlos
new password:
retype new password

Activar acceso al usuario carlos

smbpasswd -e carlos
New SMB password:
Retype new SMB passwd:
Added user carlos

Reiniciar SAMBA

service samba_server restart

Conectar a un recurso compartido desde un cliente FreeBSD


Podemos usar indistintamente tanto la dirección IP del servidor FreeBSD como su nombre

cat /etc/hosts | grep tormenta
---
192.168.88.160   	tormenta
---

smbclient es parte de Samba, por tanto, es necesario instalar Samba

pkg install samba416

Debe existir el archivo smb4.conf de lo contrario smbclient falla:

smbclient: Can't load /usr/local/etc/smb4.conf - run testparm to debug it

touch /usr/local/etc/smb4.conf
echo "workgroup = CORP">/usr/local/etc/smb4.conf
echo "client min protocol = NT1">>/usr/local/etc/smb4.conf

Listar recursos compartidos por el servidor Samba

» smbclient -L tormenta
Password for [CORP\carlos]:

	Sharename       Type      Comment
	---------       ----      -------
	dellhome        Disk	  FreeBSD
	codigo          Disk      Scripts
	poolrecovery    Disk
	docs            Disk
	public          Disk      Permitido
	IPC$            IPC       IPC Service (Samba Server Version 4.16.11 en SERVIDOR)
Reconnecting with SMB1 for workgroup listing.

	Server               Comment
	---------            -------
	servidor	     Samba Server Version 4.16.11 en SERVIDOR
                         
	Workgroup            Master
	---------            -------
	CORP                 SERVIDOR

Conectar a un recurso compartido


$ smbclient -U carlos //192.168.88.160/dellhome
smb: \>

Las conexiones Samba actuales

root@tormenta: # smbstatus

Samba version 4.16.11
PID     Username   Group        Machine     Protocol Version  Encryption     Signing
--------------------------------------------------------------------------------------------------------
22653   carlos  carlos  192.168.88.51 (ipv4:192.168.88.51:39769)  SMB3_11  partial(AES-128-GMAC)
22472   nobody  nobody  192.168.88.51 (ipv4:192.168.88.51:21993)  SMB3_11      -         -

Service      pid     Machine       Connected at                   Encryption Signing
---------------------------------------------------------------------------------------------
IPC$         25576   solaris        Sun Jul 28 21:04:52 2024 CEST    -            -
public       22472   192.168.88.51  Sun Jul 28 10:48:09 2024 CEST    -            -
docs         22653   192.168.88.51  Sun Jul 28 11:17:03 2024 CEST    -            -
dellhome     61262   macbook-pro    Mon Jul 29 08:39:57 2024 CEST    -            -

No locked files

Listar sockets abiertos IPv4

root@tormenta: # sockstat -4
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
root     smbd       22653 34 tcp4   192.168.88.160:445    192.168.88.51:39769
carlos   sshd       22630 4  tcp4   192.168.88.160:22     192.168.88.51:42658
root     sshd       22628 4  tcp4   192.168.88.160:22     192.168.88.51:42658
root     smbd       22472 34 tcp4   192.168.88.160:445    192.168.88.51:21993
root     smbd       22478 34 tcp4   192.168.88.160:445    192.168.88.135:21996
root     smbd       13189 29 tcp4   127.0.0.1:445         *:*
root     smbd       13189 30 tcp4   127.0.0.1:139         *:*
root     smbd       13189 31 tcp4   192.168.88.160:445    *:*
root     smbd       13189 32 tcp4   192.168.88.160:139    *:*
root     nmbd       13182 16 udp4   *:137                 *:*
root     nmbd       13182 17 udp4   *:138                 *:*
root     nmbd       13182 18 udp4   192.168.88.160:137    *:*
root     nmbd       13182 19 udp4   192.168.88.255:137    *:*
root     nmbd       13182 20 udp4   192.168.88.160:138    *:*
root     nmbd       13182 21 udp4   192.168.88.255:138    *:*
root     sshd       92484 5  tcp4   *:22                  *:*
...

Conectar a un recurso compartido desde un cliente FreeBSD

Conectar a un recurso compartido desde un cliente MacOS

FreeBSD es genial!.