Páginas

martes, 1 de septiembre de 2026

Script Copia de Seguridad de un Conjunto de Datos ZFS Hacia un Dispositivo Remoto

Script de Replicación ZFS (zfsrep.sh)

shell zsh

Este script automatiza la copia de seguridad y replicación incremental de snapshots de ZFS desde el sistema local (solaris.local.com FreeBSD 14.4 ZFS) hacia un servidor remoto (tormenta.local.com FreeBSD 14.4 ZFS). Gestiona la creación de la snapshot diaria, el envío incremental a través de SSH y la purga automática de snapshots antiguas tanto en origen como en destino, respetando una retención de, (el valor de retention), 15 snapshots.

Descripción del funcionamiento

El script utiliza zfs send y zfs receive para transferir los datos. Detecta la última snapshot disponible en el destino para realizar un envío incremental (ahorrando ancho de banda), o realiza un envío completo si no encuentra una base común. Todo el proceso queda registrado en un archivo de log ubicado en /home/carlos/cronlog.

Contenido del script

#!/bin/sh
### BEGIN INFO
# PROVIDE:
# REQUIRE:
# KEYWORD:
### END INFO

### INICIO DEL GUION
# Estas variables se nombran primero porque están anidadas en otras variables.
snap_prefix=snap
retention=15

# Se necesitan rutas completas a estas utilidades al ejecutar el script desde cron.
date=/bin/date
cut=/usr/bin/cut
grep=/usr/bin/grep
sed=/usr/bin/sed
sort=/usr/bin/sort
xargs=/usr/bin/xargs
zfs=/sbin/zfs

src_0="zroot/home/carlos"
dst_0="zbackup/solaris/home/carlos"
host="root@192.168.88.160"
today="$snap_prefix-`$date +%Y%m%d`"
snap_today="$src_0@$today"

# Patrón grep con sufijo numérico para evitar falsos positivos.
snap_old=`$zfs list -t snapshot -o name \
  | $grep "${src_0}@${snap_prefix}-[0-9]" \
  | $sort -r \
  | $sed 1,${retention}d \
  | $sort \
  | $xargs -n 1`

# Detecta la snapshot más reciente del destino remoto para usarla como base.
# Todo el pipeline corre en tormenta vía SSH.
snap_base_name=`ssh $host "$zfs list -t snapshot -o name \
  | grep '${dst_0}@${snap_prefix}-[0-9]' \
  | sort -r \
  | sed 1q \
  | cut -d@ -f2"`
snap_base="${src_0}@${snap_base_name}"

# snap_old_dst_0 lista las snapshots > retention en el destino remoto.
snap_old_dst_0=`ssh $host "$zfs list -t snapshot -o name \
  | grep '${dst_0}@${snap_prefix}-[0-9]' \
  | sort -r \
  | sed 1,${retention}d \
  | sort"`

log=/home/carlos/cronlog

echo >> $log
echo "zfsrep.sh" >> $log
$date >> $log
echo >> $log

# Busca la instantánea de hoy en origen y, si no la encuentras, créala.
if $zfs list -H -o name -t snapshot \
  | $sort \
  | $grep "${snap_today}$" > /dev/null
then
	echo "La instantánea de hoy '$snap_today' ya existe." >> $log
else
	echo "Tomando la instantánea de hoy: $snap_today" >> $log
	$zfs snapshot -r $snap_today >> $log 2>&1
fi

echo >> $log

# Comprueba si la instantánea de hoy ya existe en el destino remoto.
# Si existe, no hay nada que enviar; saltar directamente a la purga.
if ssh $host "$zfs list -H -o name -t snapshot \
  | grep '${dst_0}@${today}$'" > /dev/null 2>&1
then
	echo "La instantánea de hoy ya existe en destino remoto. Nada que enviar." >> $log
else
	# Detecta la base del incremental y replica.
	# Permite recuperarse de huecos de sincronización sin intervención manual.
	if [ -n "$snap_base_name" ] && $zfs list -H -o name -t snapshot \
	  | $grep "${snap_base}$" > /dev/null
	then
		echo "Usando '$snap_base' como base del incremental..." >> $log
		$zfs send -R -i $snap_base $snap_today \
		  | ssh $host $zfs receive -vuF -x mountpoint $dst_0 >> $log 2>&1
		echo >> $log
		echo "Replicacion completada." >> $log
	else
		echo "No se encontró snapshot común entre origen y destino." >> $log
		echo "Realizando envío completo (puede tardar)..." >> $log
		$zfs send -R $snap_today \
		  | ssh $host $zfs receive -vuF -x mountpoint $dst_0 >> $log 2>&1
		echo >> $log
		echo "Envío completo finalizado." >> $log
	fi
fi

echo >> $log

# Eliminar instantáneas locales más antiguas que el valor asignado a $retention.
echo "Intentando destruir instantáneas antiguas $src_0..." >> $log

if [ -n "$snap_old" ]
then
	echo "Destruyendo las siguientes instantáneas antiguas:" >> $log
	echo "$snap_old" >> $log
	$zfs list -t snapshot -o name \
	  | $grep "${src_0}@${snap_prefix}-[0-9]" \
	  | $sort -r \
	  | $sed 1,${retention}d \
	  | $sort \
	  | $xargs -n 1 $zfs destroy -r >> $log 2>&1
else
	echo "No se pudo encontrar ninguna instantánea local para destruir." >> $log
fi

echo >> $log

# Eliminar instantáneas remotas más antiguas que el valor asignado a $retention.
# Todo el pipeline, incluido zfs destroy, corre en tormenta vía SSH.
echo "Intentando destruir instantáneas antiguas $dst_0..." >> $log

