Files
plm-lottery/docs/running-the-server.md
T

125 lines
5.6 KiB
Markdown
Raw Normal View History

# Avviare il server
Presuppone che [setup.md](setup.md) sia già stato completato (`.env` pronto,
master key generata). Le migrazioni del database non si applicano a mano: le
esegue il container a ogni avvio, prima di far partire il server.
Il server gira sempre via Docker, in sviluppo e in produzione allo stesso
modo — non esiste un modo supportato per lanciare `uvicorn` direttamente.
Il venv locale (`.venv/`) serve solo per i test, per scrivere le migrazioni
Alembic e per gli script una tantum di generazione chiavi (vedi
[setup.md](setup.md) e la sezione "Commands" di
[CLAUDE.md](../CLAUDE.md#commands)).
## Docker + Caddy (unico workflow supportato)
```bash
mkdir -p data/db data/keys data/logs # una tantum, se non già presenti
docker compose up -d --build
```
- Caddy fa da reverse proxy davanti all'app e gestisce il TLS automaticamente
- App su `https://localhost/` (o sul dominio configurato, vedi sotto)
- Pannello admin su `https://localhost/admin`
- DB, master key cifrata e log persistono in `./data/` sulla root del repo
(bind mount, non volumi Docker opachi) — sopravvivono a stop/rebuild del
container e sono ispezionabili/backup-abili direttamente
### Modalità dev, senza dominio (certificato self-signed)
Non serve fare nulla: lasciando `SITE_ADDRESS` non impostata, Caddy usa
`localhost` di default. Rilevando che non è un hostname pubblico, genera da
solo un certificato dalla sua CA interna — il browser mostrerà un avviso di
sicurezza al primo accesso (normale, accettalo o usa `curl -k`).
### Modalità produzione, con dominio reale
Scrivere il dominio in `.env`, accanto agli altri valori:
```bash
# .env
SITE_ADDRESS=lottery.tuodominio.it
```
e avviare come sempre:
```bash
docker compose up -d --build
```
Docker Compose legge `.env` da solo per sostituire `${SITE_ADDRESS}` in
`docker-compose.yml`, quindi ogni avvio successivo usa lo stesso dominio.
**Non** passarlo solo sulla riga di comando
(`SITE_ADDRESS=… docker compose up -d`): il valore vale per quel comando e
basta, e il primo `docker compose up -d --build` lanciato senza di esso
riporta Caddy a `localhost` con un certificato autofirmato — il sito pubblico
smette di rispondere con un certificato valido. Per controllare:
`grep '^SITE_ADDRESS=' .env`.
Il DNS del dominio deve già puntare all'IP del server, con le porte 80 e 443
raggiungibili da internet. Caddy richiede e rinnova automaticamente un
certificato Let's Encrypt reale — nessuna configurazione aggiuntiva.
### Comandi utili
```bash
tail -f data/logs/app.log # log dell'applicazione (scheduler, Electrum, riconciliatori, errori)
docker compose logs -f app # solo output di avvio del container e di uvicorn (vedi sotto)
docker compose ps # stato dei container
docker compose stop # ferma senza rimuovere i container
docker compose down # ferma e rimuove i container (i dati in ./data/ restano)
```
**Dove sono i log.** I messaggi dell'applicazione — connessione Electrum,
scheduler dei round, riconciliatori, errori delle richieste — sono scritti
**solo** in `./data/logs/app.log` (con rotazione: `app.log.1` … `app.log.5`),
non sull'output del container. `docker compose logs -f app` mostra soltanto
l'output di avvio del container (controllo della master key, migrazioni
Alembic) e ciò che uvicorn scrive per conto suo (avvio, richieste HTTP): per
capire cosa sta facendo la lotteria si legge il file. Dettagli e messaggi da
conoscere in [audit-log.md](audit-log.md#log-applicativo).
> **Nota sul `Caddyfile`**: è montato in sola lettura nel container `caddy`
> (bind mount). Modificarlo non basta a farlo ripartire con la nuova
> configurazione — `docker compose up -d --build` non ricrea `caddy` solo
> perché il *contenuto* di un file montato è cambiato. Dopo una modifica al
> `Caddyfile` serve un passaggio in più:
> ```bash
> docker compose restart caddy
> ```
> (oppure, senza interrompere le connessioni esistenti: `docker compose exec
> caddy caddy reload --config /etc/caddy/Caddyfile`).
### Riavvii e deploy: prima la pausa
Oggi l'arresto del container non è pulito: con una pagina `/` aperta (uno
stream SSE attivo) uvicorn aspetta che lo stream si chiuda e Docker uccide il
processo dopo 10 secondi. Per il codice ogni `docker compose up -d --build`,
`restart` o `down` è quindi un crash: durante `drawing` blocca il round,
durante un invio lascia una transazione `building` da riconciliare.
Prima di **qualunque** riavvio o deploy (nuova versione, modifica di `.env`,
rotazione di un segreto):
1. fare il backup del database;
2. in `/admin` → Parametri → Manutenzione, premere "Interrompi dopo questo
round";
3. aspettare che il round in corso arrivi a `closed` (`GET /rounds/current`
senza più un round attivo) e che "Transazioni pendenti" non abbia righe
`building`;
4. riavviare, controllare in `data/logs/app.log` la riga
`Electrum connected to …`, poi "Riprendi lotteria".
La procedura completa, con i comandi e il perché di ogni passo, è
[OPS-10 in operativita.md](operativita.md#riavvio) ("Riavvio sicuro e deploy").
### ⚠️ Attenzione: riavvii automatici a metà round
`docker-compose.yml` imposta `restart: unless-stopped` sul container dell'app:
se crasha, riparte da solo. Questo però non è ancora sicuro in ogni caso: i
round in `closing` e `paying_out` riprendono da soli al riavvio, ma se il
crash avviene mentre un round è in `drawing`, lo scheduler non lo riprende e
il round resta bloccato (limite noto, vedi
[decisioni-e-limiti.md](decisioni-e-limiti.md); procedura in
[operativita.md](operativita.md)). Non trattare questo setup come
"non supervisionato" finché quel limite non è risolto.