<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Seguridad &#8211; El Cornijal de Linux</title>
	<atom:link href="https://linuxete.duckdns.org/category/seguridad/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxete.duckdns.org</link>
	<description>Un blog sobre Linux</description>
	<lastBuildDate>Sun, 01 Mar 2026 19:09:48 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Tutorial: Failover en Raspberry Pi mediante Llamada Telefónica</title>
		<link>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica</link>
					<comments>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/#comments</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Tue, 13 Jan 2026 18:16:53 +0000</pubDate>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[Sistema]]></category>
		<category><![CDATA[watchdog]]></category>
		<category><![CDATA[A7670E]]></category>
		<category><![CDATA[Failover]]></category>
		<category><![CDATA[HAT 4G]]></category>
		<category><![CDATA[HAT 4G LTE CAT-1]]></category>
		<category><![CDATA[Waveshare]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=3573</guid>

					<description><![CDATA[Nota, no recomiendo usar este hat si estás usando un disco SSD conectado a los puertos usb, si no es a través de un hub, debido a los picos de corriente que genera provocando desconexiones y problemas en los mismos. En este tutorial, aprenderemos a configurar un sistema de alerta crítica. Si tu conexión a [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota, no recomiendo usar este hat si estás usando un disco SSD conectado a los puertos usb, si no es a través de un hub, debido a los picos de corriente que genera provocando desconexiones y problemas en los mismos.</p>
</blockquote>



<p>En este tutorial, aprenderemos a configurar un sistema de alerta crítica. Si tu conexión a internet falla —ya sea por una avería de tu proveedor (ISP) o un fallo en tu propio router—, la Raspberry Pi detectará la caída de inmediato, <strong>te avisará mediante una llamada telefónica</strong> y te reportará via Telegram cuando la red sea restablecida.</p>



<p>Para que este sistema sea infalible, no podemos depender de la propia conexión de fibra que estamos monitorizando. Necesitamos una vía de comunicación externa. En este caso práctico, utilizaremos un módulo HAT 4G LTE CAT-1 (A7670E), junta a una <strong>tarjeta SIM M2M</strong> (machine to machine) como las que emplean Vodafone u Orange para alarmas profesionales, ascensores , etc. Estas tarjetas suelen estar <strong>limitadas</strong> a voz o SMS y <strong>no disponen de datos móviles</strong>. Aprovecharemos la <strong>robusta red 2G</strong> para garantizar que, en caso de caída de la conexión de fibra, la Raspberry Pi ejecute una llamada de voz a nuestro teléfono móvil de forma prioritaria.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="800" height="800" src="https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e.jpg" alt="" class="wp-image-3568" style="width:364px;height:auto" srcset="https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e.jpg 800w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-300x300.jpg 300w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-150x150.jpg 150w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-768x768.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p><strong>¿Por qué es importante este sistema?</strong> Si confías en la domótica para la seguridad de tu hogar (alarmas, detectores de inundación o cámaras), una caída de la red, te deja «a ciegas». Saber que tu red ha caído en tiempo real te permite reaccionar antes de que sea tarde.</p>



<p>¿Cómo funciona el flujo de trabajo?</p>



<ol start="1" class="wp-block-list">
<li><strong>Monitorización:</strong> La Raspberry Pi realiza «pings» constantes a servidores externos (como los DNS de Google o Cloudflare).</li>



<li><strong>Detección:</strong> Si el ping falla de forma consecutiva, el script activa el módulo A7670E.</li>



<li><strong>Alerta:</strong> El HAT ejecuta el comando AT de llamada y marca tu número de teléfono.</li>



<li><strong>Acción:</strong> Recibes la llamada y sabes, al instante, que algo va mal en casa.</li>
</ol>



<h2 class="wp-block-heading">Prepara el software de tu Raspberry.</h2>



<p>Para entrar a las funciones del HAT necesitaremos instalar el programa minicom.</p>



<pre class="wp-block-code"><code>sudo apt-get install minicom</code></pre>



<p>Para que nuestro script funcione, necesitas instalar la librería Python Serial:</p>



<pre class="wp-block-code"><code><code>sudo apt-get install python3-serial -y</code></code></pre>



<p>Por alguna extraña razón, (que solo he podido observar en Raspberry Pi, ModemManager no se lleva bien con este HAT, intenta secuestrarlo constantemente, como si fuese un módem de los antiguos.</p>



<p>Por eso motivo, ya que no será necesario, optaré por desinstalarlo con:</p>



<pre id="block-14c1177c-0d94-499d-9667-d03e8388d140" class="wp-block-preformatted">sudo apt-get purge modemmanager -y</pre>



<h3 class="wp-block-heading">Permisos del usuario.</h3>



<p>Tu usuario debe de tener permiso para usar el puerto serie (el módem) por defecto. Si no es así, el script intentará abrir el puerto y al no conseguirlo, se quedará esperando una respuesta que el sistema le bloqueará y no llegará a marcar.</p>



<p>Teclea el siguiente comando para ver los grupos a los que pertenece tu usuario.</p>



<pre class="wp-block-code"><code>groups</code></pre>



<p>Comprueba que tu usuario pertenece al grupo «dialout», si no es así, deberás agregarlo con este comando:</p>



<pre class="wp-block-code"><code>sudo usermod -a -G dialout <mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark></code></pre>



<p>Tras ejecutar este comando, <strong>reinicia</strong> tu Raspberry</p>



<pre class="wp-block-code"><code>sudo reboot</code></pre>



<h4 class="wp-block-heading">Forzar el modo de alta corriente (Si tu fuente es MUY buena)</h4>



<p>En una Raspberry pi 4 es algo común, que si usas varios dispositivos conectados a los puertos USB, Pines GPIO, etc, sufras de cuelgues del sistema y se te queden tus proyectos mas tiesos que la mojama. </p>



<p>Si tienes la fuente oficial de 3A (o una mejor), puedes intentar decirle a la Pi que desbloquee el límite de los USB, aunque esto es automático hasta cierto punto, a veces ayuda asegurar el voltaje. Sin embargo, hay un detalle técnico importante: en la Raspberry Pi 4, el límite de corriente de los USB está fijado por hardware a <strong>1.2A compartidos</strong>.</p>



<p>Pero, para «darle chicha» y asegurar que el sistema no entre en pánico cuando el SSD y el HAT 4G trabajen juntos, vamos a aplicar dos ajustes de «estabilidad máxima» que debes tener en cuenta.</p>



<h5 class="wp-block-heading">1. Evitar el «ahorro de energía» del USB (El culpable del bloqueo)</h5>



<p>Cuando el SSD y el HAT piden energía a la vez, el kernel de Linux puede intentar suspender el puerto USB para protegerse, y ahí es donde se congela la Pi. Vamos a prohibirle que lo haga.</p>



<p>Ejecuta este comando para editar el archivo de arranque:</p>



<pre class="wp-block-code"><code>sudo nano /boot/firmware/cmdline.txt</code></pre>



<p>Al final de la línea de texto (sin pulsar Enter, todo en la misma línea), añade un espacio y esto:</p>



<pre class="wp-block-code"><code>usbcore.autosuspend=-1</code></pre>



<h5 class="wp-block-heading">2. Estabilidad de Voltaje (Config.txt)</h5>



<p>Vamos a añadir un parámetro para que la CPU no baje su rendimiento bruscamente cuando detecte picos de consumo del USB, lo que evita que se cuelgue el sistema.</p>



<p>Edita el archivo de configuración:</p>



<pre class="wp-block-code"><code>sudo nano /boot/firmware/config.txt</code></pre>



<p>Añade estas líneas al final:</p>



<pre class="wp-block-code"><code># Forzar estabilidad de voltaje en puertos USB
avoid_warnings=1</code></pre>



<h2 class="wp-block-heading">El Hardware: HAT 4G LTE CAT-1 (A7670E)</h2>



<p>El <strong>HAT 4G LTE CAT-1 para Raspberry Pi (Modelo A7670E)</strong>, es un módulo compacto pero extremadamente versátil capaz de:</p>



<ul class="wp-block-list">
<li>Realizar y recibir llamadas de voz.</li>



<li>Enviar y recibir SMS.</li>



<li>Navegar por internet mediante 4G.</li>



<li>Obtener datos de GPS</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota: A partir de este momento, no es necesario tener conectado el cable USB al Módulo 4G, tan solo debe de estar conectado a los pines GPIO</p>
</blockquote>



<h3 class="wp-block-heading">Configurar la Raspberry para usar su puerto serie interno</h3>



<p>Por defecto, la Raspberry usa sus pines de transmisión para la «consola» (donde ves letras al arrancar). Hay que liberarlo:</p>



<ol start="1" class="wp-block-list">
<li>Ejecuta:<br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">sudo raspi-config</mark></code></li>



<li>Ve a <strong>Interface Options</strong> -&gt; <strong>Serial Port</strong>.</li>



<li>¿Deseas que la consola sea accesible por serie? <strong>NO</strong>.</li>



<li>¿Deseas que el hardware del puerto serie esté habilitado? <strong>SÍ</strong>.</li>



<li>Reinicia la Raspberry.</li>
</ol>



<h4 class="wp-block-heading">Localizar el nuevo puerto</h4>



<p>Una vez iniciado el sistema, vuelve a ingresar a la terminal para que podamos entrar por el puerto físico de los pines de la Raspberry, que suele ser <code>/dev/ttyS0</code></p>



<pre class="wp-block-code"><code>sudo minicom -D /dev/ttyS0 -b 115200</code></pre>



<p>Si todo va bien, entrarás a la terminal de configuración del módulo. Ahora, debemos comprobar el modo de funcionamiento en el que se encuentra el HAT 4G.</p>



<h4 class="wp-block-heading">La terminal del módulo 4G</h4>



<p>Ahora que estás en la terminal de programación del módulo, escribe el siguiente comando.</p>



<pre class="wp-block-code"><code>AT$MYCONFIG?</code></pre>



<p>Si nos devuelve <strong><code>"usbnetmode"2</code></strong>, es porque el módulo está en modo <strong>Serial(modén)</strong> que es justo lo que necesitamos.</p>



<p>Pero, si nos devuelve <strong><code>"usbnetmode",0</code></strong>, es porque el módulo está en modo <strong>RNDIS (Red)</strong> y deberemos desactivarlo.</p>



<h3 class="wp-block-heading">Cómo desactivar RNDIS</h3>



<p><em>«Muchos tutoriales te obligan a usar el modo RNDIS, pero si tu objetivo es enviar alertas mediante llamadas, el modo <strong>Serie (usbnetmode,2)</strong> es el secreto para una estabilidad del 100% en placas Raspberry Pi, evitando conflictos de red innecesarios.»</em></p>



<p>Para dejarlo en modo <strong>«serie»</strong>, que es el la opción indicada para hacer solo llamadas perdidas desde la Raspberry Pi 4, ejecuta esta secuencia exacta en tu terminal:</p>



<ol start="1" class="wp-block-list">
<li><strong>Cambia al modo 2 (Modem/Serie):</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT$MYCONFIG="usbnetmode",2</mark></code></li>



<li><strong>Desactiva el intento de marcación automática:</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT+DIALMODE=1</mark></code></li>



<li><strong>Guarda los cambios en la memoria interna (Flash):</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT&amp;W</mark></code></li>



<li><strong>Reinicia el módulo para que aplique los cambios:</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT+CRESET</mark></code></li>
</ol>



<p>Para salir del terminal del HAT 4G pulsa Ctrl + A y luego Q y volverás a la terminal de Linux.</p>



<h2 class="wp-block-heading">EL Script</h2>



<p>Tras varias pruebas, este script en su versión 4.7, es una solución de monitorización en lenguaje Python, diseñada para informar cuando tu conexión de internet principal falla.</p>



<p>Crea un archivo llamado <code>netguard.py</code></p>



<pre class="wp-block-code"><code>nano netguard.py</code></pre>



<p>Pega el siguiente código.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>No olvides sustituir tu número de <strong>teléfono, </strong>tu<strong> Token </strong>de<strong> Telegram </strong>y tu<strong> ID </strong>de<strong> Telegram.</strong></p>
</blockquote>



<pre class="wp-block-code"><code>import os
import time
import serial
import subprocess
import requests
import sys

# --- CONFIGURACIÓN ---
TELEFONO = "<mark style="background-color:#7bdcb5" class="has-inline-color">600000000</mark>"
PUERTO_MODEM = "/dev/serial0"
INTERFAZ_FIBRA = "eth0"
TOKEN_TELEGRAM = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_Token</mark>"
ID_CHAT = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_ID</mark>"

fibra_estaba_caida = False
llamada_realizada_con_exito = False

def comprobar_fibra():
    try:
        resultado = subprocess.run(
            &#91;"ping", "-I", INTERFAZ_FIBRA, "-c", "2", "-W", "3", "1.1.1.1"],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
        )
        return resultado.returncode == 0
    except:
        return False

def inicializar_modem(ser):
    """Configuración inicial recomendada para A7670E"""
    comandos = &#91;
        b"AT+CMEE=2\r\n",      # Errores verbosos
        b"AT+CRC=1\r\n",       # Resultados extendidos (útil)
        b"AT+COLP=1\r\n",      # Muestra número cuando contestan (opcional)
        b"AT+CVHU=0\r\n",      # Modo hangup correcto
        b"AT+CLCC=1\r\n",      # (no siempre necesario pero no hace daño)
    ]
    for cmd in comandos:
        ser.write(cmd)
        time.sleep(0.4)
        ser.read_all()  # descartar respuesta

def realizar_llamada_perdida():
    ser = None
    try:
        print(f"\n&#91;{time.strftime('%H:%M:%S')}] ALERTA: Sin internet → Iniciando llamada perdida...", flush=True)
        
        ser = serial.Serial(PUERTO_MODEM, 115200, timeout=1)
        inicializar_modem(ser)

        # Limpieza completa
        ser.reset_input_buffer()
        ser.reset_output_buffer()

        # Registro en red (mejor usar CEREG para LTE, pero CREG también funciona)
        print(" &#91;+] Esperando cobertura...", flush=True)
        for i in range(30):
            ser.write(b"AT+CREG?\r\n")
            time.sleep(1)
            resp = ser.read_all().decode(errors='ignore')
            if ",1" in resp or ",5" in resp:
                print(f" &#91;+] Registrado en red (intento {i+1})", flush=True)
                break
            print(f" &#91;...] Buscando torre... ({i+1}/30)", flush=True)
        else:
            print(" &#91;!] Sin cobertura. Reiniciando módulo...", flush=True)
            ser.write(b"AT+CFUN=1,1\r\n")
            return False

        # Colgar cualquier llamada residual
        ser.write(b"AT+CHUP\r\n")
        time.sleep(0.8)
        ser.read_all()

        # MARCAR
        print(f" &#x1f4de; Marcando a {TELEFONO}...", flush=True)
        ser.write(f"ATD{TELEFONO};\r\n".encode())
        time.sleep(1.5)  # esperar OK + VOICE CALL: BEGIN

        print(" &#91;?] Llamada en curso. Esperando que cuelgues (máx 45s)...", flush=True)

        timeout = time.time() + 45
        llamada_activa = False

        while time.time() &lt; timeout:
            # Polling CLCC + lectura de URCs
            ser.write(b"AT+CLCC\r\n")
            time.sleep(0.7)
            resp = ser.read_all().decode(errors='ignore').strip()

            # URC directo del módulo (lo más fiable)
            if "VOICE CALL: END" in resp:
                print(" &#x2705; Colgado detectado por URC 'VOICE CALL: END'", flush=True)
                return True

            # CLCC desapareció → colgado por receptor
            if "+CLCC:" in resp:
                llamada_activa = True
                print(" → Sonando / activa", flush=True)
            elif llamada_activa and "+CLCC:" not in resp and "OK" in resp:
                print(" &#x2705; Colgado detectado: CLCC desapareció", flush=True)
                return True

            # Backup: NO CARRIER
            if "NO CARRIER" in resp:
                print(" &#x2705; Colgado por NO CARRIER", flush=True)
                return True

        # Timeout → colgamos nosotros
        print(" &#x23f0; Timeout → colgando forzosamente", flush=True)
        ser.write(b"AT+CHUP\r\n")
        return False

    except Exception as e:
        print(f" &#91;!] Error serie: {e}", flush=True)
        return False
    finally:
        if ser and ser.is_open:
            ser.close()

# --- BUCLE PRINCIPAL ---
print("--- Vigilante M2M v5.7 (A7670E optimizado) ---", flush=True)

while True:
    hay_internet = comprobar_fibra()

    if not hay_internet:
        if not fibra_estaba_caida:
            print(f"&#91;{time.strftime('%H:%M:%S')}] Caída de fibra detectada.", flush=True)
            time.sleep(5)
            if not comprobar_fibra():  # doble chequeo
                fibra_estaba_caida = True
                if realizar_llamada_perdida():
                    llamada_realizada_con_exito = True
                else:
                    time.sleep(30)  # reintentar más lento si falló

        elif not llamada_realizada_con_exito:
            if realizar_llamada_perdida():
                llamada_realizada_con_exito = True
            else:
                time.sleep(60)

    elif hay_internet and fibra_estaba_caida:
        print(f"&#91;{time.strftime('%H:%M:%S')}] &#x2705; Fibra recuperada. Avisando por Telegram...", flush=True)
        try:
            requests.post(
                f"https://api.telegram.org/bot{TOKEN_TELEGRAM}/sendMessage",
                data={"chat_id": ID_CHAT, "text": "&#x2705; Fibra recuperada"},
                timeout=10
            )
        except:
            pass
        fibra_estaba_caida = False
        llamada_realizada_con_exito = False

    time.sleep(20)
</code></pre>



<p>Para guardar pulsa Ctrl + o y  Ctrl + x para salir</p>



<p>No olvides hacerlo ejecutable con:</p>



<pre class="wp-block-code"><code>chmod +x netguard.py</code></pre>



<h4 class="wp-block-heading">¿Cómo funciona el script?</h4>



<p>El programa actúa como un centinela que vigila la interfaz de fibra (<code>eth0</code>) cada 20 segundos mediante pings ligeros. Su inteligencia reside en cómo gestiona las alertas:</p>



<ol start="1" class="wp-block-list">
<li>El script actúa como un centinela incansable que vigila la interfaz de fibra (eth0) cada 20 segundos mediante pings ligeros. Su inteligencia reside en cómo gestiona las alertas de forma robusta y eficiente, aprovechando al máximo las capacidades del módulo A7670E (según el manual oficial SIMCom A76XX v1.09):</li>



<li><strong>Paciencia de Registro (mejorada):</strong> No marca a ciegas. Primero interroga al módem con AT+CREG? para confirmar cobertura real (registrado en red roaming o home). Realiza hasta <strong>30 intentos</strong> (más margen que antes), con pausas de 1 segundo, dando tiempo al hardware para sincronizarse con la torre más cercana. Si falla tras los intentos, fuerza un reinicio profundo del módulo (AT+CFUN=1,1) para «despertarlo» y buscar señal de nuevo.</li>



<li><strong>Inicialización Proactiva del Módem:</strong> Antes de cualquier operación crítica, envía comandos de configuración recomendados por SIMCom: AT+CMEE=2 (errores verbosos), AT+CRC=1 (resultados extendidos), AT+COLP=1 (muestra número al contestar, opcional), AT+CVHU=0 (modo colgado correcto). Esto evita errores comunes y mejora la fiabilidad.</li>



<li><strong>Detección Inteligente de Colgado (el gran salto):</strong> La clave de v5.7 es la detección <strong>proactiva y prioritaria</strong> usando URCs nativos del módulo:
<ul class="wp-block-list">
<li>Tras ATD&lt;numero>;, el módem envía automáticamente VOICE CALL: BEGIN cuando empieza a sonar.</li>



<li>Mientras la llamada está activa, polling frecuente con AT+CLCC para ver si sigue en lista (+CLCC: presente).</li>



<li><strong>Cuando cuelgas desde tu móvil</strong>, llega el URC VOICE CALL: END → detección inmediata y casi infalible.</li>



<li>Fallbacks: si CLCC desaparece tras haber estado activo, o aparece NO CARRIER.</li>



<li>Timeout máximo de <strong>45 segundos</strong> (más que suficiente para llamada perdida) → fuerza AT+CHUP si no cuelgas, evitando bloqueos eternos.</li>
</ul>
</li>



<li><strong>Flush=True, Timeouts y Limpieza de Buffers:</strong> Todas las impresiones usan flush=True para logs inmediatos en journalctl. Las lecturas/escrituras serie tienen timeout=1 y se limpian buffers (reset_input_buffer()) antes y después de comandos clave. Nada se queda «colgado».</li>



<li><strong>Reintento Inteligente y Persistencia Educada:</strong> Si la llamada falla (sin cobertura, timeout, etc.), el script reintenta en el siguiente ciclo de vigilancia (cada ~20-60 s según estado). Pero una vez que logra que tu móvil suene con éxito (colgado detectado), marca llamada_realizada_con_exito = True y <strong>deja de llamar</strong> hasta que la fibra se recupere. Así evita saturar tu línea o gastar saldo innecesario.</li>



<li><strong>Informe de Retorno por Telegram:</strong> Tras la alerta por voz, el script entra en modo «escucha». En cuanto detecta que la fibra ha vuelto (doble chequeo ping para evitar falsos positivos), envía mensaje por Telegram: «<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fibra recuperada». Así sabes no solo la caída, sino también el momento exacto de recuperación.</li>
</ol>



<p>Ademas:</p>



<ol start="1" class="wp-block-list">
<li>Doble verificación de caída (ping + 5 s espera + segundo ping) antes de alertar.</li>



<li>Logs limpios: imprime solo lo esencial (puedes reducir aún más los «→ Sonando / activa» editando el contador).</li>



<li>Manejo de excepciones y cierre seguro del puerto serie (finally con ser.close()).</li>
</ol>



<p>En resumen: v5.7 es más fiable, rápida en detección y respetuosa con tu móvil y saldo, gracias a los URC nativos y la configuración proactiva del módulo.</p>



<h4 class="wp-block-heading">Lanza tu script a ver que ocurre.</h4>



<pre class="wp-block-code"><code>python3 netguard.py</code></pre>



<h2 class="wp-block-heading">Crea el archivo del servicio.</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>«Haciéndolo Robusto: Creando un Servicio en Systemd»</strong> <em>«Un vigilante no sirve de nada si tienes que arrancarlo a mano. Al convertir nuestro script en un servicio de Linux, garantizamos que la vigilancia sea 24/7, incluso si hay un apagón y la Raspberry se reinicia sola. El sistema se encarga de que el script esté siempre vivo.»</em></p>
</blockquote>



<p>Para que este script sea realmente autónomo, debería arrancar al inicio del sistema y si falla o se cierra por un error inesperado, Linux lo reinicia automáticamente en pocos segundos.</p>



<p>Lo ideal es crear un <strong>servicio en el sistema (Systemd)</strong>.</p>



<p>Ejecuta este comando para crear el archivo de configuración:</p>



<pre class="wp-block-code"><code>sudo nano /etc/systemd/system/netguard.service</code></pre>



<p>Copia y pega este contenido (asegúrate de que la ruta <code>/home/tu_usuario/netguard.py</code> sea la correcta donde guardaste el script):</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Servicio Vigilante de Fibra por GSM
After=network.target

&#91;Service]
# Fuerza a Python a no guardar nada en memoria intermedia
Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/python3 -u /home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>/netguard.py
WorkingDirectory=/home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>
User=<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>
# El grupo dialout es clave para que el usuario tenga permiso al módem
Group=dialout
Restart=always
RestartSec=10

# Estas líneas aseguran que Systemd vuelque todo al journal al instante
StandardOutput=journal
StandardError=journal
TTYPath=/dev/ttyS0

&#91;Install]
WantedBy=multi-user.target
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>Nota: Cambia <mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark></em> por el tuyo propio.</p>
</blockquote>



<h4 class="wp-block-heading">Activar y arrancar el servicio</h4>



<p>Ahora dale las órdenes a la Raspberry para que lo ponga en marcha:</p>



<pre class="wp-block-code"><code># Recargar el sistema para que vea el nuevo servicio
sudo systemctl daemon-reload

# Activar para que arranque siempre al encender la Pi
sudo systemctl enable netguard.service

# Arrancar el servicio ahora mismo
sudo systemctl start netguard.service</code></pre>



<h4 class="wp-block-heading">¿Cómo saber si está funcionando?</h4>



<p>Puedes ver el estado del vigilante en tiempo real con este comando:</p>



<pre class="wp-block-code"><code>sudo systemctl status netguard.service</code></pre>



<p>Y si quieres ver los «logs» (lo que el script va imprimiendo):</p>



<pre class="wp-block-code"><code>journalctl -u netguard.service -f</code></pre>



<p>Un ejemplo tras varios dias de funcionamiento del script.</p>



<pre class="wp-block-code"><code>tu_usurio@raspberrypi:~ $ <strong>journalctl -u netguard.service -f</strong>
mar 01 15:53:48 tu_host python3&#91;3651558]: --- Vigilante M2M v5.7 (A7670E optimizado) ---
mar 01 15:54:13 tu_host python3&#91;3651558]: &#91;15:54:13] Caída de fibra detectada.
mar 01 15:54:22 tu_host python3&#91;3651558]: &#91;15:54:22] ALERTA: Sin internet → Iniciando llamada perdida...
mar 01 15:54:24 tu_host python3&#91;3651558]:  &#91;+] Esperando cobertura...
mar 01 15:54:25 tu_host python3&#91;3651558]:  &#91;+] Registrado en red (intento 1)
mar 01 15:54:25 tu_host python3&#91;3651558]:  &#x1f4de; Marcando a 600000000...
mar 01 15:54:27 tu_host python3&#91;3651558]:  &#91;?] Llamada en curso. Esperando que cuelgues (máx 45s)...
mar 01 15:54:28 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:28 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:29 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:30 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:30 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:31 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:55:00 tu_host python3&#91;3651558]:  &#x2705; Colgado detectado por URC 'VOICE CALL: END'
mar 01 15:55:21 tu_host python3&#91;3651558]: &#91;15:55:21] &#x2705; Fibra recuperada. Avisando por Telegram...

</code></pre>



<h2 class="wp-block-heading">Troubleshooting (solución de problemas)</h2>



<p>Si tu sistema sigue experimentando cuelgues o hace cosas extrañas cuando intenta hacer una llamada, prueba a usar un Hub USB con alimentación propia (La más segura). Conecta el SSD a un Hub USB que tenga su propia fuente de alimentación. Así, la energía para mover el módulo la da el Hub y no la Raspberry. La Pi solo se encarga de los datos. Por lo que, lo más efectivo es <strong>separar el consumo</strong>.</p>



<h2 class="wp-block-heading">Prueba final:</h2>



<p>Una vez que esté todo funcionando.</p>



<ol start="1" class="wp-block-list">
<li>Desconecta el cable <em>Ethernet</em> para provocar una llamada.</li>



<li>Abre abre una terminal y escribe <br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">ls -R /</mark></code></li>



<li>Si ya no se bloquea, es que la fuente de la Pi 5 y el comando <code>autosuspend=-1</code> han solucionado el conflicto de energía.</li>
</ol>



<p></p>



<h2 class="wp-block-heading">Miscelánea</h2>



<p>Estos son los comandos clave para extraer estadísticas y gestionar tu Vigilante como un auténtico administrador de sistemas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">1. El «Resumen de Batalla» (Estadísticas rápidas)</h3>



<p>Si quieres saber cuántas veces se ha caído la fibra o cuántas llamadas ha hecho el script sin leer miles de líneas, usa este comando. Filtrará el log y te dará solo los hitos importantes:</p>



<pre class="wp-block-code"><code>journalctl -u netguard.service | grep -E "Caída detectada|Llamada finalizada|Red recuperada"</code></pre>



<p><em>Esto te mostrará una lista limpia con los días y horas exactas de cada incidente.</em></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">2. Comprobar el estado del «Motor»</h3>



<p>Si alguna vez dudas de si el script sigue vivo (aunque ya hemos visto que es eterno), este comando te da el informe de salud de Systemd:</p>



<pre class="wp-block-code"><code>systemctl status netguard.service</code></pre>



<p><em>Fíjate en la línea que dice <code>Active: active (running) since...</code>. Te dirá cuántos días lleva encendido sin interrupciones.</em></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">3. Reiniciar tras cambios (SIM, teléfono, etc.)</h3>



<p>Si decides cambiar el número de teléfono o el token de Telegram en el archivo <code>.py</code>, no basta con guardar el archivo. Tienes que decirle a la Raspberry que cargue la nueva versión:</p>



<pre class="wp-block-code"><code>sudo systemctl restart netguard.service</code></pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Cómo crear un Watchdog para dispositivos en red.</title>
		<link>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi</link>
					<comments>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/#respond</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 09:57:17 +0000</pubDate>
				<category><![CDATA[Red]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[watchdog]]></category>
		<category><![CDATA[sensor fugas]]></category>
		<category><![CDATA[sensor inteligente]]></category>
		<category><![CDATA[tapo H100]]></category>
		<category><![CDATA[tapo P100]]></category>
		<category><![CDATA[tapo p110]]></category>
		<category><![CDATA[tapo T300]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=3554</guid>

					<description><![CDATA[Después de haber sufrido una pequeña inundación en el sótano de casa, decidí crear un sistema de alerta y corte de suministro de agua. Para que mi instalación pueda ponerse en contacto conmigo, necesito la ayuda de sensores online que vigilen constantemente si se produce alguna avería. El ecosistema Tapo de TP-Link es excelente por [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Después de haber sufrido una pequeña inundación en el sótano de casa, decidí crear un sistema de alerta y corte de suministro de agua. </p>



<p>Para que mi instalación pueda ponerse en contacto conmigo, necesito la ayuda de sensores online que vigilen constantemente si se produce alguna avería.</p>



<p>El ecosistema Tapo de TP-Link es excelente por su relación calidad-precio, especialmente sus sensores de inundación T300. Sin embargo, tiene un «talón de Aquiles» crítico: <strong>la falta de notificaciones por desconexión</strong>. Si el Hub H100 o el enchufe P100 se apagan, tu sistema de seguridad muere en silencio.</p>



<p>Aquí te explico cómo convertir tu Raspberry Pi en un vigilante activo que te avisará en segundos si algo falla.</p>



<p><strong>El problema: El silencio de los dispositivos offline</strong></p>



<p id="block-dbcce1e7-b3fc-4fff-ad55-facaf6e3522c">Tanto si la centralita H100 (Hub) como el enchufe P100 que controla el cierre de agua, se avería, sufre un pico de tensión o alguien los desenchufa accidentalmente, el sistema se queda «ciego». El sensor de agua T300 no tiene a quién avisar y la orden de corte nunca se ejecuta.</p>



<p id="block-e2c406d9-9459-4324-b879-653848742da5">Lo más preocupante es que <strong>la App de Tapo no envía notificaciones si un dispositivo se queda fuera de línea</strong>. Para darte cuenta del fallo, tendrías que entrar manualmente en la aplicación y revisar el estado de los iconos uno por uno. En una emergencia o durante unas vacaciones, esta falta de aviso proactivo es un fallo de seguridad inaceptable.</p>



<p><strong>La solución: Un «Watchdog» con Raspberry Pi</strong></p>



<p>Para eliminar este punto ciego, utilizaremos una Raspberry Pi como <strong>Watchdog (Perro Guardián)</strong>. En lugar de esperar a que la App nos avise, la Pi interrogará constantemente a los dispositivos en la red local, si estos no responden, la Pi asume que el sistema está comprometido y dispara una alerta externa.</p>



<h2 class="wp-block-heading">1. Prepara tu Telegram.</h2>



<p>Aprovechando que tenemos telegram (si no lo tienes, ya estás tardando en instalarlo) vamos a utilizarlo para que nos lleguen los avisos de alerta de nuestro script. Para ello crearemos un bot, que será el encargado de gestionar los avisos provenientes de nuestra raspberry.</p>



<h3 class="wp-block-heading">Crear tu Bot en Telegram (El Emisor)</h3>



<p>Primero necesitamos crear la «entidad» que enviará los mensajes desde tu Raspberry Pi.</p>



<ol start="1" class="wp-block-list">
<li>Abre <strong>Telegram</strong> y busca al usuario <strong>@BotFather</strong>.</li>



<li>Escribe <code>/newbot</code> y dale a enviar.</li>



<li>Te pedirá un <strong>Nombre</strong> para el bot (ejemplo: <code>Vigilante Sótano</code>).</li>



<li>Te pedirá un <strong>Username</strong> (debe terminar en <code>_bot</code>, ejemplo: <code>mi_sotano_seguro_bot</code>).</li>



<li><strong>BotFather</strong> te responderá con un mensaje largo que contiene el <strong>API Token</strong> (algo parecido a <code>74839201:AAH-u7...</code>). <strong>Copia y guarda este código</strong>, es la clave de acceso.</li>
</ol>



<h3 class="wp-block-heading">Obtener tu Chat ID (El Receptor)</h3>



<p>Ahora necesitamos saber a qué cuenta de Telegram (la tuya) debe escribirle el bot.</p>



<ol start="1" class="wp-block-list">
<li>Busca en Telegram el bot <strong>@userinfobot</strong>.</li>



<li>Escríbele un mensaje cualquiera (ej. «Hola»).</li>



<li>Te responderá con tu <strong>ID</strong> (un número de 9 o 10 dígitos). Guárdalo también.</li>
</ol>



<h2 class="wp-block-heading">2. Crea tu script</h2>



<p>Abre tu terminal para crear el archivo con:</p>



<pre class="wp-block-code"><code><code>nano TapoGuard.py</code></code></pre>



<p>Pega este código (asegúrate de poner <strong>tu Token</strong>, <strong>tu ID</strong>, la <strong>IP del H100</strong> y la <strong>IP del P100</strong>):</p>



<pre class="wp-block-code"><code>import os
import time
import requests

# --- CONFIGURACIÓN ---
TOKEN = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_TOKEN</mark>"
CHAT_ID = "<mark style="background-color:#7bdcb5" class="has-inline-color">TU_ID</mark>"

# Diccionario de dispositivos: "Nombre": "IP"
DISPOSITIVOS = {
    "Hub H100": "<mark style="background-color:#7bdcb5" class="has-inline-color">192.168.1.16</mark>",
    "Enchufe Válvula P110": "<mark style="background-color:#7bdcb5" class="has-inline-color">192.168.1.15</mark>"
}

REINTENTOS = 3
SEGUNDOS_ENTRE_CHEQUEOS = 60

# Diccionario para recordar el estado de cada uno (Todos empiezan como Online)
estados_caidos = {nombre: False for nombre in DISPOSITIVOS}

def enviar_telegram(mensaje):
    url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
    params = {"chat_id": CHAT_ID, "text": mensaje}
    try:
        requests.post(url, params=params, timeout=10)
    except Exception as e:
        print(f"Error de red: {e}")

def chequeo_ip(ip):
    # Lanza un ping. Devuelve True si responde.
    salida = os.system(f"ping -c 1 -W 1 {ip} &gt; /dev/null 2&gt;&amp;1")
    return salida == 0

print("--- Vigilante Tapo Iniciado ---")

while True:
    for nombre, ip in DISPOSITIVOS.items():
        exito = False

        # Intentos de ping para evitar falsas alarmas
        for i in range(REINTENTOS):
            if chequeo_ip(ip):
                exito = True
                break
            time.sleep(1)

        # Lógica de notificaciones individualizada
        if not exito and not estados_caidos&#91;nombre]:
            print(f"&#91;{time.strftime('%H:%M:%S')}] &#x274c; {nombre} CAÍDO")
            enviar_telegram(f"&#x26a0; ALERTA: El dispositivo '{nombre}' ({ip}) se ha caído de la red.")
            estados_caidos&#91;nombre] = True

        elif exito and estados_caidos&#91;nombre]:
            print(f"&#91;{time.strftime('%H:%M:%S')}] &#x2705; {nombre} RECUPERADO")
            enviar_telegram(f"&#x2705; OK: El dispositivo '{nombre}' ha vuelto a conectar.")
            estados_caidos&#91;nombre] = False

    time.sleep(SEGUNDOS_ENTRE_CHEQUEOS)</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Te aconsejo que pongas una IP fija a tus dispositivos, ya que si esta cambia, el script no funcionará.</p>
</blockquote>



<p>Guarda los cambios con <code>Ctrl + o</code> y sal con <code>Ctrl + x</code></p>



<p>Haz que tu archivo tenga permisos de ejecución.</p>



<pre class="wp-block-code"><code>chmod +x TapoGuard.py</code></pre>



<p>Y pruébalo con:</p>



<pre class="wp-block-code"><code>python3 TapoGuard.py</code></pre>



<p>Desconecta tu Hub del enchufe y observa que ocurre. ¿Te llegaron los mensajes? Ahora conéctalo y vuelve a mirar.</p>



<p>Si todo ha salido bien, tenemos al «cerebro» de la supervisión funcionando.</p>



<h2 class="wp-block-heading">3. Crea un servicio del sistema (systemd)</h2>



<p>Ahora, para que sea un sistema de seguridad permanente, necesitamos que se convierta en un <strong>servicio del sistema</strong> (un <em>daemon</em>).</p>



<p>De esta forma, si hay un apagón y la Pi se reinicia, el script se levantará solo sin que tengas que teclear nada.</p>



<p>Usa el editor de texto para crear un archivo de configuración en la carpeta del sistema: </p>



<pre class="wp-block-code"><code><code>sudo nano /etc/systemd/system/TapoGuard.service</code></code></pre>



<p>Copia y pega este contenido dentro del archivo (ajustando la ruta a tu usuario):</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Vigilante del Hub Tapo H100
After=network.target

&#91;Service]
# Asegúrate de que la ruta /home/tu_usuario/TapoGuard.py es la correcta
ExecStart=/usr/bin/python3 /home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>/TapoGuard.py
Restart=always
RestartSec=10
User=raspberry

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p>No olvides cambiar tu_usuario por el tuyo propio.</p>



<p>Para guardar Ctrl + o y salir con Ctrl + x</p>



<h3 class="wp-block-heading">Activa el Servicio</h3>



<p>Ahora dale las órdenes a la Raspberry Pi para que lo ponga en marcha:</p>



<ol start="1" class="wp-block-list">
<li><strong>Recarga el sistema</strong> para que reconozca el nuevo archivo: <code>sudo systemctl daemon-reload</code></li>



<li><strong>Activa el inicio automático</strong> al arrancar: <code>sudo systemctl enable TapoGuard.service</code></li>



<li><strong>Inicia el servicio</strong> ahora mismo: <code>sudo systemctl start TapoGuard.service</code></li>
</ol>



<h3 class="wp-block-heading">¿Cómo compruebo que está «vivo»?</h3>



<p>Puedes ver el estado de tu vigilante con este comando: <code>sudo systemctl status TapoGuard.service</code></p>



<ul class="wp-block-list">
<li>Si sale en verde <strong>«active (running)»</strong>, es que está patrullando la IP de tu Hub.</li>



<li>Ya puedes cerrar la terminal, apagar tu ordenador e irte tranquilo: la Pi se encargará de avisar a tu Telegram si el <strong>Tapo H100</strong> deja de responder.</li>
</ul>



<p>Y si quieres ver los «logs» (lo que el script va imprimiendo):</p>



<pre class="wp-block-code"><code>journalctl -u TapoGuard.service -f</code></pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Añade los certificados Let&#8217;s Encrypt a Pi-hole 6</title>
		<link>https://linuxete.duckdns.org/anade-los-certificados-lets-encrypt-a-pi-hole-6/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=anade-los-certificados-lets-encrypt-a-pi-hole-6</link>
					<comments>https://linuxete.duckdns.org/anade-los-certificados-lets-encrypt-a-pi-hole-6/#respond</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Tue, 09 Sep 2025 21:27:26 +0000</pubDate>
				<category><![CDATA[Pi-hole]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[pihole certificados]]></category>
		<category><![CDATA[pihole https]]></category>
		<category><![CDATA[pihole let`s encrypt]]></category>
		<category><![CDATA[pihole seguro]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=3420</guid>

					<description><![CDATA[Let&#8217;s Encrypt es una autoridad de certificación que proporciona certificados TLS gratuitos, lo que facilita que los sitios web habiliten el cifrado HTTPS y crea una internet más segura para todos. No explicaré aquí como instalar los certificados, ya que lo hice en el primer artículo de este blog Instala WordPress en tu raspberry Pi [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Let&#8217;s Encrypt es una autoridad de certificación que proporciona certificados TLS gratuitos, lo que facilita que los sitios web habiliten el cifrado HTTPS y crea una internet más segura para todos.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="477" height="600" src="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_010.png" alt="" class="wp-image-3466" style="width:294px;height:auto" srcset="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_010.png 477w, https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_010-239x300.png 239w" sizes="(max-width: 477px) 100vw, 477px" /><figcaption class="wp-element-caption">Acceso via HTTP a Pi-hole</figcaption></figure>



<p>No explicaré aquí como instalar los certificados, ya que lo hice en el primer artículo de este blog <a href="https://linuxete.duckdns.org/instala-wordpress-en-tu-raspberry-pi-4/">Instala WordPress en tu raspberry Pi 4</a> .</p>



<p>Así, que dando por puesto que ya están instalados en nuestro sistema, ya sea a través de WordPress u otro medio, los reutilizaremos para usarlos con Pi-hole</p>



<h3 class="wp-block-heading">1. Configuración de puertos.</h3>



<p>Entra en Pi-hole desde su interfaz gráfica, ve a <code>Settings</code>, <code>All Settings</code> y <code>Webserver and API</code> y busca el apartado <code>webserver.port</code> y cambia al puerto que necesites configurar.</p>



<p>Originalmente los puertos vienen así:</p>



<pre class="wp-block-code"><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-ast-global-color-0-color">80o,443os,</mark>&#91;::]:80o,&#91;::]:443os</code></pre>



<p>El primer bloque (en azul) corresponde a las direcciones IPV4 y el segundo a IPV6. </p>



<p>A continuación te dejo un ejemplo de puerto HTTP y HTTPS tanto para IPV4 como para IPV6.</p>



<pre class="wp-block-code"><code>7070o,7443os,&#91;::]:7070o,&#91;::]:7443os</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota: no olvides abrir esos mismos puertos en tu router.</p>
</blockquote>



<h3 class="wp-block-heading">2. Localiza tus certificados.</h3>



<p>Lo primero sera buscar la ruta al directorio de tu certificado.</p>



<pre class="wp-block-code"><code>sudo ls -l /etc/letsencrypt/live/</code></pre>



<p>La salida nos mostrará la ruta y con ella el directorio que tendrá el mismo nombre que nuestro dominio.</p>



<pre class="wp-block-code"><code>drwxr-xr-x 2 root root 4096 ago  8 19:00 <mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">mi.dominio.org</mark>
-rw-r--r-- 1 root root  740 feb 24  2024 README
</code></pre>



<p>Por lo que, la ruta completa para tus archivos de certificado será:</p>



<pre class="wp-block-code"><code>sudo ls /etc/letsencrypt/live/mi.dominio.org/</code></pre>



<p>Y el resultado de este último comando, listará los siguientes archivos de certificado.</p>



<pre class="wp-block-code"><code>cert.pem  chain.pem  fullchain.pem  privkey.pem  README</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">3. Copia tus certificados</h3>



<p>Como ya sabemos, los certificados de Let&#8217;s Encrypt se guardan en el directorio <code>/etc/letsencrypt/live/mi.dominio.org/</code>.</p>



<p>Tan solo necesitaremos dos archivos del directorio, que son:</p>



<ul class="wp-block-list">
<li><code>fullchain.pem</code>,  que combina los archivos <code>cert.pem</code> seguido de <code>chain.pem</code>, justo en ese orden.</li>



<li><code>privkey.pem</code>, que es la clave privada del certificado (nunca la compartas)</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Asegúrate de sustituir <code>mi.dominio.org</code> por el nombre de dominio real.</p>
</blockquote>



<p>a. &#8211; Copia el certificado fullchain.pem a /tmp/</p>



<pre class="wp-block-code"><code>sudo cp /etc/letsencrypt/live/mi.dominio.org/fullchain.pem /tmp/</code></pre>



<p>b. &#8211; Copia la clave privada a /tmp/</p>



<pre class="wp-block-code"><code>sudo cp /etc/letsencrypt/live/mi.dominio.org/privkey.pem /tmp/</code></pre>



<h3 class="wp-block-heading">4. Combina los certificados.</h3>



<p>El servidor web interno de Pi-hole v6 requiere que el certificado y la clave privada estén combinados en un solo archivo PEM llamado <code>tls.pem</code> dentro de la carpeta <code>/etc/pihole/</code>.</p>



<p>Situémonos en el directorio /tmp</p>



<pre class="wp-block-code"><code>cd /tmp/</code></pre>



<p>Si listamos el contenido de /tmp, veremos los 2 certificados copiados anteriormente.</p>



<pre class="wp-block-code"><code>me@linuxete:/tmp
$ <strong>ls -l</strong>
total 32
-rw-r--r-- 1 root root 2872 sep  8 19:57 <mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">fullchain.pem</mark>
-rw------- 1 root root  241 sep  8 19:58 <mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">privkey.pem</mark>
</code></pre>



<p>Ahora combinaremos los dos archivos que acabamos de copiar, a un único archivo <code>tls.pem</code>:</p>



<pre class="wp-block-code"><code>sudo bash -c "cat fullchain.pem privkey.pem &gt; /tmp/tls.pem"</code></pre>



<p>Verifica que el archivo <code>tls.pem</code> se ha creado correctamente.</p>



<pre class="wp-block-code"><code>me@linuxete:/tmp
$ <strong>ls -l</strong>
total 16
-rw-r--r-- 1 root root 2872 sep  8 19:57 fullchain.pem
-rw------- 1 root root  241 sep  8 19:58 privkey.pem
-rw-r--r-- 1 root root 3113 sep  8 20:01 <mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">tls.pem</mark>
</code></pre>



<h3 class="wp-block-heading">5. Permisos de usuario y grupo.</h3>



<p>Echa un vistazo al usuario y grupo tiene archivo tls.pem de Pi-hole</p>



<pre class="wp-block-code"><code>me@linuxete:~
$ <strong>ls -l /etc/pihole/tls.pem</strong>
-rw------- 1 pihole pihole 3113 sep  8 08:18 /etc/pihole/tls.pem</code></pre>



<p>Tanto el usuario como el grupo pertenecen a pihole. Además los permisos están establecidos en 600</p>



<p>Fíjate, que nuestro nuevo archivo (el que se encuentra en /tmp) tiene como usuario a root y los permisos con 644</p>



<p>Vuelve otra vez a directorio /tmp para cambiar eso.</p>



<pre class="wp-block-code"><code>cd /tmp

sudo chown pihole:pihole tls.pem

sudo chmod 600 tls.pem
</code></pre>



<p>Ahora ya lo tenemos preparado. </p>



<pre class="wp-block-code"><code>me@linuxete:/tmp
$ <strong>ls -l</strong>
total 16
-rw-r--r-- 1 root root 2872 sep  8 19:57 fullchain.pem
-rw------- 1 root root  241 sep  8 19:58 privkey.pem
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">-rw------- 1 pihole pihole 3113 sep  8 20:01 tls.pem</mark></code></pre>



<h3 class="wp-block-heading">6. Sustituye al viejo tls</h3>



<p>Antes de sustituir tu antiguo archivo tls, considera hacer una copia de seguridad.</p>



<pre class="wp-block-code"><code>sudo mv /etc/pihole/tls.pem /etc/pihole/tls.pem.bak</code></pre>



<p>Tan solo nos queda mover el nuevo tls.pem para sustituir al antiguo.</p>



<pre class="wp-block-code"><code>sudo mv /tmp/tls.pem /etc/pihole/tls.pem</code></pre>



<h3 class="wp-block-heading">7. Reinicia el servicio Pi-hole</h3>



<p><strong>Reinicia el servicio de Pi-hole</strong> para que cargue el nuevo certificado.</p>



<pre class="wp-block-code"><code><code>sudo service pihole-FTL restart</code></code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Ahora, cuando accedas a la interfaz de administración de Pi-hole en <code>https://tudominio.com:7443/admin</code>, deberías ver que la conexión es segura y que el certificado es válido.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="477" height="539" src="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_011.png" alt="" class="wp-image-3468" style="width:299px;height:auto" srcset="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_011.png 477w, https://linuxete.duckdns.org/wp-content/uploads/2025/09/Seleccion_011-265x300.png 265w" sizes="(max-width: 477px) 100vw, 477px" /><figcaption class="wp-element-caption">Acceso vía HTTPS a Pi-hole</figcaption></figure>



<h2 class="wp-block-heading">Solución errores y advertencias.</h2>



<h3 class="wp-block-heading"> Advertencia, CERTIFICATE_DOMAIN_MISMATCH</h3>



<p>La advertencia que ves ahora es solo un mensaje interno del sistema de diagnóstico de Pi-hole que te informa que la configuración predeterminada de su certificado no coincide con su dominio interno (pi.hole).</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="853" height="795" src="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-17-51-50.png" alt="" class="wp-image-3546" srcset="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-17-51-50.png 853w, https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-17-51-50-300x280.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-17-51-50-768x716.png 768w" sizes="auto, (max-width: 853px) 100vw, 853px" /></figure>



<p>Si quieres eliminar esa advertencia en la página de diagnóstico, debes decirle a Pi-hole que utilice tu dominio (<code>tu_dominio.org</code>) en lugar de <code>pi.hole</code> como su <strong>nombre de host local</strong>.</p>



<h4 class="wp-block-heading">Modo gráfico.</h4>



<p>Para solucionar a través de la interfaz web, ve al menú izquierdo de tu pi-hole, abajo verás <code><strong>Settings</strong></code> y dentro verás <code><strong>All settings</strong></code>, en el apartado <code><strong>Webserver and API settings</strong></code>, en el campo <code><strong>Value</strong></code>, cambia <code><strong>pi.hole</strong></code> por tu dominio.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="744" height="705" src="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-22-10-39.png" alt="" class="wp-image-3547" srcset="https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-22-10-39.png 744w, https://linuxete.duckdns.org/wp-content/uploads/2025/09/Captura-desde-2025-11-02-22-10-39-300x284.png 300w" sizes="auto, (max-width: 744px) 100vw, 744px" /></figure>



<p>Guarda los cambios y reinicia el equipo.</p>



<h4 class="wp-block-heading">Modo comandos de terminal</h4>



<p>Conéctate a tu Raspberry Pi por SSH o usa la terminal local.</p>



<p>Edita el archivo de configuración TOML</p>



<pre class="wp-block-code"><code>sudo nano /etc/pihole/pihole.toml</code></pre>



<p><strong>Localiza la sección <code>[webserver]</code> y modifica la variable <code>domain</code>:</strong> Busca la sección <code>[webserver]</code> (si no existe, créala al final del archivo) y asegúrate de que la línea <code>domain</code> contenga tu dominio:</p>



<pre class="wp-block-code"><code>&#91;webserver] 
# ... otras configuraciones del webserver ... 
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">domain = "pi.hole"</mark>
 # ..</code></pre>



<p>y sustituirla por la de tu dominio.</p>



<pre class="wp-block-code"><code>&#91;webserver] 
# ... otras configuraciones del webserver ... 
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">domain = "tu_dominio.com"</mark>
 # ..</code></pre>



<p>Guarda y cierra el archivo (Ctrl+X, luego Y, luego Enter).</p>



<p>Reinicia Pi-hole FTL para cargar la nueva configuración TOML:</p>



<pre class="wp-block-code"><code>sudo service pihole-FTL restart</code></pre>



<p>Al cambiar <code>domain = "tu_dominio.com"</code> en el archivo <code>pihole.toml</code>, estás estableciendo el nombre de host principal que Pi-hole utiliza para sus comprobaciones internas de HTTPS. Esto debería eliminar el error <strong><code>CERTIFICATE_DOMAIN_MISMATCH</code></strong> de la página de diagnóstico.</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/anade-los-certificados-lets-encrypt-a-pi-hole-6/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Como recuperar tu contraseña desde un LiveUSB</title>
		<link>https://linuxete.duckdns.org/como-recuperar-tu-contrasena-desde-un-liveusb/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=como-recuperar-tu-contrasena-desde-un-liveusb</link>
					<comments>https://linuxete.duckdns.org/como-recuperar-tu-contrasena-desde-un-liveusb/#respond</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Sun, 23 Mar 2025 13:56:51 +0000</pubDate>
				<category><![CDATA[disco]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[Usuarios]]></category>
		<category><![CDATA[livecd]]></category>
		<category><![CDATA[liveusb]]></category>
		<category><![CDATA[password]]></category>
		<category><![CDATA[recovery password]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=2592</guid>

					<description><![CDATA[Todos sabemos que Linux es muy seguro, pero como alguien acceda físicamente a tu máquina desde un LiveUSB, te hace la pascua. Y es que como se vio en «Como montar tu disco duro desde un Live USB» aprendimos a acceder a los datos de un disco. Ahora ademas, veremos como cambiar la contraseña de [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="358" height="358" src="https://linuxete.duckdns.org/wp-content/uploads/2025/03/unnamed3.png" alt="" class="wp-image-2697" srcset="https://linuxete.duckdns.org/wp-content/uploads/2025/03/unnamed3.png 358w, https://linuxete.duckdns.org/wp-content/uploads/2025/03/unnamed3-300x300.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2025/03/unnamed3-150x150.png 150w" sizes="auto, (max-width: 358px) 100vw, 358px" /></figure>



<p>Todos sabemos que Linux es muy seguro, pero como alguien acceda físicamente a tu máquina desde un LiveUSB, te hace la pascua. Y es que como se vio en «<strong><a href="https://linuxete.duckdns.org/como-montar-disco-duro-desde-un-live-usb/">Como montar tu disco duro desde un Live USB</a></strong>» aprendimos a acceder a los datos de un disco. Ahora ademas, veremos como cambiar la contraseña de un usuario, e incluso la de root.</p>



<p>Para esto se usa Chroot (Change root) que es una utilidad del sistema Unix que se emplea para crear un nuevo entorno separado del directorio raíz del sistema principal. Este nuevo entorno se conoce como una «jaula chroot». Un usuario que opere dentro de la jaula no puede ver ni acceder ficheros fuera del entorno en el que se le ha confinado.</p>



<h2 class="wp-block-heading">¡Comenzamos!</h2>



<p>Inicia cualquier LiveUSB, yo lo haré con Debian 12 XFCE4. </p>



<p>Una vez iniciado el sistema, abre una terminal y escribe:</p>



<pre class="wp-block-code"><code>lsblk -p</code></pre>



<p>Como resultado tendremos esta salida:</p>



<pre class="wp-block-code"><code>demo@mx1:~
$ <strong>lsblk -p</strong>
NAME                   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
/dev/loop0               7:0    0   2,1G  1 loop /live/linux
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">/dev/sda</mark>                 8:0    0 111,8G  0 disk 
├─/dev/sda1              8:1    0 110,8G  0 part 
├─/dev/sda2              8:2    0     1K  0 part 
└─/dev/sda5              8:5    0   975M  0 part &#91;SWAP]
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">/dev/sdb</mark><strong> </strong>                8:16   0 298,1G  0 disk 
└─/dev/sdb1              8:17   0 298,1G  0 part 
<mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">/dev/sdc</mark>                 8:32   1  29,3G  0 disk 
├─/dev/sdc1              8:33   1  29,3G  0 part 
│ └─/dev/mapper/ventoy 254:0    0   2,2G  1 dm   /live/boot-dev
└─/dev/sdc2              8:34   1    32M  0 part 
demo@mx1:~</code></pre>



<p>Como puedes observar, se han listado 3 discos:</p>



<ul class="wp-block-list">
<li><strong>/dev/sda</strong> que es donde está insalado Debian 12 XFCE (lo sé porque tiene 3 particiones, siendo una de ella la swap)</li>



<li><strong>/dev/sdb </strong>que es un disco que tengo como almacen.</li>



<li><strong>/dev/sdc</strong> que es el propio Pendrive de arranque del Live USB.</li>



<li>También tenemos el <strong>/dev/loop0</strong> que es donde está montado nuestro sistema provisional.</li>
</ul>



<p>Si con <code>lsblk</code> no tienes toda la información que necesitas para identificar tu disco, puedes usar estos comandos que te dejo a continuación:</p>



<ul class="wp-block-list">
<li><strong>fdisk</strong> <br>fdisk es otra opción común entre los sysops. Actualmente lista las diferentes particiones (lo que está relacionado con los discos duros, ya que un disco duro puede estar dividido en varias particiones) de su sistema.<br><strong>    sudo fdisk &#8211;list</strong></li>



<li><strong>parted</strong><br>Esta es similar a las anteriores mencionadas, lista todas las particiones y permite gestionarlas. Su principal diferencia es que también te informa de la marca y modelo de tus discos duros e incluso del tipo de conectividad utilizada en el mismo (scsi, sata, etc) y del tamaño total del disco.<br><strong>    sudo parted -l</strong></li>



<li><strong>sfdisk</strong><br>Esto es muy similar a fdisk, sin embargo sfdisk le permite ver tanto los volúmenes físicos como los lógicos y también le da un «resumen» de las particiones de los volúmenes físicos reales con los cilindros (inicio y final), sectores, tamaño y tipo.<br>Probablemente la «s» es por «super», ya que es un fdisk con superpoderes:<br><strong>    sudo sfdisk -l</strong></li>
</ul>



<h4 class="wp-block-heading">Creando el directorio contenedor.</h4>



<p>Para el montaje del disco debes crear un directorio al que puedes llamar como quieras, yo lo llamaré <strong>disco</strong>, y el lugar donde lo haré, será en <code>/media</code>.</p>



<p>Así que en una terminal homologada escribe:</p>



<pre class="wp-block-code"><code>sudo mkdir /media/disco</code></pre>



<h4 class="wp-block-heading">Montando el disco</h4>



<p>Ahora, en la carpeta contenedora llamada <code><strong>disco</strong></code>, montaré el disco <code>sda1</code> así:</p>



<pre class="wp-block-code"><code>sudo mount /dev/sda1 /media/disco</code></pre>



<p>Si vuelves a hacer un <code>lsblk</code>, verás que <code>sda1</code>, tiene el punto de montaje en esa ruta.</p>



<pre class="wp-block-code"><code>demo@mx1:~
$ lsblk -p
NAME                   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
/dev/loop0               7:0    0   2,1G  1 loop /live/linux
/dev/sda                 8:0    0 111,8G  0 disk 
<strong><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">├─/dev/sda1              8:1    0 110,8G  0 part /media/disco</mark></strong>
├─/dev/sda2              8:2    0     1K  0 part 
└─/dev/sda5              8:5    0   975M  0 part &#91;SWAP]
/dev/sdb                 8:16   0 298,1G  0 disk 
└─/dev/sdb1              8:17   0 298,1G  0 part 
/dev/sdc                 8:32   1  29,3G  0 disk 
├─/dev/sdc1              8:33   1  29,3G  0 part 
│ └─/dev/mapper/ventoy 254:0    0   2,2G  1 dm   /live/boot-dev
└─/dev/sdc2              8:34   1    32M  0 part 
demo@mx1:~</code></pre>



<h4 class="wp-block-heading">Enjaular disco</h4>



<p>Para que Chroot funcione, este debe de ser montado dentro de un disco que tenga un sistema linux instalado, ya que bash necesitará estar instalado ahí. Si lo haces sobre un disco vacío, no funcionará ningún comando.</p>



<p>Y ahora que ya lo tenemos montado, ejecutamos el comando <strong>chroot</strong> para enjaularnos dentro de nuestro disco y poder ejecutar comandos como si estuviésemos operando desde ese disco</p>



<pre class="wp-block-code"><code>sudo chroot /media/disco</code></pre>



<p>En este momento, todo lo que hagamos solo afectará al disco donde estamos enjaulados.</p>



<p>Cambia el password de root así:</p>



<pre class="wp-block-code"><code>passwd root</code></pre>



<p>Y el de usuario, así:</p>



<pre class="wp-block-code"><code>passwd tu_usuario</code></pre>



<p>Ya solo queda reiniciar el equipo, quitar el Live Cd, e introducir las nuevas contraseñas.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/como-recuperar-tu-contrasena-desde-un-liveusb/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Añade WordPress a fail2ban.</title>
		<link>https://linuxete.duckdns.org/anade-wordpress-a-fail2ban/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=anade-wordpress-a-fail2ban</link>
					<comments>https://linuxete.duckdns.org/anade-wordpress-a-fail2ban/#respond</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Sat, 14 Sep 2024 19:41:06 +0000</pubDate>
				<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[fail2ban Debian 12]]></category>
		<category><![CDATA[wordpress fail2ban]]></category>
		<category><![CDATA[wordpress raspberry pi]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=1845</guid>

					<description><![CDATA[Después de dificultar el acceso a WordPress con reCAPTCHA, vamos a dar otra vuelta de tuerca a la seguridad de nuestro servidor. Si has llegado hasta aquí, te recomiendo que leas: Hasta aquí, tenemos un blog funcionando con WordPress y un sistema de bloqueo de accesos como fail2ban. Ahora vigilaremos los accesos e intentos de [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Después de dificultar el acceso a WordPress con <code><a href="https://www.google.com/recaptcha/about/">reCAPTCHA</a></code>, vamos a dar otra vuelta de tuerca a la seguridad de nuestro servidor.</p>



<p>Si has llegado hasta aquí, te recomiendo que leas:</p>



<ul class="wp-block-list">
<li><a href="https://linuxete.duckdns.org/instala-wordpress-en-tu-raspberry-pi-4/">Instala WordPress en tu Raspberry Pi</a></li>



<li><a href="https://linuxete.duckdns.org/instalar-fail2ban-en-debian-12-y-que-funcione/">Instalar Fail2ban en Debian 12 y que funcione.</a></li>
</ul>



<p>Hasta aquí, tenemos un blog funcionando con <code><strong>WordPress</strong></code> y un sistema de bloqueo de accesos como <code><strong>fail2ban</strong></code>. </p>



<p>Ahora vigilaremos los accesos e intentos de acceso al servidor <code><strong>WordPress</strong></code>.</p>



<p>Veamos como configurar todo esto.</p>



<h3 class="wp-block-heading">Crea el filtro</h3>



<p>Crearemos el siguiente fichero <code>/etc/fail2ban/filter.d/wordpress.conf</code> con el contenido:</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/filter.d/wordpress.conf</code></pre>



<p>Ahora pega lo siguiente:</p>



<pre class="wp-block-code"><code>&#91;Definition]<br>failregex = ^ .* "(GET|POST) /+wp-login.php<br>^ .* "(GET|POST) /+xmlrpc.php</code></pre>



<p>Guarda con Crtl + o y cierra con Crtl + x</p>



<h3 class="wp-block-heading">Crea el jail</h3>



<p>Crea también la siguiente jail con:</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.d/defaults-debian.conf</code></pre>



<p>Pega el lo siguiente a continuación de la última línea:</p>



<pre class="wp-block-code"><code>&#91;wordpress]
enabled = true
port = 443
filter = wordpress
logpath = /var/log/apache2/access.log
maxretry = 3
findtime = 15m
bantime = 1h
action = %(action_mwl)s</code></pre>



<p>Como antes, guarda con Crtl + o y cierra con Crtl + x</p>



<p>Reiniciamos fail2ban:</p>



<pre class="wp-block-code"><code>sudo systemctl restart fail2ban</code></pre>



<h2 class="wp-block-heading">Comprobaciones.</h2>



<p>Vamos a realizar una serie comprobaciones para ver si se están ejecutando correctamente los servicios, estados y  advertencias.</p>



<h3 class="wp-block-heading">Test estado del servicio</h3>



<p>Comprobamos el estado del servicio con:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="785" height="504" src="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-33-25.png" alt="" class="wp-image-1846" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-33-25.png 785w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-33-25-300x193.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-33-25-768x493.png 768w" sizes="auto, (max-width: 785px) 100vw, 785px" /></figure>



<p>De momento todo correcto, el servicio está activo y corriendo.</p>



<h3 class="wp-block-heading">Test estado general de fail2ban</h3>



<p>Comprobamos el estado y la cantidad de jails en funcionamiento.</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="540" height="325" src="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-35-25.png" alt="" class="wp-image-1848" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-35-25.png 540w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-35-25-300x181.png 300w" sizes="auto, (max-width: 540px) 100vw, 540px" /></figure>



<p>Perfecto, tenemos dos jail, el primero (ssh) que creamos en <a href="https://linuxete.duckdns.org/instalar-fail2ban-en-debian-12-y-que-funcione/">Instalar Fail2ban en Debian 12 y que funcione</a>, y el segundo el que acabamos de crear para wordpress.</p>



<h3 class="wp-block-heading">Test estado de Jails específicos</h3>



<p>Comprobemos el estado para la jail de WordPress.</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status wordpress</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="540" height="325" src="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-38-42.png" alt="" class="wp-image-1849" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-38-42.png 540w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-38-42-300x181.png 300w" sizes="auto, (max-width: 540px) 100vw, 540px" /></figure>



<p>La salida nos muestra bastante información sobre las IPs baneadas (ninguna por el momento), el número de intentos de conexión, el número de baneos etc etc</p>



<h3 class="wp-block-heading">Visualizar el log de eventos</h3>



<p>Veamos si el archivo log de fail2ban contiene algún error. Visualiza el archivo log en tiempo real para ver los cambios que se van produciendo instantáneamente.</p>



<p>Copia y pega el siguiente comando:</p>



<pre class="wp-block-code"><code>sudo tail -f /var/log/fail2ban.log</code></pre>



<p>En la siguiente imagen verás el log en tiempo real de los jail sin errores.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="949" height="325" src="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-41-43.png" alt="" class="wp-image-1850" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-41-43.png 949w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-41-43-300x103.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-41-43-768x263.png 768w" sizes="auto, (max-width: 949px) 100vw, 949px" /></figure>



<p></p>



<h3 class="wp-block-heading">Test de Fail2ban</h3>



<p>Fail2ban tiene un comando testear la configuración. Para esta comprobación tienes que usar este comando:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client --test</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="567" height="325" src="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-43-50.png" alt="" class="wp-image-1851" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-43-50.png 567w, https://linuxete.duckdns.org/wp-content/uploads/2024/09/Captura-desde-2024-09-11-18-43-50-300x172.png 300w" sizes="auto, (max-width: 567px) 100vw, 567px" /><figcaption class="wp-element-caption">Test de la configuración de fail2ban</figcaption></figure>



<p>Esto demuestra que todo está bien y no tenemos ningún problema con la configuración.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/anade-wordpress-a-fail2ban/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Instalar Fail2ban en Debian 12 y que funcione.</title>
		<link>https://linuxete.duckdns.org/instalar-fail2ban-en-debian-12-y-que-funcione/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=instalar-fail2ban-en-debian-12-y-que-funcione</link>
					<comments>https://linuxete.duckdns.org/instalar-fail2ban-en-debian-12-y-que-funcione/#comments</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Wed, 28 Aug 2024 16:11:53 +0000</pubDate>
				<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[fail2ban]]></category>
		<category><![CDATA[fail2ban Debian 12]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=1607</guid>

					<description><![CDATA[Internet está lleno de gente con menos vergüenza que un gato en una matanza, así que imagino que mi Raspberry Pi, al estar las 24 horas conectada a Internet, estará siendo atacada regularmente. Por este motivo, he decidido instalar Fail2ban. Si logras poner este tutorial en marcha, descubrirás que no estoy exagerando. ¿Qué es Fail2ban? [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="509" height="203" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/instalar-y-configurar-fail2ban.png" alt="" class="wp-image-1639" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/instalar-y-configurar-fail2ban.png 509w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/instalar-y-configurar-fail2ban-300x120.png 300w" sizes="auto, (max-width: 509px) 100vw, 509px" /></figure>



<p>Internet está lleno de gente con menos vergüenza que un gato en una matanza, así que imagino que mi Raspberry Pi, al estar las 24 horas conectada a Internet, estará siendo atacada regularmente. Por este motivo, he decidido instalar Fail2ban.</p>



<p>Si logras poner este tutorial en marcha, descubrirás que no estoy exagerando.</p>



<h2 class="wp-block-heading">¿Qué es Fail2ban?</h2>



<p>Fail2ban es una aplicación que te ayudará a proteger tu servidor contra ataques maliciosos y con la que podrás mantener tus datos seguros.</p>



<p>Fail2ban evitará los accesos de bots, es decir, de máquinas automatizadas que realizan intentos de acceso indiscriminados a los servidores. Este tipo de bots son muy comunes en Internet y simplemente se dedican a intentar loguearse en los servidores, probando diferentes usuarios y claves de acceso, para autorizarse correctamente y tomar el control de la máquina.</p>



<p>Fail2ban se encarga de monitorizar los registros de acceso al servidor en busca de fallos de acceso e impidiendo nuevos intentos de login desde las direcciones IP involucradas, por un tiempo determinado.</p>



<h2 class="wp-block-heading">Como instalar Fail2ban</h2>



<p>Para instalar fail2ban deberemos abrir una terminal y escribir lo siguiente:</p>



<pre class="wp-block-code"><code>sudo apt install fail2ban python3-systemd</code></pre>



<h2 class="wp-block-heading">Configuración</h2>



<p>La configuración de Fail2ban se encuentra en la carpeta «/etc/fail2ban/«. Allí encontraremos un archivo llamado «jail.conf» con las configuraciones del sistema. </p>



<p>Pero nosotros trabajaremos con una copia del archivo <strong>jail.conf</strong> a la que llamaremos <strong>jail.local</strong>, ya que así evitaremos que tras una actualización este pueda ser sustituido por la versión por defecto, cambiando así toda nuestra configuración.</p>



<p>El archivo <strong>jail.local</strong> se carga después de <strong>jail.conf</strong> y en él realizaremos nuestra configuración, por lo que todo lo que se escriba en <strong>jail.local</strong> es lo que se va a tener en cuenta definitivamente.</p>



<p>La copia del archivo jail.conf, la haremos desde la terminal con el comando cp (copy)</p>



<pre class="wp-block-code"><code>sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local</code></pre>



<p>Ahora abre el archivo en cuestión</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.local</code></pre>



<h3 class="wp-block-heading">Configuración Default (por defecto)</h3>



<p>En la sección [DEFAULT] encontramos las configuraciones predeterminadas que afectarán a todos los jail. Todas las configuraciones que pongas en [DEFAULT] son heredadas por los jail</p>



<p>En la sección «[DEFAULT]» encontramos la configuración global de las opciones. Allí veremos diversas variables a definir como las siguientes:</p>



<ul class="wp-block-list">
<li><strong>ignoreip:</strong> Aquí puedes añadir direcciones IP que&nbsp;<strong>nunca</strong>&nbsp;serán baneadas por Fail2ban. Por ejemplo, nuestra propia dirección IP.</li>



<li><strong>bantime:</strong> es el tiempo que una IP será baneada, expresado en segundos, minutos, horas, días &#8230;. (por defecto en 10 minutos)</li>



<li><strong>findtime:</strong> es el tiempo que transcurre entre intentos de conexión antes de ser baneado. (por defecto en 10 minutos)</li>



<li><strong>maxretry</strong>: es el número máximo de intentos de login que podrán realizarse antes de que la IP sea baneada. (por defecto en 5 intentos)</li>
</ul>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="725" height="512" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_148.png" alt="" class="wp-image-1669" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_148.png 725w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_148-300x212.png 300w" sizes="auto, (max-width: 725px) 100vw, 725px" /></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota si quieres que se ignoren todas las ips procedentes de tu red local, escribe la primera dirección IP (que suele ser la del router) seguido de un /24, esto hará que no se tengan en cuenta las direcciones de la 1 a la 254.</p>
</blockquote>



<p>Seguimos cambiando otras cosas de la sección <strong>Default</strong>.</p>



<p>Como yo no uso iptables, ya que el firewall lo tengo activo a nivel de router, haremos algunos cambios.</p>



<p>Busca las siguientes líneas y comenta con el signo #</p>



<pre class="wp-block-code"><code>&#91;Default]

banaction = iptables-multiport
banaction_allports = iptables-allports
</code></pre>



<p>Pega debajo las siguientes líneas.</p>



<pre class="wp-block-code"><code>banaction = nftables
banaction_allports = nftables&#91;type=allports]
</code></pre>



<p>Quedando como en la siguiente imagen.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="541" height="150" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/fail2ban.png" alt="" class="wp-image-1612" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/fail2ban.png 541w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/fail2ban-300x83.png 300w" sizes="auto, (max-width: 541px) 100vw, 541px" /></figure>



<p>Guarda con<code> Ctrl + o</code></p>



<h2 class="wp-block-heading">Configuración de Jail</h2>



<p>Baja hasta la sección <code>JAILS</code>, <code>SSH servers</code>, <code>[sshd]</code>.</p>



<pre class="wp-block-code"><code>#
# JAILS
#

#
# SSH servers
#

&#91;sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and det&gt;
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
</code></pre>



<p>Justo debajo de #mode = normal, añade lo siguiente:</p>



<pre class="wp-block-code"><code>enabled = true</code></pre>



<p>Esto habilitada el jail&nbsp;<strong>sshd</strong>.</p>



<p>Debajo, moddifica  las líneas en negrita, que son, el puerto de conexión, la ruta de log de eventos y el backend</p>



<pre class="wp-block-code"><code>&#91;sshd]
enabled = true
<strong>port    = 2353
logpath = %(sshd_log)s
backend = systemd</strong></code></pre>



<p>Quedando todo así:</p>



<pre class="wp-block-code"><code>#
# JAILS
#

#
# SSH servers
#

&#91;sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and det&gt;
#mode   = normal
<strong>enabled = true
port    = 2353
logpath = %(sshd_log)s
backend = systemd</strong></code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="has-medium-font-size"><em><strong>Nota: </strong>Cambia port por el puerto que usas en tu servidor ssh</em></p>
</blockquote>



<p>Reinicia el el servicio fail2ban así:</p>



<pre class="wp-block-code"><code>sudo systemctl restart fail2ban</code></pre>



<p>Hasta aquí todo listo, ya solo queda comprobar que todo va bien.</p>



<h3 class="wp-block-heading">Comprobaciones.</h3>



<p>Vamos a realizar una serie comprobaciones para ver si se están ejecutando correctamente los servicios, estados y  advertencias.</p>



<h3 class="wp-block-heading">Test estado del servicio</h3>



<p>Comprobamos el estado del servicio con:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<p>Es posible que después de hacer una status, el servicio aparezca inactivo, como se muestra en la siguiente imagen.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="963" height="475" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Captura-desde-2024-11-28-00-00-00.png" alt="" class="wp-image-2094" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Captura-desde-2024-11-28-00-00-00.png 963w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Captura-desde-2024-11-28-00-00-00-300x148.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Captura-desde-2024-11-28-00-00-00-768x379.png 768w" sizes="auto, (max-width: 963px) 100vw, 963px" /></figure>



<p>Para arreglar esto, haz lo siguiente. En una terminal, escribe:</p>



<pre class="wp-block-code"><code>sudo echo "sshd_backend = systemd" &gt;&gt; /etc/fail2ban/paths-debian.conf</code></pre>



<p>Reinicia el servicio con:</p>



<pre class="wp-block-code"><code>sudo systemctl restart fail2ban</code></pre>



<p>Y volvemos a ver el estado de como está el servicio:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="844" height="490" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_001.png" alt="" class="wp-image-1627" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_001.png 844w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_001-300x174.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_001-768x446.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /></figure>



<p>Ahora está todo correcto, el servicio aparece activo y corriendo.</p>



<h3 class="wp-block-heading">Test estado general de fail2ban</h3>



<p>Comprobamos el estado y la cantidad de jails en funcionamiento.</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="682" height="553" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_005.png" alt="" class="wp-image-1672" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_005.png 682w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_005-300x243.png 300w" sizes="auto, (max-width: 682px) 100vw, 682px" /></figure>



<h3 class="wp-block-heading">Test estado de Jails específicos</h3>



<p>Para comprobar si una jail específica funciona, en mi caso, <strong>ssh</strong>, ejecuta el siguiente comando:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status sshd</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="682" height="553" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_006.png" alt="" class="wp-image-1673" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_006.png 682w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_006-300x243.png 300w" sizes="auto, (max-width: 682px) 100vw, 682px" /></figure>



<p>La salida nos muestra bastante información sobre las IPs baneadas, el número de intentos de conexión, el número de baneos etc etc</p>



<h3 class="wp-block-heading">Visualizar el log de eventos</h3>



<p>Veamos si el archivo log de fail2ban contiene algún error. Visualiza el archivo log en tiempo real para ver los cambios que se van produciendo instantáneamente.</p>



<p>Copia y pega el siguiente comando:</p>



<pre class="wp-block-code"><code>sudo tail -f /var/log/fail2ban.log</code></pre>



<p>En la siguiente imagen verás que no aparece ningún error y se carga nuestro jail  <strong>sshd</strong></p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="296" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_002-1024x296.png" alt="" class="wp-image-1628" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_002-1024x296.png 1024w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_002-300x87.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_002-768x222.png 768w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_002.png 1258w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Test de Fail2ban</h3>



<p>Fail2ban tiene un comando testar la configuración. Para esta comprobación tienes que usar este comando:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client --test</code></pre>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="844" height="280" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_007.png" alt="" class="wp-image-1676" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_007.png 844w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_007-300x100.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_007-768x255.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /><figcaption class="wp-element-caption">Test de la configuración de fail2ban</figcaption></figure>



<p>Vaya! tenemos un mensaje de advertencia. No es un error, tampoco afectará al funcionamiento de fail2ban, pero se puede arreglar.</p>



<h3 class="wp-block-heading">Corregir advertencia Warning IPV6</h3>



<p>Para arreglar esto tendremos que abrir el archivo de configuración que se encuentra en <strong>/etc/fail2ban/fail2ban.conf</strong></p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/fail2ban.conf</code></pre>



<p>Ve al apartado <strong>[Definition]</strong>, verás que está vacío y escribe debajo lo siguiente:</p>



<pre class="wp-block-code"><code> <strong>allowipv6 = auto</strong></code></pre>



<p>Quedando de la siguiente manera:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="844" height="427" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_008.png" alt="" class="wp-image-1678" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_008.png 844w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_008-300x152.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_008-768x389.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /></figure>



<p>Volvemos a repetir el test y ahora se habrá quitado el mensaje de advertencia.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="844" height="427" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_009.png" alt="" class="wp-image-1680" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_009.png 844w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_009-300x152.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-_009-768x389.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /></figure>



<h2 class="wp-block-heading">Test de Baneo</h2>



<p>Provocamos un ban sobre nosotros para ver si la configuración es correcta.</p>



<p>Intento entrar por ssh desde mi teléfono móvil con una contraseña errónea. Debe de haber 5 intentos de conexión y un baneo de 10 minutos.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="433" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_003-1-1024x433.png" alt="" class="wp-image-1635" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_003-1-1024x433.png 1024w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_003-1-300x127.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_003-1-768x325.png 768w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_003-1.png 1258w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Conexión baneada por excesos de inicio de sesión fallidos. </figcaption></figure>



<p>Al quinto intento nos banea y como vimos antes, hasta transcurridos 10 minutos no dejará que volvamos a probar.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="461" height="1024" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-29-461x1024.jpg" alt="" class="wp-image-1630" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-29-461x1024.jpg 461w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-29-135x300.jpg 135w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-29.jpg 576w" sizes="auto, (max-width: 461px) 100vw, 461px" /><figcaption class="wp-element-caption">Conexión baneada por excesos de inicio de sesión fallidos. </figcaption></figure>



<p>Pasados 10 minutos, tal como está configurado en [Default] se levanta el baneo y dará permiso para volver a dejarnos entrar.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="433" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_004-1-1024x433.png" alt="" class="wp-image-1634" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_004-1-1024x433.png 1024w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_004-1-300x127.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_004-1-768x325.png 768w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/chapuboot@debian-etc-fail2ban_004-1.png 1258w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Desbaneo de una IP a los 10 minutos.</figcaption></figure>



<p>Mi teléfono vuelve a dejarnos escribir la contraseña. </p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="461" height="1024" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-35-461x1024.jpg" alt="" class="wp-image-1631" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-35-461x1024.jpg 461w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-35-135x300.jpg 135w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/photo_2024-08-28_17-27-35.jpg 576w" sizes="auto, (max-width: 461px) 100vw, 461px" /></figure>



<h2 class="wp-block-heading">Desbanear una IP</h2>



<p>Las IP baneadas pueden ser sacadas de la lista de ban sin tener que esperar al tiempo de ban por defecto. Para ello usa unban y la ip a desbanear.</p>



<pre class="wp-block-code"><code>sudo fail2ban-client unban 192.168.1.1</code></pre>



<h2 class="wp-block-heading">Envío de alertas por email.</h2>



<p>Para que <strong>fail2ban</strong> envíe alertas por email, debes de tener instalado y configurado algún programa que envíe correos electrónicos. En mi caso uso <strong>sSMTP</strong> y la configuración que usaré en fail2ban, será con este programa.</p>



<p><strong>sSMTP</strong> es un programa que envía correo electrónico desde un equipo a un servidor de correo configurado. Es decir que este no es un servidor de correo como si lo es sendmail o postfix sino que solo se encarga del envío de correos.</p>



<p>Fail2ban te avisará cuando una IP sea baneada, aportando una valiosa información acerca de su procedencia, proveedor etc etc</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><mark style="background-color:rgba(0, 0, 0, 0);color:#cf2e2e" class="has-inline-color">Importante, es indispensable instalar y configurar sSMTP</mark></p>
</blockquote>



<p>Si no tienes instalado y configurado sSMTP entra aquí <strong>«<a href="https://linuxete.duckdns.org/como-enviar-emails-con-ssmtp/">Como enviar emails con sSMTP</a>»  </strong>y seguir los pasos que allí te indico.</p>



<p>Si ya tienes configurado sSMTP, puedes seguir con la configuración <strong>jail.local</strong> &#8230;.</p>



<p>En una terminal homologada, escribe el siguiente comando:</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.local</code></pre>



<p>Ve al apartado <strong>Actions</strong></p>



<p>Busca la líneas que dicen, destemail y mta</p>



<pre class="wp-block-code"><code># Some options used for actions

# Destination email address used solely for the interpolations in
# jail.{conf,local,d/*} configuration files.
<strong>destemail = root@localhost</strong>

# Sender email address used solely for some actions
sender = root@&lt;fq-hostname&gt;

# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
# mailing. Change mta configuration parameter to mail if you want to
# revert to conventional 'mail'.
<strong>mta = sendmail</strong></code></pre>



<p>En <strong>destemail</strong> escribe la dirección de correo a la que llegarán las alertas, por ejemplo mi_email@gmail.com<br>En <strong>mta</strong> aquí usa el modo en que tu programa envía mails, en el caso de sSMTP pondré sendmail</p>



<pre class="wp-block-code"><code># Some options used for actions

# Destination email address used solely for the interpolations in
# jail.{conf,local,d/*} configuration files.
<strong>destemail = mi_email@gmail.com</strong>

# Sender email address used solely for some actions
sender = root@&lt;fq-hostname&gt;

# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
# mailing. Change mta configuration parameter to mail if you want to
# revert to conventional 'mail'.
<strong>mta = sendmail</strong></code></pre>



<p>Ve al Jail <strong>[sshd ]</strong> de la ruta <code>/etc/fail2ban/jail.local</code></p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.local</code></pre>



<p>Añade al fina la siguiente línea</p>



<pre class="wp-block-code"><code>action = %(action_mwl)s</code></pre>



<p>action = “mw” después de “action_” le dice a Fail2ban que le envíe correos electrónicos. “mwl” además adjunta los registros.</p>



<p>Ahora nuestra <strong>Jail sshd</strong> queda de la siguiente manera:</p>



<pre class="wp-block-code"><code>&#91;sshd]
enabled = true
port    = 2353
logpath = %(sshd_log)s
backend = systemd
<strong>action = %(action_mwl)s</strong></code></pre>



<p>Reinicia el servicio fail2ban</p>



<pre class="wp-block-code"><code>sudo systemctl restart fail2ban</code></pre>



<p>Vuelve a visualizar el log de eventos a ver si todo está correcto</p>



<pre class="wp-block-code"><code>sudo tail -f /var/log/fail2ban.log</code></pre>



<p>Si todo anda bien y no recibes errores, puedes intentar loguearte por ssh de forma errónea por 5 veces consecutivas y recibirás un bonito mail de baneo.</p>



<h3 class="wp-block-heading">Fallo de email al inicio (corrección)</h3>



<p>Aunque todo marcha bien, es muy probable que al arrancar el sistema, no lleguen los emails de inicio del servicio.</p>



<p>Esto se debe a que Fail2ban inicia su servicio de envío de correo antes de que el servicio de red esté completamente disponible. Como resultado, no puede alcanzar el servidor SMTP y el proceso falla. Cuando reinicias el servicio manualmente, la red ya está en pleno funcionamiento y la conexión se realiza sin problemas.</p>



<h4 class="wp-block-heading">Visualiza en busca de errores</h4>



<p>Una vez iniciado el sistema, haz un tail al registro de fail2ban para ver si tienes algún error</p>



<pre class="wp-block-code"><code>raspberry@pi5:~
<strong>sudo tail -f /var/log/fail2ban.log</strong>
To: mi_email@gmail.com\n
Hi,\n
The jail sshd has been started successfully.\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f "email@gmail.com" "mi_email@gmail.com"
2025-08-30 06:30:04,525 fail2ban.utils          &#91;932]: <mark style="background-color:#fcb900" class="has-inline-color">ERROR   7fff679379b0 -- stderr: 'sendmail: Cannot open smtp.gmail.com:587'</mark>
2025-08-30 06:30:04,525 fail2ban.utils          &#91;932]: ERROR   7fff679379b0 -- returned 1
2025-08-30 06:30:04,526 fail2ban.actions        &#91;932]: <mark style="background-color:#fcb900" class="has-inline-color">ERROR   Failed to start jail 'sshd' action 'sendmail-whois-lines': Error starting action Jail('sshd')/sendmail-whois-lines: 'Script error'</mark>
2025-08-30 06:30:05,506 fail2ban.filtersystemd  &#91;932]: INFO    &#91;sshd] Jail is in operation now (process new journal entries)
2025-08-30 06:38:04,525 fail2ban.filter         &#91;932]: INFO    &#91;sshd] Ignore 192.168.1.50 by ip
</code></pre>



<p>El primer error <strong><code>sendmail: Cannot open smtp.gmail.com:587</code></strong>, nos indica que fail2ban no pudo establecer una conexión con el servidor de correo de Gmail </p>



<p>Como resultado del fallo anterior <strong><code>Failed to start jail 'sshd' action 'sendmail-whois-lines': Error starting action Jail('sshd')/sendmail-whois-lines: 'Script error'</code></strong>nos dice que Fail2ban intentó ejecutar una acción (<code>sendmail-whois-lines</code>) para notificar que la <em>jail</em> de <code>sshd</code> se había iniciado, pero debido a que el envío de correo falló, la acción completa no pudo completarse.</p>



<h4 class="wp-block-heading">Solución al problema.</h4>



<p>Dentro de la ruta <code>etc/systemd/system/</code> crearemos un directorio con el nombre <code>fail2ban.service.d</code> y a su vez dentro de este crearemos un archivo con el nombre <code>override.conf</code>. Systemd lo detectará y le dará prioridad sobre la configuación original del servicio.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota, nunca edites los archivos originales de la ruta <code>/lib/systemd/system/</code> ya que pueden ser modificados tras un actualización del sistema.</p>
</blockquote>



<p>Usa el comando <code>mkdir -p</code> para crear el directorio.</p>



<pre class="wp-block-code"><code>sudo mkdir -p /etc/systemd/system/fail2ban.service.d/</code></pre>



<p>Utiliza el comando <code>sudo nano</code> para crear el archivo.</p>



<pre class="wp-block-code"><code>sudo nano /etc/systemd/system/fail2ban.service.d/override.conf</code></pre>



<p>Dentro del archivo pega las siguientes líneas:</p>



<pre class="wp-block-code"><code>&#91;Unit]
After=network.target network-online.target
Wants=network-online.target</code></pre>



<p><strong>Guarda el archivo</strong>,  presiona <strong><code>Ctrl + O</code></strong> (para «Write Out», que es guardar), confirma el nombre del archivo y luego presiona <strong><code>Enter</code></strong>. <br><strong>Sal del editor</strong>. Presiona <strong><code>Ctrl + X</code></strong>.</p>



<p>Estas tres líneas de configuración en <code>systemd</code> le dicen al sistema <strong>cómo y cuándo</strong> iniciar un servicio en relación con el estado de la red. Sirven para asegurar que un servicio, como Fail2ban, no se inicie antes de que la conexión a Internet esté completamente operativa.</p>



<p>Ahora, recarga <code>systemd</code> para que lea el nuevo archivo de configuración.</p>



<pre class="wp-block-code"><code>sudo systemctl daemon-reload</code></pre>



<p>Reinicia el sistema</p>



<pre class="wp-block-code"><code>sudo reboot</code></pre>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="111" src="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038-1024x111.png" alt="" class="wp-image-3127" srcset="https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038-1024x111.png 1024w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038-300x32.png 300w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038-768x83.png 768w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038-1536x166.png 1536w, https://linuxete.duckdns.org/wp-content/uploads/2024/08/Seleccion_038.png 1553w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Cuando cargue el sistema completamente, mira en tu bandeja de entrada y comprobarás los email de <strong>stopped</strong>, pero sobre todo los de <strong>started</strong> te aparecen.</p>



<h2 class="wp-block-heading">Control de fallos (incremento de la seguridad)</h2>



<p>Tenemos una opción con la que incrementar el tiempo de baneos de una ip. Con esta configuración, proporcionamos una protección más dinámica contra ataques de fuerza bruta, por lo que, si los atacantes persisten, serán bloqueados por períodos de tiempo cada vez más largos, lo que dificulta sus intentos de acceso.</p>



<p>Esto lo realizaremos con <strong>fail.increment</strong>, con lo que <strong>fail2ban</strong> aumentará el tiempo de bloqueo para cada intento fallido adicional de una IP.</p>



<h4 class="wp-block-heading">¿Cómo funciona?</h4>



<p>Si una IP falla X veces en X minutos, se bloqueará durante X horas.</p>



<p>Si la misma IP intenta conectarse nuevamente y falla otras X veces en X minutos, el tiempo de bloqueo se multiplicará por X horas.</p>



<p>Este proceso continúa, aumentando el tiempo de bloqueo en cada intento fallido adicional, hasta alcanzar el tiempo máximo de bloqueo definido en <strong>fail2ban_increment_max_bantime</strong>.</p>



<h4 class="wp-block-heading">¿Cómo lo hago?</h4>



<p>Vuelve a editar el archivo <strong>jail.local</strong> desde la terminal.</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.local</code></pre>



<p>Ahora en nuestro jail sshd, continua añadiendo las siguientes líneas.</p>



<pre class="wp-block-code"><code>maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true 
bantime.factor = 1.5 
bantime.maxtime = 1d</code></pre>



<p>Quedando de la siguiente manera</p>



<pre class="wp-block-code"><code>&#91;sshd]
enabled = true
port = 2353
logpath = %(sshd_log)s
backend = systemd
action = %(action_mwl)s
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 1.5
bantime.maxtime = 1d</code></pre>



<p>Explicación de los parámetros clave</p>



<ul class="wp-block-list">
<li>enabled = true: Activa el jail para SSH.</li>



<li>port = ssh: Especifica el puerto SSH (generalmente 22).</li>



<li>logpath = %(sshd_log)s Define la ruta al archivo de registro de autenticación.</li>



<li>maxretry = 3: Establece el número máximo de intentos fallidos antes de bloquear una IP.</li>



<li>bantime = 1h: Tiempo de bloqueo inicial de 1 hora.</li>



<li>findtime = 10m: Tiempo en el que se buscan los intentos fallidos (10 minutos).</li>



<li>fail2ban_actions: Define las acciones que se realizarán al bloquear una IP (bloqueo, envío de correo electrónico, etc.).</li>



<li>bantime.increment = true: Habilita la función de incremento de tiempo de bloqueo.</li>



<li>bantime.factor  = 1.5: Factor por el cual se multiplicará el tiempo de bloqueo en cada intento fallido adicional.</li>



<li>bantime.maxtime = 1d: Tiempo de bloqueo máximo de 1 día.</li>
</ul>



<h4 class="wp-block-heading">¿Cómo funciona fail.increment?</h4>



<p>En el ejemplo anterior, <strong>fail2ban</strong> aumentará el tiempo de bloqueo para cada intento fallido adicional de una IP. Por ejemplo:</p>



<p>Si una IP falla 3 veces en 10 minutos, se bloqueará durante 1 hora.</p>



<p>Si la misma IP intenta conectarse nuevamente y falla otras 3 veces en 10 minutos, el tiempo de bloqueo se multiplicará por 1.5 (1.5 horas).</p>



<p>Este proceso continúa, aumentando el tiempo de bloqueo en cada intento fallido adicional, hasta alcanzar el tiempo máximo de bloqueo definido en <strong>fail2ban_increment_max_bantime</strong>.</p>



<h2 class="wp-block-heading">Reincidentes</h2>



<p>¿Y que pasa con aquellos que son como moscas cojoneras, esos que no se dan por vencidos, y duran y duran como el conejito de Duracell? A esos los llamaremos los <strong>reincidentes</strong>, y para ellos existe un lugarl llamado <strong>Recidive Jail </strong>(cárcel para reincidentes).</p>



<h3 class="wp-block-heading">¿Qué es el <code>recidive jail</code>?</h3>



<p>La palabra «recidive» se refiere a la reincidencia. El <code>recidive jail</code> es un jail especial de fail2ban diseñado para detectar y banear a las <strong>direcciones IP reincidentes</strong>, es decir, aquellas que han sido baneadas en múltiples ocasiones por diferentes jails (o el mismo jail) en un corto período de tiempo.</p>



<p>En lugar de banear a una IP por un único ataque de fuerza bruta, el <code>recidive jail</code> la considera una amenaza persistente y la castiga con un bloqueo mucho más largo.</p>



<h3 class="wp-block-heading">¿Cómo funciona?</h3>



<p>A diferencia de otros jails que monitorean archivos de registro de servicios específicos (como SSH o Apache), el <code>recidive jail</code> monitorea el <strong>propio archivo de registro de fail2ban</strong> (<code>/var/log/fail2ban.log</code>). Busca entradas que indiquen que una IP ha sido baneada y, si el mismo atacante ha sido baneado varias veces, aplica un nuevo bloqueo, mucho más largo.</p>



<h3 class="wp-block-heading">¿Cómo lo activo?</h3>



<p>El <code>recidive jail</code> suele venir preconfigurado en las instalaciones de fail2ban. Para activarlo, generalmente solo necesitas editar tu archivo de configuración <code>jail.local</code> y asegurarte de que la sección <code>[recidive]</code> esté habilitada (<code>enabled = true</code>).</p>



<p>Escribe en tu terminal homologada:</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/jail.local</code></pre>



<p>Busca las siguientes líneas, donde dice <code>[recidive]</code> (si usas el editor nano, Crtl + w te permite buscar por palabra clave)</p>



<pre class="wp-block-code"><code># Jail for more extended banning of persistent abusers
# !!! WARNINGS !!!
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
#    is not at DEBUG level -- which might then cause fail2ban to fall into
#    an infinite loop constantly feeding itself with non-informative lines
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
#    to maintain entries for failed logins for sufficient amount of time
<mark style="background-color:#7bdcb5" class="has-inline-color">&#91;recidive]</mark>

logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 1w
findtime = 1d
</code></pre>



<p>Si no lo tienes o lo tienes en <code>false</code>, añade debajo de <code>[recidive]</code> la variable <code>enabled=true</code></p>



<pre class="wp-block-code"><code># Jail for more extended banning of persistent abusers
# !!! WARNINGS !!!
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
#    is not at DEBUG level -- which might then cause fail2ban to fall into
#    an infinite loop constantly feeding itself with non-informative lines
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
#    to maintain entries for failed logins for sufficient amount of time
&#91;recidive]

<mark style="background-color:#fcb900" class="has-inline-color">enabled = true</mark>
logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 1w
findtime = 1d
<mark style="background-color:#fcb900" class="has-inline-color">maxretry = 3</mark></code></pre>



<p>También he añadido un <code>maxretry = 3</code>, ya que no tampoco estaba en la configuración inicial.</p>



<p>Que significa esto:</p>



<ul class="wp-block-list">
<li><code><strong>bantime</strong></code>: Este es el tiempo que durará el bloqueo por reincidencia. En este ejemplo, es 1 semana (<code>1w</code>). Puedes ajustarlo a tu gusto (por ejemplo, <code>1d</code> para 1 día, <code>24h</code> para 24 horas, o incluso <code>1y</code> para 1 año, tambien con -1 sería por tiempo indefinido).</li>



<li><code><strong>findtime</strong></code>: Este es el período de tiempo durante el cual fail2ban buscará reincidencias. En este ejemplo, el jail buscará si una IP ha sido baneada en cualquier otro jail durante el último día (<code>1d</code>).</li>



<li><strong><code>maxretry = 3</code>:</strong>  Este valor significa que si una misma IP es baneada en cualquiera de tus jails (SSH, WordPress, etc.) 3 veces en el período de <code>1d</code> (<code>findtime</code>), el <code>recidive jail</code> se activará y le aplicará el baneo de 1 año. El valor de <code>3</code> es un buen punto de partida, ya que un atacante podría haber sido baneado dos veces en <code>sshd</code> o en <code>wordpress</code> y la tercera vez, independientemente del servicio, será baneado por el <code>recidive jail</code>.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nota: Revisando la documentación de fail2ban, la manera en que el <code>recidive jail</code> detecta la reincidencia es mediante la lectura de su propio registro (<code>/var/log/fail2ban.log</code>). El jail se activa cuando encuentra la palabra «Ban» un número de veces dentro del <code>findtime</code> especificado.</p>
</blockquote>



<p>Veamos ahora que nos dice nuestro fail2ban.log</p>



<pre class="wp-block-code"><code>sudo tail -f /var/log/fail2ban.log</code></pre>



<pre class="wp-block-code"><code>raspberry@pi5:~
$ <strong>sudo tail -f /var/log/fail2ban.log</strong>
2025-08-25 22:50:46,292 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Ignore 192.168.1.1 by ip
2025-08-25 22:51:26,359 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Ignore 192.168.1.1 by ip
2025-08-25 22:52:26,340 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Ignore 192.168.1.1 by ip
2025-08-25 22:52:31,651 fail2ban.actions        &#91;374644]: NOTICE  &#91;wordpress] Unban 59.125.157.215
2025-08-25 22:53:37,381 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 65.109.154.253 - 2024-08-29 22:53:37
2025-08-25 22:53:37,563 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 65.109.154.253 - 2024-08-29 22:53:37
2025-08-25 22:53:44,556 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 65.109.154.253 - 2024-08-29 22:53:44
2025-08-25 22:53:44,881 fail2ban.actions        &#91;374644]: NOTICE  &#91;wordpress] Ban 65.109.154.253
2025-08-25 22:53:44,885 fail2ban.filter         &#91;374644]: <mark style="background-color:#7bdcb5" class="has-inline-color">INFO    &#91;recidive] Found 65.109.154.253</mark> - 2024-08-29 22:53:44
2025-08-25 22:54:54,188 fail2ban.filter         &#91;374644]: INFO    &#91;sshd] Ignore 192.168.1.50 by ip
2025-08-25 22:58:51,595 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 101.68.43.75 - 2024-08-29 22:58:51
2025-08-25 22:58:52,296 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 101.68.43.75 - 2024-08-29 22:58:52
2025-08-25 22:58:58,201 fail2ban.filter         &#91;374644]: INFO    &#91;wordpress] Found 101.68.43.75 - 2024-08-29 22:58:57
2025-08-25 22:58:58,261 fail2ban.actions        &#91;374644]: NOTICE  &#91;wordpress] Ban 101.68.43.75
2025-08-25 22:58:58,266 fail2ban.filter         &#91;374644]: <mark style="background-color:#7bdcb5" class="has-inline-color">INFO    &#91;recidive] Found 101.68.43.75</mark> - 2024-08-29 22:58:58
</code></pre>



<p>La línea <code>INFO [recidive] Found 65.109.154.253</code> e <code>INFO [recidive] Found 101.68.43.75</code> significan que <code>recidive</code> se ha dado cuenta de que esa IP ha sido baneada en mas de una ocasión, pero aún no han sido baneadas por <code>recidive</code> porque no han cumplido los criterios de reincidencia.</p>



<p>Como podemos ver en la salida del comando:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status recidive</code></pre>



<p>Esto no significa que recidive haya enviado  ya la haya baneado.</p>



<pre class="wp-block-code"><code>raspberry@pi5:~
$ <strong>sudo fail2ban-client status recidive</strong>
Status for the jail: recidive
|- Filter
|  |- Currently failed:	19
|  |- Total failed:	19
|  `- File list:	/var/log/fail2ban.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:	
</code></pre>



<p>En la salida de <code>fail2ban-client status recidive</code>, observamos que:</p>



<ul class="wp-block-list">
<li><code>Currently failed: 19</code> y <code>Total failed: 19</code>: Esto confirma que el filtro del <code>recidive jail</code> ha detectado 19 baneos totales en otros jails. El <code>recidive jail</code> está haciendo su trabajo de contar los baneos.</li>



<li><code>Currently banned: 0</code> y <code>Total banned: 0</code>: Esto indica que ninguna de las IPs ha alcanzado el umbral para ser considerada reincidente. Las IPs anteriormente mostradas en el <code>log</code> (65.109.154.253 y 101.68.43.75) han sido baneadas una sola vez en el <code>log</code>, por lo que no han activado la acción de ban del <code>recidive jail</code>.</li>
</ul>



<h2 class="wp-block-heading">Mi configuración.</h2>



<p>Y para terminar, después de un tiempo de uso, he estado probando varias configuraciones, y estas son las que uso actualmente:</p>



<h3 class="wp-block-heading">Configuración [sshd]</h3>



<pre class="wp-block-code"><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-ast-global-color-1-color">&#91;sshd]
enabled = true
port    = 2353
logpath = %(sshd_log)s
backend = systemd
action = %(action_mwl)s
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 24
bantime.maxtime = 5w</mark></code></pre>



<h3 class="wp-block-heading">Configuración [recidive]</h3>



<pre class="wp-block-code"><code># Jail for more extended banning of persistent abusers
# !!! WARNINGS !!!
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
#    is not at DEBUG level -- which might then cause fail2ban to fall into
#    an infinite loop constantly feeding itself with non-informative lines
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
#    to maintain entries for failed logins for sufficient amount of time
<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-ast-global-color-1-color">&#91;recidive]

enabled = true
logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 1y
findtime = 1d</mark>
<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-ast-global-color-1-color">maxretry = 3</mark></code></pre>



<p>Tal vez te estés preguntando, ¿para que usamos b<code>antime.increment</code> con un <code>bantime.maxtime</code> de 5 semanas, si en un día los reincidentes serán expulsados por un año?. ¿No le dará tiempo a bantime.increment a echar a nadie por 5 semanas?</p>



<p>Pues tiene su lógica, imaginemos 2 escenarios distintos:</p>



<h5 class="wp-block-heading">Escenario 1: Ataques que no cumplen los criterios de <code>recidive</code></h5>



<ul class="wp-block-list">
<li><strong>Un atacante muy lento y persistente:</strong> Un atacante podría hacer un par de intentos, ser baneado, y no volver a intentar nada por 36 horas. Luego, repite el proceso. Como el <code>findtime</code> de tu <code>recidive jail</code> es <code>1d</code> (un día), los intentos de este atacante podrían quedar fuera del rango de detección de <code>recidive</code>. En este caso, el <code>bantime.increment</code> seguirá aumentando el tiempo de baneo con cada nuevo intento, sin que <code>recidive</code> se active.</li>
</ul>



<h5 class="wp-block-heading">Escenario 2: Ataques contra un solo servicio y de forma intermitente</h5>



<ul class="wp-block-list">
<li>Si un atacante solo se enfoca en SSH y va incrementando su tiempo de espera entre ataques, el <code>bantime.increment</code> del <code>sshd</code> jail se encargará de él. Un atacante podría ser baneado por 1 hora, luego 24 horas, y luego 5 días. Si el atacante vuelve a intentar después de los 5 días, el <code>bantime.increment</code> seguiría su progresión hasta alcanzar las 5 semanas, castigando el comportamiento persistente en <strong>ese servicio en particular</strong>, sin que el <code>recidive jail</code> se active si no cumple con sus criterios de frecuencia.</li>
</ul>



<h5 class="wp-block-heading">Conclusión</h5>



<p>Pensemos en nuestros jails como una defensa por capas:</p>



<ol start="1" class="wp-block-list">
<li><strong>Capa 1: Jails individuales</strong> (<code>sshd</code>, <code>wordpress</code>, etc.). Son tu primera línea de defensa, con reglas para bloquear ataques de fuerza bruta rápidos.</li>



<li><strong>Capa 2: <code>bantime.increment</code></strong>. Es la capa que maneja la <strong>persistencia</strong> contra un <strong>único servicio</strong>. Su propósito es hacer cada vez más costoso para un atacante seguir intentando contra ese servicio.</li>



<li><strong>Capa 3: <code>recidive jail</code></strong>. Es la defensa definitiva contra la <strong>reincidencia general</strong> en tu sistema. Se encarga de los atacantes más serios que atacan múltiples servicios o persisten a pesar de los baneos iniciales.</li>
</ol>



<p>El <code>bantime.maxtime</code> garantiza que la Capa 2 sea muy efectiva por sí misma, incluso si el atacante no cumple los criterios para ser considerado «reincidente» por el <code>recidive jail</code>. Por lo que conviene usarlo, ya que cubre escenarios que el <code>recidive jail</code> no. Esta configuración es muy sólida y está bien pensada, ya que combina de manera excelente estas diferentes capas de seguridad.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/instalar-fail2ban-en-debian-12-y-que-funcione/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
	</channel>
</rss>
