# 2026-07-09 — Incident infra: "BOOK LIVE conto offline" = cert Traefik di default (non un problema del conto) **Tipo:** incident operativo (infra VPS), non ricerca. Nessun edge, nessun cambio a strategie/pesi/config di trading. Documentato qui perché ha **bloccato la lettura del conto del book live** e ha prodotto l'alert Telegram `⚠️ BOOK LIVE — conto offline`. ## Sintomo Alert dal `cron_book` orario (`scripts/live/book_execute.py --execute`): ``` ⚠️ BOOK LIVE — conto offline nota: salto l'esecuzione, non opero a cieco ``` Nel log (`logs/cron_book.log`) le run recenti mostravano `conto non leggibile (offline) -> stop, non eseguo a cieco`. 10 run offline su 382 totali → **regressione recente**, non uno stato storico. ## Diagnosi (catena completa) Il book legge il conto Deribit mainnet in sola lettura via **Cerbero MCP** (`DeribitRead`, `src/live/deribit.py` → `https://cerbero-mcp.tielogic.xyz`). `book_report` marca `online=False` quando `DeribitRead.mark_price(BTC)` lancia. Riproduzione diretta: ``` mark_price BTC: FAIL -> SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate ``` Il proxy presentava il **cert self-signed di default di Traefik** (`CN = TRAEFIK DEFAULT CERT`, `notBefore Jul 9 19:55 2026`) al posto del vero Let's Encrypt. `curl -k` → HTTP 401 (backend `cerbero-mcp` healthy, routing OK): **solo la presentazione del cert TLS era rotta**. `requests` verifica il cert → fallisce → `online=False` → il book salta l'esecuzione (comportamento di sicurezza **corretto**: non opera a cieco). **Causa a monte** (log di avvio Traefik, 11:37:16Z, container `traefik-traefik-1`): ``` ERR The ACME resolve is skipped from the resolvers list error="unable to get ACME account: permissions 660 for /acme.json are too open, please use 600" resolver=mytlschallenge → (a cascata) Router uses a nonexistent certificate resolver certificateResolver=mytlschallenge routerName=cerbero-mcp@docker [+ ~14 altri router: git, vault, portfolio, budget, cerbero-bite, ...] ``` Sequenza: 1. Immagine `traefik:latest` + **Watchtower** (`com.centurylinklabs.watchtower.enable=true`) → auto-upgrade a **Traefik 3.7.7** con restart alle 11:37 di oggi. 2. Traefik 3.x **rifiuta** `acme.json` con permessi più larghi di `600`; il file era `660` (`-rw-rw---- root:adriano`) → **resolver `mytlschallenge` scartato**. 3. Tutti i ~15 router che lo referenziano → "nonexistent certificate resolver" → Traefik serve il **cert di default self-signed** a ogni host HTTPS del VPS (non solo cerbero-mcp). 4. I cert veri erano **già dentro `acme.json`** (14 domini, incl. `cerbero-mcp.tielogic.xyz`) → nessuna ri-emissione necessaria, **zero rischio rate-limit** Let's Encrypt. ## Impatto - **VPS-wide:** ogni servizio HTTPS dietro Traefik serviva un cert invalido (warning browser, fallimento di ogni client che verifica il TLS). Non solo il trading. - **Trading:** **nessun trade perso.** Target del book **flat** (TP01/SKH01 risk-off) + conto reale ~$598 (non finanziato al livello nominale): anche online il book avrebbe fatto HOLD. Il doppio gate di sicurezza ha lavorato come previsto. ## Fix **Immediato** (eseguito dall'utente): ```bash sudo chmod 600 /opt/docker/traefik/acme.json docker restart traefik-traefik-1 ``` Il resolver ricarica i cert già presenti in `acme.json` e li ripresenta subito. **Durevole** (pin dell'immagine, `/opt/docker/traefik/docker-compose.yml`): ```yaml - image: "traefik" # = traefik:latest → Watchtower salta ai major (causa dell'incident) + image: "traefik:3.7" # Watchtower resta su 3.7.x: patch sì, salto a 3.8+ breaking no ``` Applicato con `docker compose up -d` (container ricreato su `traefik:3.7`, 20:05:05Z). ## Verifica (end-to-end, post-fix) | Check | Risultato | |---|---| | `acme.json` perms | `600` | | Cert `cerbero-mcp.tielogic.xyz` | issuer **Let's Encrypt** (fino 2026-09-27) | | Traefik log | nessun `ACME resolve is skipped` / `too open` | | Container image | `traefik:3.7` (running) | | `DeribitRead.mark_price` | BTC 63.193 / ETH 1.746 | | `book_report.online` | **True** · `eq_basis=mainnet USDC` · `real_equity=$598.06` · `pos_error=None` | ## Lezioni - **`traefik:latest` + Watchtower = auto-upgrade non deterministico.** Un bump di major (qui il giro di vite sui permessi di `acme.json`) diventa un'interruzione TLS di tutto il VPS senza intervento umano. Pinnare la minor (`3.7`) rende i restart prevedibili pur ricevendo le patch. - **Traefik 3.x pretende `acme.json` a `600`** (non solo warning: **scarta il resolver**). Se il file è group/other-readable, tutti i router cadono sul cert di default. - **Il gate `online` del book ha fatto il suo lavoro:** un problema *infra di lettura* non ha prodotto ordini a cieco. L'alert "conto offline" va letto prima come possibile problema di **connettività/cert al Cerbero MCP**, non del conto Deribit. - **Runbook rapido** per "BOOK LIVE conto offline": 1. `python -c "from src.live.deribit import DeribitRead; DeribitRead().mark_price('BTC-PERPETUAL')"` → se `SSLError`/`CERTIFICATE_VERIFY_FAILED` è il cert del proxy, non il conto. 2. `openssl s_client -connect cerbero-mcp.tielogic.xyz:443 -servername cerbero-mcp.tielogic.xyz | openssl x509 -noout -issuer` → se `TRAEFIK DEFAULT CERT`, Traefik non serve il cert reale. 3. `docker logs traefik-traefik-1 | grep -iE "ACME resolve is skipped|too open|nonexistent"` → conferma resolver scartato; controlla `stat -c %a /opt/docker/traefik/acme.json` (deve essere `600`). Nessun file di trading toccato; `config/live.json`, sleeve e pesi **invariati**.