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
Elegir una ubicación y descargar el archivo de configuración. Asegurarse de generar el par de claves con anticipación de modo que la clave privada se agregue al archivo de configuración.

Descargar el 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
 82.102.18.210
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!.