if [ -n "$snap_old_dst_0" ]
then
	echo "Destruyendo las siguientes instantáneas antiguas en $host:" >> $log
	echo "$snap_old_dst_0" >> $log
	ssh $host "$zfs list -t snapshot -o name \
	  | grep '${dst_0}@${snap_prefix}-[0-9]' \
	  | sort -r \
	  | sed 1,${retention}d \
	  | sort \
	  | xargs -n 1 $zfs destroy -r" >> $log 2>&1
else
	echo "No se pudo encontrar ninguna instantánea remota para destruir." >> $log
fi

echo "**********" >> $log

### FIN DEL SCRIPT

Estructura de zbackup (servidor)

carlos@tormenta:~ % zfs list -r zbackup
NAME                          USED  AVAIL  REFER  MOUNTPOINT
zbackup                      1008G   791G  92.5M  none
zbackup/dellhome             56.6G   791G  56.6G  none
zbackup/nfsv4                36.6G   791G    96K  none
zbackup/nfsv4/docs           7.80G   791G  7.80G  none
zbackup/nfsv4/secrets        28.8G   791G  28.8G  none
zbackup/recovery              755G   791G   104K  none
zbackup/recovery/solaris      282G   791G   282G  none
zbackup/recovery/tormenta     473G   791G   473G  none
zbackup/reserved               50G   841G    96K  none
zbackup/solaris              80.9G   791G    96K  none
zbackup/solaris/home         80.9G   791G    96K  none
zbackup/solaris/home/carlos  80.9G   791G  73.2G  none
zbackup/usr                   147M   791G   104K  none
zbackup/usr/home              147M   791G   140M  none

zfsrep.sh - Funcionamiento

Asigna rutas absolutas a los binarios (zfs, date, grep, etc.) para evitar problemas de $PATH al ejecutarse desde cron

date=/bin/date
cut=/usr/bin/cut
grep=/usr/bin/grep
sed=/usr/bin/sed
sort=/usr/bin/sort
xargs=/usr/bin/xargs
zfs=/sbin/zfs

Contexto

El script corre en solaris (cliente) y replica el dataset zroot/home/carlos hacia zbackup/solaris/home/carlos en tormenta (servidor), usando SSH como canal de transporte.

1 - Definición de variables

src_0="zroot/home/carlos"
dst_0="zbackup/solaris/home/carlos"
host="root@192.168.88.160"
today="snap-20260901"
snap_today="zroot/home/carlos@snap-fecha_de_hoy"

Se calculan los nombres de las snapshots y rutas antes de hacer nada. today se genera en este momento con $date, así que si el script corre a las 2:00 AM o a las 23:00 del mismo día, el nombre es idéntico - eso es lo que permite la comprobación de duplicado más adelante.

2 - Inventario de snapshots antiguas a purgar (local)

snap_old=`$zfs list -t snapshot -o name
  | $grep "${src_0}@${snap_prefix}-[0-9]"
  | $sort -r
  | $sed 1,${retention}d
  | $sort
  | $xargs -n 1`

Se calcula en este momento, antes de crear la snapshot de hoy. El pipeline:

Lista todas las snapshots del sistema Filtra las de zroot/home/carlos@snap- seguido de dígito Las ordena de más reciente a más antigua (sort -r) Elimina las primeras 15 líneas (sed 1,15d) - las 15 más recientes se conservan Lo que queda son las candidatas a destruir

Este cálculo es previo a la snapshot de hoy para que retention=15 sea exacto.

3 - Inventario remoto: base del incremental y purga

snap_base_name=`ssh $host "...pipeline en tormenta..."`
snap_old_dst_0=`ssh $host "...pipeline en tormenta..."`

Se abren dos conexiones SSH a tormenta para:

snap_base_name: la snapshot más reciente que tiene zbackup/solaris/home/carlos. Será el punto de partida del incremental. Si el destino tiene snap-20260831, el incremental enviará solo los cambios entre ese día y hoy. snap_old_dst_0: lista de snapshots en destino que superan retention=15, candidatas a purga remota.

Todo el pipeline de grep/sort/sed corre dentro del SSH, en tormenta, para que el resultado que llega a solaris sea solo texto limpio.

4 - Snapshot de hoy en origen

if zfs list ... | grep "${snap_today}$"
then
    "ya existe"
else
    zfs snapshot -r $snap_today
fi

Comprueba si zroot/home/carlos@snap-20260901 ya existe. El flag -r crea la snapshot de forma recursiva - si hubiera datasets hijo bajo zroot/home/carlos, también se snapshotearían. Si ya existe (segunda ejecución del día), simplemente lo anota en el log y continúa.

5 - Comprobación de duplicado en destino

if ssh $host "zfs list ... | grep '${dst_0}@${today}$'"
then
    "Nada que enviar"
else
    # continuar con el send
fi

Pregunta a tormenta: ¿ya tienes zbackup/solaris/home/carlos@snap-20260901? Si la respuesta es sí, el script salta directamente a la purga - no hay nada que transferir. Esto evita el reenvío innecesario si cron lanza el script más de una vez al día.

6 - Replicación incremental (o completa)

Caso normal - base común encontrada:

zfs send -R -i $snap_base $snap_today \
  | ssh $host zfs receive -vuF -x mountpoint $dst_0

zfs send genera un stream binario con los bloques que cambiaron entre snap_base y snap_today. Ese stream se pasa directamente por el pipe a SSH, que lo entrega a zfs receive en tormenta. No se escribe nada en disco en solaris - es un flujo directo en memoria.

Los flags:

-R: incluye snapshots hijas recursivamente
-i: incremental entre dos snapshots
-v: verbose en el log
-u: no monta el dataset recibido
-F: destruye en destino lo que no existe en el stream (mantiene coherencia)
-x mountpoint: ignora la propiedad mountpoint del stream — el destino mantiene mountpoint=none

