Páginas

sábado, 5 de septiembre de 2026

Configuración de WiFi con IP fija en FreeBSD 14.4

Configuración de WiFi con IP fija en FreeBSD 14.4

Incluye script de resume (opcional) para recuperar conexión tras hibernación

Configuración básica en /etc/rc.conf

Para usar una IP fija en wlan0, añadir o modificar estas líneas:

wlans_iwm0="wlan0"
ifconfig_wlan0="WPA inet 192.168.88.51 netmask 255.255.255.0"
defaultrouter="192.168.88.1"

En FreeBSD, la forma más sencilla y moderna de obtener el firmware para tu tarjeta inalámbrica es usando la herramienta fwget. Esta utilidad detecta automáticamente el hardware de tu sistema e instala los paquetes de firmware necesarios

sudo wget

Este comando analizará el hardware, identificará qué controladores y firmwares necesita e instalará los paquetes correspondientes automáticamente.

Configuración en /boot/loader.conf

Después de instalado el firmware, para que el sistema lo cargue al arrancar, es necesario agregar las siguientes líneas al archivo /boot/loader.conf

if_iwm_load="YES"
iwm8265fw_load="YES"
legal.intel_iwm.license_ack=1

Reiniciar el sistema para que los módulos se carguen correctamente

 reboot
Notas importantes: Asegúrarse de que /etc/wpa_supplicant.conf contiene los datos de su red WiFi. cat /etc/wpa_supplicant.conf
# /etc/wpa_supplicant.conf written by wifimgr(8)
ctrl_interface=/var/run/wpa_supplicant
eapol_version=2
fast_reauth=1

network={
	ssid="MikroTik-39F9C0"
	psk=755864a8b1a4ef59e2e62590977a75f5317193637a8629dccb18c40e8638a68e
}

Al usar IP fija, no se necesita dhclient. Por tanto, desactivar background_dhclient (ponerlo a "NO" o eliminar la línea) para evitar que sobrescriba la configuración estática al despertar:

background_dhclient="NO"

¿El sistema se recupera solo tras hibernación?

En la mayoría de los casos, sí. Al despertar, FreeBSD intenta restaurar el estado de las interfaces. Si el driver (iwm) y el subsistema WiFi funcionan correctamente, la interfaz se reasociará y mantendrá la IP fija. Esto suele funcionar bien con hardware Intel y configuraciones sencillas.

Sin embargo, si la asociación falla o la interfaz queda en un estado inconsistente (por ejemplo, si el firmware no responde o hay eventos de red que disparan dhclient). Si al despertar no tiene conexión, se puede usar el script de resume que se describe a continuación.

Script opcional para recuperar la conexión (resume-wlan.sh)

Este script destruye y recrea wlan0, fuerza la asociación, asigna la IP fija y la ruta por defecto, y mata posibles procesos dhclient que puedan interferir.

Crear el script en /usr/local/sbin/resume-wlan.sh

#!/bin/sh
# Script para restaurar WiFi tras hibernación (IP fija)
# Destruye y recrea wlan0, espera asociación, asigna IP y ruta.

sleep 3

# Destruir y recrear wlan0
ifconfig wlan0 destroy 2>/dev/null
ifconfig wlan0 create wlandev iwm0 country ES
ifconfig wlan0 up

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

# Esperar asociación (hasta 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-wlan: status=$status tras ${i}s"

if [ "$status" != "associated" ]; then
    logger "resume-wlan: ERROR - no asociado"
    exit 1
fi

# Asignar IP fija
ifconfig wlan0 inet 192.168.88.51 netmask 255.255.255.0

# Añadir ruta por defecto
route add default 192.168.88.1

# Matar posibles dhclient que interfieran
pkill -f "dhclient.*wlan0" 2>/dev/null

# Verificar pasados 5 segundos y reañadir si es necesario
sleep 5
if ! netstat -rn | grep -q "^default.*wlan0"; then
    route add default 192.168.88.1
    logger "resume-wlan: ruta reañadida por seguridad"
fi

logger "resume-wlan: completado (IP fija y ruta activas)"

Darle permisos de ejecución:

chmod +x /usr/local/sbin/resume-wlan.sh

Configurar devd para ejecutar el script al despertar

Crea el archivo /etc/devd/resume-wlan.conf con este contenido:

notify 100 {
    match "system"      "ACPI";
    match "subsystem"   "Resume";
    action "/usr/local/sbin/resume-wlan.sh &";
};

Reiniciar devd:

service devd restart

