# OperacjeProwadzić daemona w produkcji: rotacja logów, syslog, lifecycle daemona i znane obrazy błędów.

## Rotacja logów

Daemon obsługuje oba popularne wzorce rotacji:

- **Rotate-and-Rename** (access-log zostaje przemianowany, nowy plik zajmuje jego miejsce). Wykrywane przez zmianę inode/device na obserwowanej ścieżce.
- **Copytruncate** (zawartość pliku jest kopiowana gdzie indziej, potem oryginał obcięty do rozmiaru zero). Wykrywane przez `tell() > stat()`.

W obu przypadkach daemon otwiera plik na nowo od początku i zapisuje `info reopen after rotate dev=… ino=…` (Rotate-and-Rename) lub `info truncate file shrank` (Copytruncate) na stderr.

Jeśli wokół rotacji brakuje wpisów, sprawdź konfigurację narzędzia rotacji:

- Na OpenBSD `newsyslog` standardową rotacją jest Rotate-and-Rename — żadna specjalna konfiguracja nie jest potrzebna.
- Na Linuksie `logrotate` lepiej brać default (rotacja + SIGHUP do serwera web) zamiast trybu `copytruncate`. Oba działają, ale Rotate-and-Rename jest tańszy i nie traci linii.

## Skrypt `rc.d` (OpenBSD)

Minimalny wariant `/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
```

Potem:

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

Na Linuksie z systemd patrz dokumentacja dystrybucji; prosta jednostka `Type=simple` wskazująca na `/usr/local/sbin/abusive_http_watch` z tymi samymi argumentami wystarcza.

## Eventy syslog

Daemon emituje jedną klasę eventów — `added` — gdy nowe IP przekracza próg trafień. Format:

```
<syslog-tag>[<pid>]: added ip=<ip> path=<ścieżka-blocklisty>
```

Przykład:

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

Przez `syslog.conf` zrutować do osobnego pliku do przeglądu:

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

W połączeniu z `ABUSIVE_SYSLOG_FACILITY=local0` daje to czyste audit-log każdego zablokowanego IP.

## Sygnały monitoringu

Dla zautomatyzowanego monitoringu dwa wskaźniki są użyteczne:

- **Tempo wzrostu blocklisty** — `wc -l /var/www/run/abusive_http_hosts` w czasie. Na publicznym serwerze web to powinno stale rosnąć (od kilku IP dziennie do wielu na godzinę, zależnie od ekspozycji). Płaska linia przez 24 h na publicznej stronie wskazuje, że daemon nie działa lub czyta zły log.
- **Health procesu** — `pgrep -f abusive_http_watch` powinno zawsze zwracać dokładnie jedną PID. Alert przy zero.

Dla setupów Prometheus wystarczy maleńki eksporter, który po prostu robi `wc -l` na pliku blocklisty i eksponuje liczbę jako gauge. Bez metrics-endpointu w samym daemonie — by design, aby utrzymać go bez zależności.

## Troubleshooting

### Plik blocklisty pozostaje pusty

Możliwe przyczyny, według prawdopodobieństwa:

1. **Daemon czyta zły plik.** Uruchomić na pierwszym planie z `ABUSIVE_DEBUG=1`. Sprawdzić, czy loguje `start following dev=… ino=…` dla oczekiwanej ścieżki. Jeśli nie, poprawić argument.
2. **Brak prawdziwego ruchu ataków.** Mało prawdopodobne na publicznym serwerze web, ale możliwe wewnętrznie. Uruchomić z `ABUSIVE_DEBUG=1` i szukać linii `[dbg] ip=…` bez odpowiadającego `[dbg] token match`.
3. **Whitelist pochłania wszystko.** Sprawdzić `/etc/abusive_http_whitelist` — błędny wpis CIDR `/0` whitelistuje cały internet. Usunąć i zrestartować.
4. **Próg trafień zbyt wysoki.** Testowo obniżyć `ABUSIVE_MIN_HITS` do `1` i obserwować zachowanie.

### Blocklista rośnie, ale firewall nie blokuje

Daemon pisze plik. Firewall musi zostać poinstruowany, aby go czytał. Sprawdzić:

- Cron przeładowuje tabelę `pf` / set `nftables` co kilka minut (daemon nie wywołuje `pfctl` sam).
- Reguła firewalla, która wskazuje na tabelę, jest w odpowiednim chain i `quick` na tyle, aby chwytać przed późniejszymi regułami `pass`.

### Legalni użytkownicy są blokowani

Dodać ich publiczny IP lub CIDR-range do `/etc/abusive_http_whitelist`. Daemon czyta whitelistę przy każdej linii — zmiany działają w ciągu sekund.

Aby usunąć pojedyncze IP z istniejącej blocklisty, edytować plik bezpośrednio i przeładować tabelę firewalla. Daemon nie potrzebuje restartu — wpisze IP ponownie tylko wtedy, gdy użytkownik znowu trafi w tokeny.

### Daemon crashuje po rotacji logów

Nie powinno się wydarzyć z opisaną wyżej obsługą rotacji. Jeśli jednak tak, uruchomić na pierwszym planie z `ABUSIVE_DEBUG=1`, wywołać rotację i zapisać stderr. Zapisany log wysłać przez stronę [Kontakt](/pl/contact/) — to prawdziwy bug, który chcemy naprawić.

## Czysty shutdown

Daemon łapie `SIGTERM` i kończy czysto po aktualnej iteracji:

```sh
doas rcctl stop abusive_http_watch
```

Loguje `[info] TERM received, exiting`, zamyka handle pliku logu, flushuje wszystkie oczekujące write'y i kończy ze statusem 0. Bez korupcji stanu, nawet przy mocno używanym logu.