Caso de hueco - sin base común:

zfs send -R $snap_today | ssh $host zfs receive -vuF -x mountpoint $dst_0

Si no hay ninguna snapshot común entre origen y destino, se hace un envío completo. Más lento, pero garantiza que el destino queda sincronizado desde cero.

7 - Purga local

zfs list -t snapshot -o name
  | grep "${src_0}@${snap_prefix}-[0-9]"
  | sort -r | sed 1,15d | sort
  | xargs -n 1 zfs destroy -r

Mismo pipeline que en el paso 2, pero esta vez ejecutando zfs destroy -r sobre cada snapshot antigua. El -r destruye también las snapshots hijas si las hubiera. Las 15 más recientes quedan intactas.

8 - Purga remota

ssh $host "zfs list ... | grep ... | sort -r | sed 1,15d | sort | xargs -n 1 zfs destroy -r"

Ídem pero en tormenta. Todo el pipeline - incluido el zfs destroy - corre dentro del SSH. Esto es crítico: si el destroy corriera en local, intentaría destruir zbackup/... en solaris, donde ese dataset no existe.

Entrada en cron para ejecución diaria a las 2:00 AM

 crontab -e
# Ejecución diaria de la copia de seguridad ZFS a las 2:00 AM
0 2 * * * /home/carlos/bin/zfsrep.sh
Guardar y salir

Que sea ejcutable

chmod +x /home/carlos/bin/zfsrep.sh

Comprobar que el script funciona manualmente antes de programarlo

sh -x /home/carlos/bin/zfsrep.sh

Ejemplo de crontab completo (para root)

SHELL=/bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin
MAILTO=root

# Ejecución diaria de la copia de seguridad ZFS a las 2:00 AM
0 2 * * * /home/carlos/bin/zfsrep.sh

Notas Finales

Robustez: La lógica de incremental/completo permite que el script se recupere automáticamente si se borra una instantánea intermedia.

Eficiencia: La mejora que evita reenvíos el mismo día ahorra ancho de banda y CPU.

Mantenimiento: La limpieza automática en origen y destino evita que el espacio se llene con instantáneas antiguas.

Portabilidad: Al usar rutas absolutas, el script funciona correctamente desde cron.

Con este sistema, tus datos están respaldados diariamente en un dispositivo remoto, con una política de retención clara y la capacidad de recuperación ante fallos de sincronización.

FreeBSD es genial!.

domingo, 30 de agosto de 2026

Hacer Windows Rápido y Silencioso (Windows 10 y Windows 11)

Antes de modificar servicios del sistema o el registro de Windows, es muy recomendable tener un punto de recuperación.

La forma más segura y completa de hacerlo es a través de un Punto de Reatauración, ya que permite revertir todo el sistema a un estado anterior. Es similar a un snapshot en FreeBSD.

Crear un punto de restauración

Paso 1: Abrir la Configuración
1. Pulsa la tecla Windows y escribe "Crear un punto de Restauración".
2. Haz clic en el resultado que aparece con el icono de un escudo azul y amarillo

Paso 2: Activar la protección (si no lo está)
Se abrirá una ventana llamada "Propiedades del sistema" en la pestaña "Protección del sistema".
Mira la columna "Configuración de tu disco local (normalmente en C:) Si dice "Desactivada",
haz clic en el botón "Configurar..." Selecciona "Activa la protección del sistema", mueve el control deslizante hasta asignar un poco de
espacio (5% o 10 GB es suficiente), y pulsa "Aceptar".

Paso 3: Crear el punto
1. En esa misma ventana, haz clic en el botón "Crear..."
2. Escribe un nombre descriptivo, por ejemplo: "Antes de optimizar Windows".
3. Pulsa en "Crear" y espera unos minutos (Windows creará un foto tu sistema).
4. Cuando termine, te dará el mensaje de que se creó correctamente. ¡Pulsa "Cerrar"!

Ahora puedes hacer los cambios con total tranquilidad

Consejo clave para restaurar

Si después de desactivar los servicios algo funcionar mal, vuelve a abrir esa misma ventana de "Protección del sistema", haz clic en "Restaurar sistema..." y elige el punto "Antes de optimizar Windows". Esto devolverá tu PC al estado exacto en el que estaba ahora mismo.

Nota importante: El punto de restauración no afecta a tus archivos personales (fotos documentos, etc.), solo revierte los cambios del sistema, drivers y el registro.

Desactivar tareas pesadas de Windows (como la telemetría o el superfetch) para mejorar la velocidad del portátil o PC de sobremesa.

En un equipo que utilice SSD, deshabilitar servicios como SysMain no afectará a la velicidad de arranque y liberará muchos recursos para el procesador.

Servicios seguros para deshabilitar

SysMain (Superfetch): Precarga apps en RAM. En SSD es innecesario y causa picos de disco/CPU.

Windows Search (WSearch): Indexa archivos para búsquedas rápidas. Puede desactivarse si no buscas archivos frecuentemente.

DiagTrack (Telemetría): Envía datos de diagnóstico a Microsoft sin aportar rendimiento.

Xbox Live Services: Servicios para consola Xbox que consumen recursos innecesariamente, si no usas Xbox Game Pass en la PC o juegas títulos de Microsoft puedes desactivarlos.

Servicios de Xbox: Se dividen en tres y se ocupan del guardado y las redes para la consola. Sólo si no usas Xbox en la PC o juegas títulos de Microsoft a través de la aplicacion.

Delivery Optimization (Optimización de entrega) "DoSvc":

Este servicio es famoso por consumir recursos en segundo plano, ya que convierte tu PC en un "servidor" para subir y descargar actualizaciones de Windows a otros usuarios en tu red o en Internet.

