# OperaciónCorrer el daemon en producción: rotación de logs, syslog, ciclo de vida del daemon y modos de fallo conocidos.

## Rotación de logs

El daemon maneja los dos esquemas estándar de rotación:

- **Rotate-and-rename** (el log se renombra, un nuevo fichero toma
  su lugar). Detectado por cambio de inodo/device en la ruta
  vigilada.
- **Copytruncate** (el contenido se copia a otro sitio y luego se
  trunca el original a cero). Detectado por `tell() > stat()`.

En ambos casos el daemon reabre el fichero desde el principio y
escribe `info reopen after rotate dev=… ino=…` (rotate-and-rename)
o `info truncate file shrank` (copytruncate) en stderr.

Si observas entradas perdidas alrededor de la rotación, revisa la
config de la herramienta de rotación:

- En OpenBSD `newsyslog`, la rotación por defecto es
  rotate-and-rename — no requiere configuración especial.
- En Linux `logrotate`, preferir el default (rotar y SIGHUP al
  servidor web) sobre el modo `copytruncate`. Ambos funcionan,
  pero rotate-and-rename es más barato y no pierde líneas.

## Script `rc.d` (OpenBSD)

Variante mínima `/etc/rc.d/abusive_http_watch`:

```sh
#!/bin/ksh
daemon="/usr/local/sbin/abusive_http_watch"
daemon_flags="/var/www/logs/access.log"
daemon_user="_www"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_cmd $1
```

Luego:

```sh
doas rcctl enable abusive_http_watch
doas rcctl start abusive_http_watch
doas rcctl check abusive_http_watch
```

En Linux con systemd, ver la doc de la distribución; una unidad
simple `Type=simple` apuntando a
`/usr/local/sbin/abusive_http_watch` con los mismos argumentos
basta.

## Eventos syslog

El daemon emite una clase de evento — `added` — cuando una IP
cruza el umbral de hits. Formato:

```
<syslog-tag>[<pid>]: added ip=<ip> path=<ruta-blocklist>
```

Ejemplo:

```
abusive_http_watch[12345]: added ip=198.51.100.42 path=/var/www/run/abusive_http_hosts
```

Rutar vía `syslog.conf` a un fichero dedicado para revisión:

```
local0.notice                                          /var/log/abusive_http.log
```

Combinado con `ABUSIVE_SYSLOG_FACILITY=local0`, da un log de
auditoría limpio de cada IP bloqueada.

## Señales de monitorización

Para monitorización automatizada, dos indicadores útiles:

- **Tasa de crecimiento de la blocklist** —
  `wc -l /var/www/run/abusive_http_hosts` en el tiempo. En un
  servidor web público debería crecer de forma sostenida (varias
  IPs por día a muchas por hora, según exposición). Una línea
  plana de 24h en un sitio público sugiere que el daemon no corre
  o lee el log equivocado.
- **Salud del proceso** — `pgrep -f abusive_http_watch` debería
  retornar siempre un PID. Alertar si cero.

Para sistemas con Prometheus, un exporter pequeño que solo
`wc -l` el fichero blocklist y exponga el conteo como gauge es
suficiente. No hay endpoint de métricas dentro del daemon — por
diseño, para mantenerlo sin dependencias.

## Troubleshooting

### El fichero blocklist se queda vacío

Causas posibles, por orden de probabilidad:

1. **El daemon lee el fichero equivocado.** Lanzar en primer
   plano con `ABUSIVE_DEBUG=1`. Confirmar que logea
   `start following dev=… ino=…` para la ruta esperada. Si no,
   corregir el argumento.
2. **No hay tráfico de ataque real.** Improbable en un servidor
   web público, posible en uno interno. Lanzar con
   `ABUSIVE_DEBUG=1` y buscar líneas `[dbg] ip=…` sin
   `[dbg] token match` asociado.
3. **La whitelist se traga todo.** Revisar
   `/etc/abusive_http_whitelist` — una entrada CIDR `/0` errante
   whitelistea internet entero. Quitar y reiniciar.
4. **Umbral de hits demasiado alto.** Bajar `ABUSIVE_MIN_HITS` a
   `1` temporalmente y observar.

### La blocklist crece pero el firewall no bloquea

El daemon escribe el fichero. Hay que decirle al firewall que lo
lea. Verificar:

- Cron recarga la tabla `pf` / el set `nftables` cada pocos
  minutos (el daemon no llama a `pfctl` por sí mismo).
- La regla firewall que referencia la tabla está en la cadena
  correcta y suficientemente `quick` para tomar efecto antes de
  cualquier `pass` posterior.

### Usuarios legítimos están siendo bloqueados

Añadir su IP pública o rango CIDR a
`/etc/abusive_http_whitelist`. El daemon relee la whitelist en
cada línea — los cambios surten efecto en segundos.

Para retirar una IP individual de la blocklist existente, editar
el fichero directamente y recargar la tabla firewall. El daemon
no necesita reinicio — no la añadirá de nuevo a menos que el
usuario vuelva a tocar tokens.

### El daemon crashea tras una rotación de logs

No debería ocurrir dado el manejo de rotación descrito arriba.
Si ocurre, lanzar en primer plano con `ABUSIVE_DEBUG=1`,
provocar una rotación, capturar stderr. Enviar el log capturado
por la página de [Contacto](/es/contact/) — eso es un bug real
que merece arreglarse.

## Apagado limpio

El daemon captura `SIGTERM` y sale limpiamente tras la iteración
actual:

```sh
doas rcctl stop abusive_http_watch
```

Logea `[info] TERM received, exiting`, cierra el handle del log,
flushea cualquier escritura pendiente y sale con status 0. Sin
corrupción de estado, ni siquiera en un log muy activo.
