Páginas

martes, 15 de abril de 2025

Script sh Replicar Instantáneas de Conjunto de Datos ZFS desde Servidor FreeBSD Local a otra Máquina FreeBSD Externa

Fuente:

https://www.iceflatline.com/2015/07/using-zfs-replication-features-in-freebsd-to-improve-my-offsite-backups/

El autor de este sencillo e ingenioso guión es iceflatline. Contiene algunas modificaciones para adaptarlo a este laboratorio

https://gnulinuxcodigo.blogspot.com/2025/03/crear-particiones-en-disco-duro-usb-con.html

Conjuntos de datos zbackup

carlos@tormenta:~ % zfs list -r zbackup | grep "/zbackup*"
zbackup                            48.9G  1.71T  4.86M  /zbackup
zbackup/solaris                    40.8G  1.71T    96K  /zbackup/solaris
zbackup/solaris/home               40.8G  1.71T    96K  /zbackup/home
zbackup/solaris/home/carlos        40.8G  1.71T  39.9G  /zbackup/home/carlos
zbackup/tormenta-confiles           800K  1.71T   800K  /zbackup/tormenta-confiles
zbackup/usr                        8.16G  1.71T   104K  /zbackup/usr
zbackup/usr/backup                 7.80G  1.71T   104K  /zbackup/usr/backup
zbackup/usr/backup/docs            7.80G  1.71T  7.80G  /zbackup/usr/backup/docs
zbackup/usr/home                    368M  1.71T   132M  /zbackup/usr/home
#!/bin/sh 
### BEGIN INFO
# PROVIDE: 
# REQUIRE: 
# KEYWORD: 
# Description:	
# This script is used to replicate incremental zfs snapshots daily from one 
# pool/dataset(s) to another using ZFS send and receive. 
# The number of snapshots to retain is defined in the variable retention.
# Note that an initial full snapshot must be created and sent to destination 
# before this script can be successfully used. 
# Author: iceflatline <iceflatline@gmail.com>
#
# OPTIONS:
# -R: Generate replication stream recursively
# -i: Generate incremental stream
# -v: Be verbose
# -u: Do not mount received stream,
# -d: Use the full sent snapshot path without the first element (without pool 
# name) to determine the name of the new snapshot
# -F: Destroy snapshots and file systems that do not exist on the sending side. 
### END INFO
 
### INICIO DEL GUION

# Estas variables se nombran primero porque están anidadas en otras variables. 
snap_prefix=snap 
retention=30
 
# Se necesitan rutas completas a estas utilidades al ejecutar el script desde 
# cron.
date=/bin/date
grep=/usr/bin/grep
sed=/usr/bin/sed
sort=/usr/bin/sort
xargs=/usr/bin/xargs
zfs=/sbin/zfs

src_0="zroot/home"
dst_0="zbackup/solaris"
host="root@192.168.88.160"
today="$snap_prefix-`date +%Y%m%d`"
yesterday="$snap_prefix-`date -v -1d +%Y%m%d`"
snap_today="$src_0@$today"
snap_yesterday="$src_0@$yesterday"
snap_old=`$zfs list -t snapshot -o name | $grep "$src_0@$snap_prefix-*" | \
$sort -r | $sed 1,${retention}d | $sort | $xargs -n 1`
log=/home/carlos/cronlog

# snap_old_dst_0 lista las instantaneas > retention en el pool destino zbackup
dst_0_old="zbackup/solaris"
snap_old_dst_0=`ssh $host $zfs list -t snapshot -o name | \
$grep "$dst_0_old@$snap_prefix*" | $sort -r | $sed 1,${retention}d | $sort \
| $xargs -n 1`


# Crea una línea en blanco entre la entrada de registro anterior y esta
echo >> $log
 
# Imprimir el nombre del script.
echo "zfsrep.sh" >> $log

# Imprime la fecha de hoy
$date >> $log

# Crea una linea en blanco
echo >> $log
 
# Busca la instantánea de hoy 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

# Busque la instantánea de ayer y, si la encuentra, realice una replicación 
# incremental; de lo contrario, imprima un mensaje de error
if $zfs list -H -o name -t snapshot | $sort | $grep "$snap_yesterday$" > \
/dev/null 
then
	echo "La instantánea de ayer '$snap_yesterday' existe. Continuando con 
    # la replicacion..." >> $log
	$zfs send -R -i $snap_yesterday $snap_today | ssh $host $zfs receive \
    -vudF $dst_0 >> $log 2>&1
	 
	echo >> $log
 	echo "Replicacion completada." >> $log
else
	echo "Error: Replicacion no completada. Falta la instantánea de ayer." \
    >> $log
fi
 
echo >> $log
 
# Eliminar instantáneas 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*" | \
    $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 para destruir." >> $log
fi

echo >> $log

# Eliminar instantáneas más antiguas que el valor asignado a retention.
echo "Intentando destruir instantáneas antiguas $dst_0..." >> $log
 
if [ -n "$snap_old_dst_0" ]
then
	snap_remoto="zbackup/solaris/home"
	echo "Destruyendo las siguientes instantáneas antiguas:" >> $log
	echo "$snap_old_dst_0" >> $log
	ssh $host $zfs list -t snapshot -o name | $grep \
    "$snap_remoto@$snap_prefix-*" | $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 para destruir." >> $log
fi

# Marcar el fin del script con un delimitador.
echo "**********" >> $log
 
### FIN DEL SCRIPT

Luego, agregue una tarea a la tabla cron bajo la cuenta del usuario. El script se ejecuta todos los días a las 22:00 (hora local):