Opción 1. Para evitar que la PC (portátil) consuma ancho de banda descargando actualizaciones para otras personas.

Opción 2. Dejarlo activado y cambiar la opción "Equipos de mi red local" en lugar de equipos en Internet". Ve a Configuración > Actualización y Seguridad > Optimización de entrega (o Configuración > Windows Update > Opciones Avanzadas > Optimización de entrega en Windows 10/11.

Usa PowerShell como adminstrador y ejecuta estos comandos:

Stop-Service -Name "SysMain" -Force 
Set-Service -Name "SysMain" -StartupType Disabled
Stop-Service -Name "DiagTrack" -Force 
Set-Service -Name "DiagTrack" -StartupType Disabled
Stop-Service -Name "WSearch" -Force 
Set-Service -Name "WSearch" -StartupType Disabled
Stop-Service -Name "DoSvc" -Force
Set-Service -Name "DoSvc" -StartupType Disabled

Detener y deshabilitar todos los servicios de Xbox Live

$xboxServices = @("XblAuthManager", "XblGameSave", "XboxNetApiSvc")
foreach ($svc in $xboxServices) {
  Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
  Set-Service -Name $svc -StartupType Disabled -ErrorAction SilentlyContinue
}

Límites de inicio (Administrador de tareas)

Pulsa Ctrl + Shift + Esc para abrir el Administrador de tareas, ve a la pestaña Inicio, clic derecho sobre programas que no use (como OneDrive o Spotify, etc.) y seleccione Deshabilitar.

Excluir el antivirus y las aplicaciones

En Configuración > privacidad > Aplicaciones en segundo plano, desactivar las apps de la tienda que no utilice.

Si su disco es SSD no es necesario desactivar Windows Defender.

Si en unos días notas que Windows vuelve a estar pesado (a veces las actualizaciones reactivan algunos servicios), solo tiene que repetir el comando PowerShell o revisar el "Administrador de tareas".

FreeBSD es genial!.

lunes, 6 de abril de 2026

Configuración de LAGG failover en FreeBSD 14.4

LAGG failover en FreeBSD 14.4 em0 (primaria) y wlan0 (respaldo via iwm0)

Fuente:


https://www.ccammack.com/posts/configure-a-wifi-client-on-freebsd
https://wiki.freebsd.org/Devd
https://headthirst.com/freebsd-suspend.html
https://forums.freebsd.org/threads/freebsd-command-line-wifi-manager.89090/
https://www.dwarmstrong.org/freebsd-network-laptop/
https://libreboot.org/docs/bsd/suspend-resume-speedup.html
https://forums.freebsd.org/threads/freebsd-command-line-wifi-manager.89090/
https://forums.freebsd.org/threads/wifi-stops-working-after-suspend-resume.85889/
https://www.reddit.com/r/voidlinux/comments/1lfxurz/wifi_disappears_after_waking_from_suspend_i

Nombres de los dispositivos 802.11 disponibles

sysctl net.wlan.devices
net.wlan.devices: iwm0

Tomando como ejemplo mi computadora portátil (Dell Latitude 7390), la interfaz Ethernet em0 funcionará como puerto maestro y la interfaz inalámbrica wlan0 será el dispositivo de respaldo. Combino las dos interfaces en una interfaz virtual sobrescribiendo la dirección MAC de la interfaz Ethernet con la dirección MAC de la interfaz inalámbrica.

Determinar la dirección MAC de la interfaz inalámbrica

ifconfig wlan0 | grep ether
	ether 18:56:80:f8:98:e6

Cambiar la dirección MAC de la interfaz Ethernet para que coincidan

ifconfig em0 ether 18:56:80:f8:98:e6	

/etc/rc.conf

...
ifconfig_em0="ether 18:56:80:f8:98:e6"
wlans_iwm0="wlan0"
ifconfig_wlan0="WPA"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto failover laggport em0 laggport wlan0 SYNCDHCP"
create_args_wlan0="country ES"
defaultrouter="192.168.88.1"
defaultroute_delay="10"
background_dhclient_lagg0="YES"
... 
Archivo /etc/wpa_supplicant
/etc/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
eapol_version=2
fast_reauth=1

network={
	ssid="MikroTik-39F9C0"	
        psk=755862a5b1a4ef59e2e62590677a75f5317193637a8629dccb18c40e8634a68e
}

Reiniciar

Estado general del LAGG

ifconfig lagg0
lagg0: flags=1008843 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP metric 0 mtu 1500
	options=0
	ether 18:56:80:f8:98:e6
	hwaddr 00:00:00:00:00:00
	inet 192.168.88.50 netmask 0xffffff00 broadcast 192.168.88.255
	laggproto failover lagghash l2,l3,l4
	laggport: em0 flags=1 MASTER
	laggport: wlan0 flags=4 ACTIVE
	groups: lagg
	media: Ethernet autoselect
	status: active
	nd6 options=29 PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL

Ver puerto activo

ifconfig lagg0 | grep -E "laggport|status"
	laggport: em0 flags=1 MASTER 
	laggport: wlan0 flags=4 ACTIVE
	status: active

Estadísticas en detalle

sysctl net.link.lagg
net.link.lagg.lacp.default_strict_mode: 1
net.link.lagg.lacp.debug: 0
net.link.lagg.default_flowid_shift: 16
net.link.lagg.default_use_numa: 1
net.link.lagg.default_use_flowid: 0
net.link.lagg.failover_rx_all: 0

En /etc/rc.conf em0 no debe tener IP propia, es gestionado por lagg0 wlan0 no debe tener DHCP propio cuando está bajo lagg0; el DHCP lo gestiona lagg0. El failover es automático, al detectar pérdida de carrier en em0, el tráfico pasa a wlan0 sin intervención manual.

