# Incident 2026-07-31 — LXC 110 (moltbot): DNS mort după logout Tailscale + OOM **Severity:** Medium (serviciu `echo-core` indisponibil ~8 min; fără pierdere de date) **Detected:** 2026-07-31 ~09:28 EEST (user — „nu mai răspunde la SSH, nu mai merge echo") **Resolved:** 2026-07-31 09:34 EEST (fix DNS) + 09:5x EEST (zram pe pve1) **Author:** Claude Code (mmarius28@gmail.com) --- ## TL;DR — lanțul cauzal 1. **06:26 UTC** — LXC 110 se oprește după **65 zile uptime**. În log-urile de shutdown: `user-1000.slice: A process of this unit has been killed by the OOM killer`. OOM **local containerului** (plafon 8GB), NU la nivel de host — pve1 nu a avut niciun OOM în 30 de zile și avea 18GB available. 2. **06:26:59** — la revenire, `tailscaled` generează nodekey nou și rămâne **delogat** (`machineAuthorized=false`, `authURL=true`). 3. **DNS moare complet.** LXC 110 nu avea `nameserver` în `pct config`, deci moștenea `/etc/resolv.conf` de la host-ul **pve1** — iar acolo fișierul e scris de Tailscale și conținea **doar MagicDNS** (`100.100.100.100` + `fd7a:115c:a1e0::53`). Cu Tailscale delogat, resolverul devine inaccesibil. 4. **`echo-core.service` intră în crash-loop** cu `telegram.error.TimedOut` (restart counter ajunsese la **11**). **Capcana de diagnostic:** rețeaua L3 era perfect funcțională — `ping 8.8.8.8` OK, gateway OK, rută OK. Doar **rezoluția numelor** pica. Ușor de interpretat greșit ca „bot stricat" sau „internet căzut". SSH-ul „care nu răspundea" era doar containerul în curs de repornire — la verificare funcționa deja normal. --- ## Diagnostic — comenzi cheie ```bash # NU te lua după ping — verifică întâi rezoluția getent hosts api.telegram.org # gol => DNS mort cat /etc/resolv.conf # doar 100.100.100.100 => depinde de Tailscale ping -c2 8.8.8.8 # OK => L3 e sănătos, problema e DNS tailscale status # "Logged out." # serviciile echo rulează ca user systemd (user moltbot) su - moltbot -c 'XDG_RUNTIME_DIR=/run/user/1000 systemctl --user status echo-core' ``` ## Fix 1 — DNS explicit (aplicat) ```bash # pe pve1 pct set 110 --nameserver '10.0.20.1 1.1.1.1' # persistent, aplicat la următorul start # live, fără restart de container (backup: /etc/resolv.conf.bak-2026-07-31) printf '# --- BEGIN PVE ---\nnameserver 10.0.20.1\nnameserver 1.1.1.1\n# --- END PVE ---\n' \ > /etc/resolv.conf su - moltbot -c 'XDG_RUNTIME_DIR=/run/user/1000 systemctl --user restart echo-core' ``` Rezultat: Telegram `getUpdates` → 200 OK, Discord online, 0 restarturi ulterioare. > **Expunere similară:** orice alt LXC de pe pve1 **fără `nameserver` explicit** moștenește > același resolv.conf Tailscale și va pica identic la un logout Tailscale. ## Fix 2 — zram swap pe pve1 (aplicat) `pct config 110` avea `swap: 4096`, dar în container `free -h` arăta **`Swap: 0B`**. Cauza: limita cgroup exista corect pe host… ``` /sys/fs/cgroup/lxc/110/memory.max = 8589934592 (8 GB) /sys/fs/cgroup/lxc/110/memory.swap.max = 4294967296 (4 GB) <- plafon OK /sys/fs/cgroup/lxc/110/memory.swap.current = 0 <- nimic nu-l umple ``` …dar **pve1 nu avea niciun swap** (`swapon --show` gol, nimic în `/etc/fstab`). Limita cgroup e doar un *plafon* peste swap-ul host-ului; fără backing store fizic, kernelul nu are unde scrie paginile. Root-ul pve1 e pe ZFS (`rpool/ROOT/pve-1`), deci swapfile e exclus (risc de deadlock) — aceeași situație rezolvată pe pvemini în 2026-06-24. ```bash # pe pve1 (host) — identic cu pvemini apt install -y zram-tools cat > /etc/default/zramswap <<'EOF' # zram swap config - host buffer pentru spike-uri OOM (ex: LXC 110 moltbot) ALGO=zstd SIZE=8192 PRIORITY=100 EOF systemctl restart zramswap.service # enabled persistent la boot swapon --show # /dev/zram0 8G prio 100 ``` Verificare în container — cei 4GB au acum backing real: ``` free -h → Swap: 4.0Gi ``` Vârfurile tranzitorii fac swap-out în loc de OOM-kill instant. --- ## Rămas de făcut (necesită acțiune user) | Item | Detalii | |------|---------| | **Re-auth Tailscale în LXC 110** | Necesită login interactiv din browser (`tailscale up` regenerează URL-ul). Până atunci IP-ul 100.120.119.70 nu răspunde; accesul pe 10.0.20.173 e normal. | | **Bridge WhatsApp deconectat** | `{"connected":false,"qr":null}` pe `127.0.0.1:8098`. Discord + Telegram merg. Probabil necesită re-pairing prin QR. | | **Monitorizare** | De urmărit dacă `MemoryHigh` pe TTS chiar oprește recurența — următorul episod ar trebui să se manifeste ca throttling, nu ca kill. | ## OOM-ul NU e izolat — istoric recurent Verificarea jurnalului complet (nu doar boot-ul curent) arată că OOM-ul din 31 iulie e **al cincilea episod**, nu un accident: ``` Apr 25 08:34:53 echo-core.service: Failed with result 'oom-kill' May 28 14:09:36 echo-core.service: Failed with result 'oom-kill' <- 1.4G memory peak May 28 14:15:44 echo-core.service: Failed with result 'oom-kill' May 28 14:18:13 echo-core.service: Failed with result 'oom-kill' May 28 14:18:13 supertonic-tts.service: Failed with result 'oom-kill' Jul 31 06:26:22 user-1000.slice: killed by the OOM killer -> reboot ``` Pe 28 mai: **4 kill-uri în 9 minute**, `echo-core` luând cu el și `supertonic-tts`. Log-ul de atunci confirmă lipsa swap-ului: `1.4G memory peak, 0B memory swap peak` — fără backing store, kernelul trece direct la kill. ### Cauza structurală: servicii fără limite Cele 7 servicii user systemd (`echo-core`, `echo-taskboard`, `echo-whatsapp-bridge`, `pocket-tts`, `supertonic-tts`, `romfast-website`, `dbus`) rulează **toate fără plafon**: ``` MemoryMax=infinity MemoryHigh=infinity ``` Deci orice serviciu poate consuma singur toți cei 8 GB ai containerului, iar OOM killer-ul alege victime după `oom_score_adj` — de unde procesele mici ucise aiurea (`dbus-daemon`, `sd-pam`) care fac diagnosticul derutant. Stiva TTS e cea mai grea: `pocket-tts` ~945 MB + `supertonic` ~500 MB, în repaus. ### Fix 3 — MemoryHigh pe stiva TTS (aplicat) `MemoryHigh` face **throttling + reclaim** în loc de kill, deci serviciul degradează elegant sub presiune. `MemoryMax` e plasa de siguranță: izolează un eventual kill **în interiorul serviciului**, în loc să lase OOM killer-ul să aleagă victime aleatorii în tot containerul. Drop-in-uri în `~/.config/systemd/user/.service.d/limits.conf` (user `moltbot`): | Serviciu | RSS repaus | MemoryHigh | MemoryMax | |----------|-----------|------------|-----------| | `pocket-tts` | ~945 MB | 1536M | 2G | | `supertonic-tts` | ~500 MB | 1024M | 1536M | ```bash su - moltbot mkdir -p ~/.config/systemd/user/pocket-tts.service.d cat > ~/.config/systemd/user/pocket-tts.service.d/limits.conf <<'EOF' [Service] MemoryHigh=1536M MemoryMax=2G EOF export XDG_RUNTIME_DIR=/run/user/1000 systemctl --user daemon-reload systemctl --user restart pocket-tts supertonic-tts systemctl --user show pocket-tts -p MemoryHigh,MemoryMax,MemoryCurrent # verificare ``` Verificat post-aplicare: ambele `active/running`, porturile 7788 + 7789 deschise, `echo-core` neîntrerupt. Consum după restart: pocket-tts 773M, supertonic 463M. > Restul serviciilor (`echo-core`, `echo-taskboard`, `echo-whatsapp-bridge`, > `romfast-website`) au rămas **fără limite** — TTS-ul e consumatorul dominant. De > reevaluat dacă apar OOM-uri cu altă victimă. ## Prevenție - **zram pe pve1** amortizează spike-urile (aplicat) — dar singur e paliativ: fără limite pe servicii, swap-ul doar întârzie kill-ul. Fixul de fond e `MemoryHigh` pe TTS (aplicat). - **DNS explicit pe LXC 110** elimină dependența de Tailscale (aplicat). - De evaluat același `--nameserver` pentru celelalte LXC-uri de pe pve1. - Alertare pe `NRestarts` la serviciile user systemd ar fi prins crash-loop-ul mai devreme decât raportarea manuală. --- **Legături:** `../../lxc110-moltbot/README.md` · `../../lxc171-claude-agent/README.md` (secțiunea „Memorie & OOM" — incidentul zram pvemini 2026-06-24)