¿Cuándo usar el script y cuándo no?

Si no se utiliza el script:

El sistema se encarga de restaurar la interfaz al despertar. Es la opción más simple y recomendable si funciona correctamente en el hardware. Si después de probar varias hibernaciones todo va bien, no es necesario el script.

Si se usa el script:

Aporta una capa extra de fiabilidad, especialmente si se ha tenido problemas de conectividad tras la hibernación. También es útil si se cambia de red o si el driver WiFi es propenso a fallar.

Recomendación: Pruebrar primero sin el script. Si la conexión se pierde ocasionalmente, activar el script.

Notas adicionales Si en algún momento se cambia a DHCP, recordar eliminar la IP fija y habilitar background_dhclient de nuevo. Hay que asegurar de que el país (country ES) coincide con la región. Puede omitirse si no es necesario.

Script si se utiliza IP dinámica (cambia a DHCP)

Vamos a adaptar el script para que funcione con DHCP en lugar de IP fija. Esto es útil si quieremos que la interfaz obtenga la IP automáticamente al despertar (por ejemplo, si cambias de red con frecuencia o el router asigna IPs dinámicamente).

#!/bin/sh
# Script para restaurar WiFi tras hibernación (DHCP)
# Destruye y recrea wlan0, espera asociación, y lanza dhclient.

sleep 3

# Destruir y recrear wlan0
ifconfig wlan0 destroy 2>/dev/null
ifconfig wlan0 create wlandev iwm0 country ES
ifconfig wlan0 up

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

# Esperar asociación (hasta 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-wlan: status=$status tras ${i}s"

if [ "$status" != "associated" ]; then
    logger "resume-wlan: ERROR - no asociado"
    exit 1
fi

# Obtener IP por DHCP
dhclient wlan0

# Asegurar ruta por defecto (por si dhclient no la pone)
sleep 2
if ! netstat -rn | grep -q "^default.*wlan0"; then
    # Intenta obtener el gateway de la concesión DHCP (opcional)
    # Si no funciona, puedes poner un gateway fijo o simplemente reintentar dhclient.
    logger "resume-wlan: ruta por defecto no encontrada, reintentando dhclient"
    dhclient wlan0
fi

logger "resume-wlan: completado (DHCP)"
FreeBSD es genial!.

viernes, 4 de septiembre de 2026

Conectar Surfshark VPN protocolo WireGuard FreeBSD 14.4

2. FreeBSD 14.4 Wireguard VPN Surfshark
Elige una ubicación y descarga el archivo de configuración. Asegúrate de generar el par de claves con anticipación de modo que la clave privada se agregue al archivo de configuración.

Descargar archivo de configuración

Archivo /etc/rc.conf

wireguard_enable="YES"
wireguard_interface="wg0"

Copiar el archivo de configuración descargado y renombrado como wg0

cp fr-par.conf /usr/local/etc/wireguard/wg0.conf

Luego ejecutar

wg-quick up wg0

comprobar dirección IP VPN

 curl ifconfig.me
FreeBSD es genial!.

jueves, 3 de septiembre de 2026

FreeBSD 14.4 WireGuard VPN Surfshark

1. Conectar Surfshark VPN WireGuard FreeBSD 14.4
Análisis de la tabla de rutas

ifconfig

  em0: flags=8842<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=4e524bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,LRO,WOL_MAGIC,VLAN_HWFILTER,VLAN_HWTSO,RXCSUM_IPV6,TXCSUM_IPV6,HWSTATS,MEXTPG>
	ether e4:b9:7a:6b:96:cd
	media: Ethernet autoselect
	status: no carrier
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
wlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=0
	ether 18:56:80:f8:98:e6
	inet 192.168.88.51 netmask 0xffffff00 broadcast 192.168.88.255
	groups: wlan
	ssid MikroTik-39F9C0 channel 1 (2412 MHz 11g) bssid c4:ad:34:39:f9:c0
	regdomain FCC country US authmode WPA2/802.11i privacy ON
	deftxkey UNDEF AES-CCM 2:128-bit AES-CCM 3:128-bit
	AES-CCM ucast:128-bit txpower 30 bmiss 10 scanvalid 60 protmode CTS
	wme roaming MANUAL
	parent interface: iwm0
	media: IEEE 802.11 Wireless Ethernet OFDM/54Mbps mode 11g
	status: associated
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
pflog0: flags=1000141<UP,RUNNING,PROMISC,LOWER_UP> metric 0 mtu 33152
	options=0
	groups: pflog