Sin conexión a Internet después de salir de hibernación

Al salir de hibernación, devd no recrea lagg0 de forma automática. La solución es un script de resume que se ejecute al despertar.

Crear el script de resume-network.sh

/usr/local/sbin/resume-network.sh

#!/bin/sh
sleep 3

# Destruir interfaces
ifconfig lagg0 destroy 2>/dev/null
ifconfig wlan0 destroy 2>/dev/null

# Recrear wlan0 sin country (lo hereda de rc.conf al crear)
ifconfig wlan0 create wlandev iwm0
ifconfig wlan0 country ES 2>/dev/null

# Recrear lagg0
ifconfig lagg0 create
ifconfig lagg0 laggproto failover
ifconfig lagg0 laggport em0
ifconfig lagg0 laggport wlan0
ifconfig lagg0 up

# Arrancar wpa_supplicant
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf

# Esperar asociacion (max 30s)
i=0
while [ $i -lt 30 ]; do
    status=$(ifconfig wlan0 | grep "status:" | awk '{print $2}')
    [ "$status" = "associated" ] && break
    sleep 1
    i=$((i + 1))
done

logger "resume-network: wlan0 status=$status tras ${i}s"

# Matar dhclient previo si existe
pkill -F /var/run/dhclient/dhclient.lagg0.pid 2>/dev/null
sleep 1

# Obtener IP
dhclient lagg0

# Ruta por defecto si dhclient no la puso
sleep 2
netstat -rn | grep -q "^default" || route add default 192.168.88.1

logger "resume-network: completado"

Aumentar timeout de dhclient

vim /etc/dhclient.conf
interface "lagg0" {
    timeout 60;
    retry 10;
}

Configurar devd para se ejecute al despertar

vim /etc/devd/resume-network.conf
notify 100 {
    match "system"      "ACPI";
    match "subsystem"   "Resume";
    action "/usr/local/sbin/resume-network.sh &";
};

Reinicar devd

sudo service devd restart

Comprobar que devd capta el evento revisando tras salir de hibernación

tail -5 /var/log/messages
Apr  5 16:11:50 solaris dhclient[13642]: New IP Address (lagg0): 192.168.88.50
Apr  5 16:11:50 solaris dhclient[13646]: New Subnet Mask (lagg0): 255.255.255.0
Apr  5 16:11:50 solaris dhclient[13650]: New Broadcast Address (lagg0): 192.168.88.255
Apr  5 16:11:50 solaris dhclient[13654]: New Routers (lagg0): 192.168.88.1
Apr  5 16:11:51 solaris root[13671]: resume-network: completado

Al hibernar, FreeBSD destruye las interfaces clonadas (lagg0) y en algunos casos también wlan0. Al despertar, rc.conf no se reprocesa. devd es el mecanismo correcto para reaccionar a eventos ACPI como Resume.

El sleep 3 inicial es importante porque iwm0 necesita unos segundos para que el firmware del adaptador WiFi Intel esté operativo tras el resume.

Ver si devd captó el evento Resume

grep -E "Resume|resume-network" /var/log/messages | tail -5

Apr  5 15:48:07 solaris carlos[12362]: resume-network: wlan0 status=associated tras 3s
Apr  5 15:48:09 solaris carlos[12527]: resume-network: completado
Apr  5 16:11:39 solaris kernel: rtsx0: Resume
Apr  5 16:11:49 solaris root[13506]: resume-network: wlan0 status=associated tras 3s
Apr  5 16:11:51 solaris root[13671]: resume-network: completado

Comprobar que dhclient obtuvo IP

Apr  5 16:11:50 solaris dhclient[27343]: My address (192.168.88.50) was deleted, dhclient exiting
Apr  5 16:11:51 solaris dhclient[28339]: dhclient already running, pid: 28314.
Apr  5 16:11:51 solaris dhclient[28339]: exiting.
Apr  5 16:11:52 solaris dhclient[28317]: connection closed
Apr  5 16:11:52 solaris dhclient[28317]: exiting.
Apr  5 16:11:54 solaris dhclient[28659]: New IP Address (lagg0): 192.168.88.50
Apr  5 16:11:54 solaris dhclient[28663]: New Subnet Mask (lagg0): 255.255.255.0
Apr  5 16:11:55 solaris dhclient[28667]: New Broadcast Address (lagg0): 192.168.88.255
Apr  5 16:11:55 solaris dhclient[28671]: New Routers (lagg0): 192.168.88.1
FreeBSD es genial!.

viernes, 3 de abril de 2026

Crear Rotación de logs FileBrowser FreeBSD 14.4

https://gnulinuxcodigo.blogspot.com/2026/03/filebrowser-con-tailscale-en-freebsd.html


Rotación de logs

Para que los logs no crezcan indefinidamente, se puede configurar newsyslog en FreeBSD

Crear /etc/newsyslog.conf.d/filebrowser.conf

sudo tee /etc/newsyslog.conf.d/filebrowser.conf > /dev/null << EOF
# FileBrowser log rotation - rotates weekly or when > 10MB
/home/carlos/.config/filebrowser/filebrowser.log  carlos:carlos  640  7 10000 *  Z
EOF

Reiniciar servicio

sudo service newsyslog restart
FreeBSD es genial!.

miércoles, 18 de marzo de 2026

FileBrowser con Tailscale HTTPS Habilitado en FreeBSD 14.3

Fuente:

https://tailscale.com/docs/reference/examples/serve
https://tailscale.com/docs/how-to/quickstart
https://tailscale.com/docs/features/access-control
https://filebrowser.org/cli/filebrowser-config-init.html
https://filebrowser.org/cli/filebrowser-users-add.html

Instalar FileBrowser

pkg install filebrowser
which filebrowser
filebrowser version
File Browser v2.52.0/c11c986b7382a5c1f18d83ee7e6093dc0544cff9