# Ejecuta script backup cada día a las 22:00
0 22 * * * /home/carlos/bin/zfsrep.sh

Las entradas del archivo /home/carlos/cronlog se verán así:

**********

zfsrep.sh
Tue Apr 15 09:45:19 CEST 2025

Tomando la instantánea de hoy: zroot/home@snap-20250415

La instantánea de ayer 'zroot/home@snap-20250414' existe. Continuando con la replicacion...
receiving incremental stream of zroot/home@snap-20250415 into zbackup/solaris/home@snap-20250415
received 312B stream in 0.91 seconds (341B/sec)
receiving incremental stream of zroot/home/carlos@snap-20250415 into zbackup/solaris/home/carlos@snap-20250415
received 16.3M stream in 7.07 seconds (2.30M/sec)

Replicacion completada.

Intentando destruir instantáneas antiguas zroot/home...
Destruyendo las siguientes instantáneas antiguas:
zroot/home@snap-20250327

Intentando destruir instantáneas antiguas zbackup/solaris...
No se pudo encontrar ninguna instantánea para destruir.
FreeBSD es genial!.

viernes, 11 de abril de 2025

Configuración de Zerotier Acceso a Servidor LAN vía SSH FreeBSD 14.2

Configuración para conectar clientes a un servidor FreeBSD via Zerotier y SSH

Instalación y configuración de Zerotier en el servidor FreeBSD

Instalación y puesta en marcha de Zerotier

 pkg install net/zerotier
 sysrc zerotier_enable=YES
 service zerotier start

Unirse a la Red Zerotier (192.168.192.0-24):

 zerotier-cli join <Network ID>

Reemplaza <Network ID> con el ID de tu red Zerotier (puedes verlo en Zerotier central).

Autorizar el servidor en Zerotier, aparecerá en la lista de miembros con su ID

Asigna una IP fija al servidor en la red Zerotier (por ej: 192.168.192.133).

Configuración del cortafuegos PF en el servidor FreeBSD

Habilitar IP Forwarding (Reenvío de paquetes):

echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf

Aplicar los cambios:

sysctl net.inet.ip.forwarding=1
net.inet.ip.forwarding: 1

Reglas PF (/etc/pf.conf)

# Macros
wan_if = "re0"               # Interfaz conectada al MikroTik (LAN)
lan_net = "192.168.88.0/24"  # Red local
zt_if = "zt1ocu1pr8e2sac"    # Interfaz ZeroTier
zt_net = "192.168.192.0/24"  # Red ZeroTier

# Opciones generales
set block-policy drop
set skip on { lo0, $zt_if }  # ZeroTier no necesita filtrado estricto
scrub in all fragment reassemble

# Reglas predeterminadas
block all
pass out quick keep state

# Permitir tráfico entre redes LAN y ZeroTier
pass quick from $lan_net to $zt_net
pass quick from $zt_net to $lan_net

# Permitir servicios desde la LAN (Samba, NFSv4, SSH)
pass in on $wan_if proto { tcp, udp } from $lan_net to any port { 139, \
445, 111, 2049, 22 }

# Permitir SSH desde ZeroTier (clientes externos)
pass in on $zt_if proto tcp from $zt_net to ($wan_if) port 22

# Reglas para ZeroTier (puerto UDP 9993 y comunicación entre peers)
pass in on $zt_if proto udp from any to any port 9993

# Permitir ICMP (pings y mensajes de error)
pass in inet proto icmp all icmp-type { echoreq, unreach }

Configuración de clientes Zerotier:

Instalar Zerotier en los dispositivos cliente

Unirlos a la red Zerotier

zerotier-cli join <Network ID> o mediante la app

Autoriza los clientes en Zerotier y asígnales IPs fijas si es necesario

Acceso SSH al servidor

Conectarse desde un cliente usando la IP de Zerotier del servidor

 ssh usuario@192.168.192.133

Ruta estática entre la red local (192.168.88.0/24) y Zerotier (192.168.192.0/24)

¿Por qué es necesaria?

Los clientes en Zerotier (192.168.192.0/24) no saben como llegar a la red local del servidor (192.168.88.0/24) por defecto.

La ruta estática indica a Zerotier que el servidor actúa como puerta de enlace para la red local.

Configuración en Zerotier Central:

Ir a su red en Zerotier
En Advanced > Managed Routes,
añadir:

 - Destination: 192.168.88.0/24
 - Via: 192.168.192.133 (IP Zerotier del servidor)

Explicación Técnica

Zerotier como VPN Layer 2:

Crea una red virtual donde todos los dispositivos aparecen como si estuvieran en la misma LAN, evitando la necesidad de port forwarding

Ruta estática:

Dirige el tráfico desde Zerotier hacia la red local a través del servidor, que actúa como router.

Verificaión:

Desde un cliente Zerotier, por ej: desactivo la conexión wifi de mi teléfono móvil y activo los datos para conectarme desde una red externa:

 ssh usuario@192.168.192.133


En el servidor

 tcpdump -i zt1ocu1pr8e2sac

Optimizar ZeroTier:

- En /usr/local/etc/zerotier-one/zerotier-one.conf, configura allowManaged y allowGlobal para controlar el acceso a rutas:

   {
     "settings": {
       "allowManaged": true,
       "allowGlobal": false
     }
   }

Diagrama de Flujo

Esta configuración garantiza que solo los servicios necesarios estén expuestos, y la comunicación entre redes se realice de manera segura y controlada.

FreeBSD es genial!.