wg0: flags=10080c1<UP,RUNNING,NOARP,MULTICAST,LOWER_UP> metric 0 mtu 1420
	options=80000<LINKSTATE>
	inet 10.14.0.2 netmask 0xffff0000
	groups: wg
	nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>
tailscale0: flags=1008003<UP,BROADCAST,MULTICAST,LOWER_UP> metric 0 mtu 1280
	options=4080000<LINKSTATE,MEXTPG>
	groups: tun
	nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>
	Opened by PID 1452

netstat -rn

Routing tables

Internet:
Destination        Gateway            Flags         Netif Expire
0.0.0.0/1          link#5             US              wg0
default            192.168.88.1       UGS           wlan0
10.14.0.2          link#2             UH              lo0
85.204.70.87       192.168.88.1       UGHS          wlan0
128.0.0.0/1        link#5             US              wg0
192.168.88.0/24    link#3             U             wlan0
192.168.88.51      link#2             UHS             lo0

Ruta por defecto

Ruta por defecto (default) 192.168.88.1 por wlan0 Es la ruta genérica, pero no es la que se usa para la mayoría del tráfico.

Rutas VPN (Wireguard)
0.0.0.0/1 y 128.0.0.0/1 ambas apuntan a wg0

Estas dos rutas cubren todo el rango IPv4 (0.0.0.0/1 y 128.0.0.0/1 = 0.0.0.0/0).

Como son más específicas que default, todo el tráfico (excepto las excepciones) se envía por wg0, es decir, por la VPN

Excepción para el servidor VPN

85.204.70.87 va directamente por wlan0 (gateway local)

Esa IP es el endpoint de WireGuard de Surfshark. Sin esta ruta, el tráfico del túnel intetaría pasar por el propio túnel (bucle) y fallaría.

Red local

192.168.88.0/24 por wlan0. Así puedes acceder a tu router, impresoras, etc., sin pasar por la VPN.

IP propia (loopback)

192.168.88.51 y 10.14.0.2 están en lo0 como direcciones locales (para evitar enrutamiento externo).

¿Qué significa esto en la práctica?

Tu IP pública (la que ven los sitios web) es la de Surfshark, no la de tu router.

El tráfico de navegación (HTTP/HTTPS, DNS, etc.) pasa por el túnel WireGuard.

El tráfico local (a tu router, otros PCs en 192.168.88.x) no pasa por la VPN.

El servidor VPN se alcanza directamente por WiFi, sin pasar por el túnel (para evitar bucles).

Tailscale está presente pero no parece estar enrutando tráfico por defecto (quizás solo para acceso a otros nodos).

Destruir lagg0 y limpiar wlan0

sudo ifconfig lagg0 destroy
sudo ifconfig wlan0 destroy

Crear wlan0 limpio con la configuración correcta

sudo ifconfig wlan0 create wlandev iwm0 country ES
sudo ifconfig wlan0 up

Archivo /etc/wpa_supplicant

 
/etc/wpa_supplicant.conf written by wifimgr(8)
ctrl_interface=/var/run/wpa_supplicant
eapol_version=2
fast_reauth=1

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

Iniciar wpa_supplicant (si no está corriendo)

sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf

Esperar a que se asocie (opcional, pero recomendado)

sleep 5
ifconfig wlan0 | grep status

Asignar IP fija y ruta por defecto

sudo ifconfig wlan0 inet 192.168.88.51 netmask 255.255.255.0
sudo route add default 192.168.88.1

Reiniciar WireGuard para que use la nueva interfaz

sudo wg-quick down wg0 && wg-quick up wg0 # 0 sudo service wireguard restart

Archivo /etc/pf.conf

/etc/pf.conf
ext_if="wlan0"
torrent="53541"
vpn_if="wg0"
wireguard="51820"
lan_net="192.168.88.0/24"

set block-policy return
set skip on lo

scrub in on $ext_if all fragment reassemble

table <jails> persist

nat on $ext_if from <jails> to any -> ($ext_if:0)
rdr-anchor "rdr/*"

block in all

antispoof for $ext_if inet

# Salida: todo el tráfico local permitido y trackeado
pass out quick keep state

# Entrada SSH
pass in quick inet proto tcp from $lan_net to any port ssh flags S/SA keep state

# Entrada VPN WireGuard (túnel Surfshark)
pass in quick on $vpn_if all keep state
pass out quick on $vpn_if all keep state

# Entrada qBittorrent
pass in quick on $ext_if inet proto { tcp } to port $torrent