Crear esttructura de directorios


Directorio para archivos compartidos

mkdir -p /home/carlos/fileserver

Directorio para configuracion

mkdir -p /home/carlos/.config/filebrowser

Iniciarlizar la base de datos de FileBrowser

filebrowser config init -d /home/carlos/.config/filebrowser/filebrowser.db

Crear usuario administrador

filebrowser users add carlos tu_contraseña_segura \
  --perm.admin \
  --perm.create \
  --perm.delete \
  --perm.download \
  --perm.execute \
  --perm.modify \
  --perm.rename \
  --perm.share \
  -d /home/carlos/.config/filebrowser/filebrowser.db

Explicación de permisos:

--perm.admin → Acceso administrativo completo
--perm.create → Crear archivos y carpetas
--perm.delete → Eliminar archivos
--perm.download → Descargar archivos
--perm.execute → Ejecutar comandos
--perm.modify → Modificar archivos
--perm.rename → Renombrar archivos/carpetas
--perm.share → Compartir enlaces públicos

Crear usuario adicional con permisos limitados


Detener completamente filebrowser

sudo service FileBrowser stop  
sudo pkill -9 filebrowser
filebrowser users add invitado password123 \
  --perm.download \
  --scope /home/carlos/fileserver/publico \
  -d /home/carlos/.config/filebrowser/filebrowser.db
 

Comprobar configuracion

 filebrowser config cat -d /home/carlos/.config/filebrowser/filebrowser.db
 

Ver usuarios

  
  filebrowser users ls -d /home/carlos/.config/filebrowser/filebrowser.db
  

Crear archivo /home/carlos/.config/filebrowser/config.json

  {
  "port": 8080,
  "baseURL": "",
  "address": "0.0.0.0",
  "log": "/home/carlos/.config/filebrowser/filebrowser.log",
  "database": "/home/carlos/.config/filebrowser/filebrowser.db",
  "root": "/home/carlos/fileserver"
}

Crear script de servicio rc.d sudo vim /usr/local/etc/rc.d/filebrowser

#!/bin/sh
# PROVIDE: filebrowser
# REQUIRE: NETWORKING DAEMON tailscaled
# KEYWORD: shutdown

. /etc/rc.subr

name="filebrowser"
desc="Web File Browser"
rcvar="${name}_enable"

load_rc_config $name

: ${filebrowser_enable:="NO"}
: ${filebrowser_runas:="carlos"}
: ${filebrowser_config:="/home/carlos/.config/filebrowser/config.json"}

procname="/usr/local/bin/${name}"
command="/usr/sbin/daemon"

command_args="-c -u ${filebrowser_runas} -t \"${desc}\" \
    ${procname} -c ${filebrowser_config}"

start_precmd="filebrowser_prestart"

filebrowser_prestart()
{
    log_file="/home/carlos/.config/filebrowser/filebrowser.log"
    if [ ! -f "${log_file}" ]; then
        touch "${log_file}"
        chown ${filebrowser_runas} "${log_file}"
        chmod 640 "${log_file}"
    fi
}

run_rc_command "$1"

Permisos correctos

sudo chmod 555 /usr/local/etc/rc.d/filebrowser

Habilitar FileBrowser en rc.conf

sudo sysrc filebrowser_enable="YES"

Comprobar

sudo service filebrowser status
filebrowser is running as pid 1918.
ls -ld /var/run/filebrowser
drwxr-xr-x  2 carlos wheel 3 Apr  3 09:21 /var/run/filebrowser
sudo cat /var/run/filebrowser/filebrowser.pid
1918
tail -10 /home/carlos/.config/filebrowser/filebrowser.log 
2026/04/02 23:57:05 Listening on [::]:8080
2026/04/03 08:40:10 Got signal: terminated
2026/04/03 08:40:10 Stopped serving new connections.
2026/04/03 08:40:10 Graceful shutdown complete.
2026/04/03 08:41:06 Listening on [::]:8080
2026/04/03 08:46:48 Got signal: terminated
2026/04/03 08:46:48 Stopped serving new connections.
2026/04/03 08:46:48 Graceful shutdown complete.
2026/04/03 08:47:40 Listening on [::]:8080
2026/04/03 09:21:27 Listening on [::]:8080

Verificar Tailscale

tailscale status
100.69.99.114  tornado  nombreusuario@  freebsd  - 

Si no está corriendo

sudo service tailscaled start
tailscale up

Recomendación de mantenimiento


Nunca vuelva a ejecutar tailscale up sin --hostname o sin haber hecho tailscale logout antes. Uso correcto:

tailscale logout
tailscale up --hostname=tornado

Actualizar reglas de PF

# ========================================
# Configuración PF para tornado.local.com
# ========================================

# MACROS (Variables)
ext_if = "wlan0"                      # Interfaz de red
tailscale_if = "tailscale0"
local_net = "192.168.88.0/24"         # Red local permitida
ssh_port = "22"                       # Puerto SSH
filebrowser_port = "8080"
filebrowser_https_port = "8443"
http_port = "80"
https_port = "443"

# --- OPCIONES ---
set skip on lo0                       # No filtrar loopback
set block-policy drop                 # Descartar paquetes bloqueados silenciosamente
set loginterface $ext_if              # Interfaz para estadísticas

# --- SCRUB (Normalización de paquetes) ---
scrub in all                          # Normalizar todo el tráfico entrante

# --- POLÍTICA PREDETERMINADA ---
block all                             # Bloquear todo por defecto

# --- REGLAS ANTISPOOF ---
antispoof quick for $ext_if           # Protección contra IP spoofing

# --- PERMITIR LOOPBACK ---
pass quick on lo0 all                 # Permitir todo en loopback

# --- PERMITIR TRÁFICO EN TAILSCALE ---
pass quick on $tailscale_if all keep state

# --- Solo permite TAILSCALE ---
pass in quick on $tailscale_if all keep state

# --- PERMITIR ICMP (ping) desde red local ---
pass in quick on $ext_if inet proto icmp from $local_net to any icmp-type { echoreq } keep state

# --- PERMITIR SSH SOLO DESDE RED LOCAL ---
pass in quick on $ext_if proto tcp from $local_net to ($ext_if) port $ssh_port keep state

# --- PERMITIR FILEBROWSER HTTP DESDE RED LOCAL ---
pass in quick on $ext_if proto tcp from $local_net to ($ext_if) port $filebrowser_port keep state

# --- PERMITIR FILEBROWSER HTTP DESDE TAILSCALE ---
pass in quick on $tailscale_if proto tcp to any port $filebrowser_port keep state

# --- PERMITIR FILEBROWSER HTTPS DESDE RED LOCAL ---
pass in quick on $ext_if proto tcp from $local_net to ($ext_if) port $filebrowser_https_port keep state

# --- PERMITIR FILEBROWSER HTTPS DESDE TAILSCALE ---
pass in quick on $tailscale_if proto tcp to any port $filebrowser_https_port keep state

# --- PERMITIR TRÁFICO SALIENTE ---
pass out quick on $ext_if all keep state

# --- LOGGING (opcional) ---
# pass in log on $ext_if proto tcp from $local_net to ($ext_if) port $ssh_port keep state

Recargar reglas

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

Iniciar filebrowser

sudo service filebrowser start

Estado de filebrowser

sudo service filebrowser status
Password:
filebrowser is running as pid 4721

Puerto de escucha

sudo sockstat -4l | grep 8080
carlos   filebrowse  1322 5   tcp46  *:8080

Acceder a FileBrowser


Desde la red local:

http://192.168.88.183:8080

Desde Tailscale HTTPS (desde cualquier lugar):

https://100.69.99.114:443
https://tornado.tail0788a4.ts.net

Credenciales

Usuario carlos
Contraseña tu_contraseña_segura

Ver logs de diagnóstico

tail -f /home/carlos/.config/filebrowser/filebrowser.log

Proceso filebrowser

 
ps aux | grep filebrowser    
carlos     5542   0.0  0.4 1270900 30200  -  I    23:57 \
0:05.52 /usr/local/bin/filebrowser -c /home/carlos/.config/filebrowser/config.json

Reglas PF activas

sudo pfctl -sr 
Password:
scrub in all fragment reassemble
block drop all
block drop in quick on ! wlan0 inet from 192.168.88.0/24 to any
block drop in quick inet from 192.168.88.183 to any
pass in quick on wlan0 inet proto tcp from 192.168.88.0/24 to \
(wlan0) port = ssh flags S/SA keep state
pass in quick on wlan0 inet proto tcp from 192.168.88.0/24 to \
(wlan0) port = http-alt flags S/SA keep state
pass in quick on wlan0 inet proto tcp from 192.168.88.0/24 to \
(wlan0) port = 8443 flags S/SA keep state
pass in quick on wlan0 inet proto icmp from 192.168.88.0/24 to \
any icmp-type echoreq keep state
pass out quick on wlan0 all flags S/SA keep state
pass quick on lo0 all flags S/SA keep state
pass quick on tailscale0 all flags S/SA keep state

IMPORTANTE: Detener FileBrowser antes de modificar la base de datos

sudo service filebrowser stop
sudo pkill -9 filebrowser

Cambiar contraseña de usuario

filebrowser users update carlos \
  --password nueva_contraseña \
  -d /home/carlos/.config/filebrowser/filebrowser.db

Habilitar branding personalizado

filebrowser config set \
  --branding.name "Servidor de Carlos" \
  --branding.disableExternal \
  -d /home/carlos/.config/filebrowser/filebrowser.db
  

Cambiar a tema oscuro por defecto

filebrowser config set \
  --theme dark \
  -d /home/carlos/.config/filebrowser/filebrowser.db
  

Reiniciar FileBrowser

sudo service filebrowser start  

Seguridad adicional


Deshabilitar registro público

filebrowser config set --signup false -d /home/carlos/.config/filebrowser/filebrowser.db
 

Configurar límite de sesión

filebrowser config set --auth.recaptcha.secret "" -d /home/carlos/.config/filebrowser/filebrowser.db

Copia de seguridad de configuración


Copia de seguridad de base de datos

cp /home/carlos/.config/filebrowser/filebrowser.db /home/carlos/.config/filebrowser/filebrowser.db.backup

Copia de seguridad de archivos

tar -czf /home/carlos/fileserver-backup-$(date +%Y%m%d).tar.gz /home/carlos/fileserver/

Resumen de comandos de gestión


Reiniciar servicio

sudo service filebrowser restart

Detener FileBrowser completamente

sudo service filebrowser stop
sudo pkill -9 filebrowser

Limpiar el pidfile

rm -f /var/run/filebrowser/filebrowser.pid

Iniciar FileBrowser limpiamente

sudo service filebrowser start 

Verificar que solo hay un proceso

sudo ps aux | grep "filebrowser"
carlos   1322  0.0  0.4 1279096 29736 v0- I   Sun23  1:11.45 \
/usr/local/bin/filebrowser -c /home/carlos/.config/filebrowser/config.json

Ver logs en tiempo real

tail -f /home/carlos/.config/filebrowser/filebrowser.log

Listar usuarios. Hay que detener FileBrowser antes

sudo service filebrowser stop
sudo pkill -9  filebrowser
filebrowser users ls -d /home/carlos/.config/filebrowser/filebrowser.db