# Entrada ICMP básico (diagnóstico)
pass in quick on $ext_if inet proto { icmp } all icmp-type { echoreq, unreach }

Verificar

¿La ruta por defecto apunta a wlan0 y las rutas VPN cubren el resto?

netstat -rn | grep -E "(default|wg0|wlan0)"

¿WireGuard está activo?

wg show 
interface: wg0
  public key: pkpZvkWaVDd6DmEb3cl9DEvsnOKl9dvZVAP+KMJLZCs=
  private key: (hidden)
  listening port: 58461

peer: AsvLuvKKAGdc67aA/vHA3vb61S6YnDGx2Pd4aP4wal8=
  endpoint: 82.102.18.179:51820
  allowed ips: 0.0.0.0/0
  latest handshake: 1 minute, 14 seconds ago
  transfer: 1.39 MiB received, 1.51 MiB sent

ping -c 8.8.8.8

Mostrar la IP pública (la IP de Surfshark)

curl -s ifconfig.me
FreeBSD es genial!.

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!.

jueves, 12 de marzo de 2026

Solucionar error librería compartida not found Alacritty FreeBSD 14.3

Solucionar error Shared object "libLLVM.so.19.1" not found Alacritty FreeBSD 14.3

alacritty &
[1] 87350

 libEGL warning: MESA-LOADER: failed to open iris: Shared object "libLLVM.so.19.1" \
 not found, required by "iris_dri.so" (search paths /usr/local/lib/dri, suffix _dri)

libEGL warning: MESA-LOADER: failed to open zink: Shared object "libLLVM.so.19.1" \
not found, required by "zink_dri.so" (search paths /usr/local/lib/dri, suffix _dri)

libEGL warning: MESA-LOADER: failed to open swrast: Shared object "libLLVM.so.19.1" \
not found, required by "swrast_dri.so" (search paths /usr/local/lib/dri, suffix _dri)

Error: Error { raw_code: Some(12289), raw_os_message: None, kind: InitializationFailed }

[1] + 87350 exit 1   alacritty

Causa

Los controladores iris (Intel), zink (capa de traducción Vulkan) y swrast (software rasterizador) fueron compilados contra LLVM 19, pero la librería compartida correspondiente no está instalada en el sistema y si lo está el sistema no la encuentra.

Comprobar que LLVM19 esta instalado

pkg info | grep llvm
linux-rl9-llvm-20.1.8          The Low Level Virtual Machine suite (Rocky Linux 9.7)
llvm18-18.1.8_2                LLVM and Clang
llvm19-19.1.7_1                LLVM and Clang
spirv-llvm-translator-llvm19-19.1.14 Bi-directional translation between SPIR-V and LLVM IR

Comprobar que el archivo existe en la ruta que por defecto es buscado por el programa

ls -l /usr/local/lib/libLLVM.so.19.1
ls: /usr/local/lib/libLLVM.so.19.1: No such file or directory

Verificar que la existencia real de la biblioteca

find /usr/local -name "libLLVM.so.19.1" 2>/dev/null 

/usr/local/llvm19/lib/libLLVM.so.19.1

existe, pero está en /usr/local/llvm19/lib/, un directorio que no está en las rutas de búsqueda por defecto del enlazador dinámico. Hay que hacer que el sistema la encuentre

Solución definitiva

Esta es la opción más ordenada y escalable si en el futuro se necesitan más bibliotecas de LLVM 19.

Agregar el directorio a la configuración de ldconf


Crear archivo de configuración para ldconfig

echo "/usr/local/llvm19/lib" | sudo tee /usr/local/libdata/ldconfig/llvm19.conf

Actualizar la caché de bibliotecas compartidas

sudo ldconfig -m /usr/local/llvm19/lib

Comprobar que se resuelve la dependencia

ldd /usr/local/lib/dri/iris_dri.so | grep LLVM
	libLLVM.so.19.1 => /usr/local/llvm19/lib/libLLVM.so.19.1 (0x13cd9c800000)

Abrir Alacritty

 
alacritty &

Muestra información de versión al iniciar

alacritty -v
Created log file at "/tmp/Alacritty-2576.log"
[0.000017635s] [INFO ] [alacritty] Welcome to Alacritty
[0.000143511s] [INFO ] [alacritty] Version 0.16.1
[0.000156837s] [INFO ] [alacritty] Running on X11
[0.002709829s] [INFO ] [alacritty] Configuration files loaded from:
                       "/home/carlos/.config/alacritty/alacritty.toml"
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!.