Ver configuración completa

filebrowser config cat -d /home/carlos/.config/filebrowser/filebrowser.db

Navegador local

http://localhost:8080

Red local

http://192.168.88.183:8080

Acceso remoto desde Internet (con Tailscale conectado) Sin Tailscale no funcionará (esto es correcto por seguridad).

http://100.69.99.114:8080
https://https://tornado.tail0788a4.ts.net

Configuración completada exitosamente: FileBrowser instalado y configurando Autenticación habilitada (usuario: carlos) Acceso desde red local (192.168.88.0/24) Acceso remoto seguro vía Tailscale Firewall PF configurado correctamente Autoarranque habilitado (rc.conf)

Tailscale HTTPS (certificados automáticos de Tailscale)

Tailscale puede proporcionar certificados HTTPS válidos de forma automática para un nodo.

Esto generará certificados en /var/lib/tailscale/certs/ o /usr/local/tailscale/certs/. Si no existe el directorio, Tailscale los colocará en el directorio actual.

Obtener el nombre MagicDNS de su nodo

tailscale status

Desde cualquier dispositivo con Tailscale conectado

https://tornado.tail0788a4.ts.net

¡El certificado será válido y reconocido por todos los navegadores!

Usar Tailscale Serve (proxy HTTPS automático)

sudo tailscale serve --bg http://127.0.0.1:8080

Exponer FileBrowser con HTTPS automático en

https://tornado.tail0788a4.ts.net

No es necesario configurar nada más, Tailscale maneja todo el HTTPS

Comprobar

tailscale serve status
https://tornado.tail0788a4.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:8080

Obtener su URL completa

tailscale status --json | grep tornado    
    "DNSName": "tornado.tail0788a4.ts.net.",
    "tornado.tail0788a4.ts.net"

Hacer permanente la configuración

Para que Tailscale Serve se mantenga después de reiniciar:

Crear un servicio rc.d

sudo vim /usr/local/etc/rc.d/tailscale_serve

#!/bin/sh
# PROVIDE: tailscale_serve
# REQUIRE: tailscaled filebrowser
# KEYWORD: shutdown

. /etc/rc.subr

name="tailscale_serve"
rcvar="tailscale_serve_enable"

load_rc_config $name

: ${tailscale_serve_enable:="NO"}

start_cmd="${name}_start"
stop_cmd="${name}_stop"

tailscale_serve_start()
{
    echo "Starting Tailscale Serve..."
    /usr/local/bin/tailscale serve --bg http://127.0.0.1:8080
}

tailscale_serve_stop()
{
    echo "Stopping Tailscale Serve..."
    /usr/local/bin/tailscale serve reset
}

run_rc_command "$1"

Otorgar permisos

sudo chmod +x /usr/local/etc/rc.d/tailscale_serve

Habilitar tailscale_serve

sudo sysrc tailscale_serve_enable="YES"
sudo service tailscale_serve start

Habilitar HTTPS y Serve en Tailscale


Ir a esta URL desde el navegador:

https://login.tailscale.com/admin/machines

Encontrar su máquina (por ejemplo, "tornado")

Hacer clic en los 3 puntos -> "Enable HTTPS"

En la página que se abre: Marcar "HTTPS certificates" (requerido) NO marque "Funnel" (a menos que quiera acceso público desde Internet)

Nota: Serve = Acceso solo desde tu Tailnet (privado) - Esto es lo que quiere

Hacer clic en "Enable HTTPS and Serve" o "Enable"

Volver a configurar Serve

sudo tailscale serve --bg http://127.0.0.1:8080

Debería funcionar sin errores

Verificar serve

tailscale serve status 
https://tornado.tail0788a4.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:8080

Desde cualquier dispositivo con Tailscale

https://tornado.tail0788a4.ts.net

Cuando habilita HTTPS en Tailscale, el nombre de su dispositivo (tornado.tail0788a4.ts.net) se escribirá en un Certificate Transparency Log público. Esto es un requisito de Let's Encrypt y no se puede evitar. Esto NO expone:

Su IP
Sus archivos
El contenido de tu servidor

Solo registra:

El nombre del dispositivo (tornado.tail0788a4.ts.net)

Comprobar que MagicDNS está habilitado

sudo tailscale status --json | grep -i magic
    "InMagicSock": false,
  "MagicDNSSuffix": "tail0788a4.ts.net",
    "MagicDNSSuffix": "tail0788a4.ts.net",
    "MagicDNSEnabled": true
      "InMagicSock": true,
      "InMagicSock": true,
      "InMagicSock": true,
      "InMagicSock": true,

FileBrowser no arranca


Limpiar procesos

sudo pkill -9 filebrowser
rm -f /var/run/filebrowser/filebrowser.pid

Ver error exacto

filebrowser -c /home/carlos/.config/filebrowser/config.json
2026/03/27 09:17:02 Using config file: /home/carlos/.config/filebrowser/config.json
2026/03/27 09:17:02 Using database: /home/carlos/.config/filebrowser/filebrowser.db

Ver logs

  tail -50 /home/carlos/.config/filebrowser/filebrowser.log

Iniciar filebrowser manualmente

filebrowser -c /home/carlos/.config/filebrowser/config.json &

Configuración final completada

Elemento		  Valor
URL de acceso		  https://tornado.tail0788a4.ts.net
Certificado SSL 	  Let's Encrypt (válido, sin advertencias)
FileBrowser		  HTTP en localhost:8080
Tailscale Serve		  HTTPS proxy en puerto 443
Acceso			  Solo desde su Tailnet (privado)
Usuario			  carlos
Usuario no privilegiado	  invitado
https://gnulinuxcodigo.blogspot.com/2026/04/crear-rotacion-de-logs-filebrowser.html

FreeBSD es genial!.