Documentate doua probleme intalnite la deploy: variabile env noi (AUTOPASS_RAR_ENV, AUTOPASS_SESSION_SECRET, AUTOPASS_WORKER_SEND_ENABLED) devenite obligatorii in docker-compose.yml fara actualizare in Dokploy, si crash-loop api/worker cu "readonly database" dupa ce imaginea a trecut la user non-root (uid 10001) fara chown pe volumul SQLite existent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
11 KiB
autopass — Deploy pe Dokploy LXC 103
Descriere
Gateway RAR AUTOPASS (Python / FastAPI) care preia prezentări de service-auto și le declară la RAR AUTOPASS (Legea 142/2023). Deployat pe Dokploy / LXC 103 ca serviciu Docker Compose.
- Domenii:
autopass.romfast.ro(public, site IIS dedicat) +autopass.roa.romfast.ro(prin wildcard) - Staging: branch
staging→autopass-test.roa.romfast.ro— vezi autopass-staging.md - Server: LXC 103 (10.0.20.167)
- Deployment: Dokploy → Docker Compose, provider Custom Git
- Repo:
git@gitea.romfast.ro:romfast/rar-autopass.git, branchmain
Arhitectură
Browser → VM201 IIS (TLS, site roa-apps) → Traefik LXC103 (HTTP :80) → api (uvicorn :8010)
↓
worker + autoheal
↓
SQLite /data/autopass.db
Servicii Docker Compose (docker-compose.yml, un singur image):
api— FastAPI/uvicorn pe:8010, expus prin Traefik (entrypointweb)worker— procesează coada; partajează volumulautopass-datașiAUTOPASS_CREDS_KEYautoheal— restarteazăworker-ul când probe-ul îl marchează unhealthy (proces agățat)
Deploy în Dokploy UI
1. Creare Service
- https://dokploy.romfast.ro → Services → Create Service → Docker Compose
- Name:
autopass, Server: LXC 103 (local)
2. Provider — Custom Git (NU Gitea nativ)
Integrarea nativă Gitea dă "Failed to fetch repositories: Unauthorized" (token OAuth
expirat în Dokploy). Folosește tab-ul </> Git:
- Repository URL:
git@gitea.romfast.ro:romfast/rar-autopass.git - Branch:
main - Compose Path:
./docker-compose.yml - SSH: adaugă deploy key-ul afișat de Dokploy în Gitea → repo → Settings → Deploy Keys
3. Environment (în Dokploy, NU în .env — e gitignored)
| Variabilă | Valoare |
|---|---|
AUTOPASS_CREDS_KEY |
cheie Fernet, partajată api↔worker (vezi mai jos) |
AUTOPASS_REQUIRE_API_KEY |
true pentru prod |
AUTOPASS_RAR_ENV |
prod |
AUTOPASS_SESSION_SECRET |
secret random (vezi generare mai jos), doar pt api |
AUTOPASS_WORKER_SEND_ENABLED |
true pentru prod (worker-ul trimite efectiv la RAR) |
# Generare AUTOPASS_CREDS_KEY:
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Generare AUTOPASS_SESSION_SECRET:
openssl rand -hex 32
Fără cheie, compose pică explicit (:?seteaza AUTOPASS_CREDS_KEY / :?seteaza AUTOPASS_RAR_ENV / :?seteaza AUTOPASS_SESSION_SECRET / :?seteaza AUTOPASS_WORKER_SEND_ENABLED) — compose-ul din repo a adăugat ulterior aceste variabile
ca obligatorii pentru api/worker; dacă lipsesc din Environment-ul Dokploy, deploy-ul
pică la interpolare înainte de build, câte una pe rând (docker compose se oprește la
prima variabilă lipsă, deci fixul se poate face în mai multe runde), cu eroare de tipul:
error while interpolating services.api.environment.AUTOPASS_RAR_ENV: required variable
AUTOPASS_RAR_ENV is missing a value: seteaza AUTOPASS_RAR_ENV (test|prod) in .env
containerele deja rulante nu sunt afectate — doar noul deploy eșuează, prod rămâne pe imaginea veche până se adaugă variabilele lipsă și se redeploy-ează.
4. Domain
Domains → service api, port 8010, domain autopass.roa.romfast.ro.
TLS-ul public se termină la IIS (VM 201), deci în Dokploy e suficient entrypoint web.
5. Autodeploy (deploy automat la commit)
Toggle Autodeploy = ON nu e suficient — trebuie webhook în Gitea (Custom Git nu-l creează automat):
- Dokploy → General → copiază Webhook URL (
https://dokploy.romfast.ro/api/deploy/compose/<token>) - Gitea → repo → Settings → Webhooks → Add Webhook → Gitea:
- Target URL: (URL-ul din Dokploy), Method
POST, Content Typeapplication/json - Branch filter:
main, trigger Push Events, Active - Test Delivery → trebuie
200
- Target URL: (URL-ul din Dokploy), Method
- Doar ce e
git push-uit pemaindeclanșează deploy.
Rutare (de ce NU trebuie regulă IIS per-app)
IIS site roa-apps (VM 201) are binding wildcard *.roa.romfast.ro (80+443) și o regulă
URL Rewrite catch-all care forwardează tot către Traefik:
<rule name="Proxy to LXC 103 Traefik" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://10.0.20.167/{R:1}" />
...
</rule>
ARR are preserveHostHeader=True, deci Host-ul original ajunge la Traefik, care rutează
după Host(...). Un app nou sub *.roa merge automat — nu adaugi nimic în IIS, doar
domeniul în Dokploy.
Probleme întâlnite la primul deploy (și fix-urile)
1. Gitea Unauthorized în Dokploy
Simptom: "Failed to fetch repositories: Unauthorized", dropdown Repository gol. Cauză: token-ul OAuth al integrării native Gitea în Dokploy e expirat/revocat. Fix: folosește provider Custom Git (vezi pasul 2). Alternativ: regenerează OAuth app / PAT în Gitea și reconectează în Dokploy → Settings → Git.
2. 404 la https://autopass.roa.romfast.ro/ — api în crash-loop
Simptom: site-ul răspunde 404 (nu 502). docker ps → api în Restarting (1),
worker + autoheal healthy.
Cauză: ModuleNotFoundError: No module named 'itsdangerous'. SessionMiddleware
(app/main.py) îl cere, dar lipsea din requirements.txt — era doar instalat local în
dev, nu tras tranzitiv în imaginea Docker. Worker-ul nu importă SessionMiddleware,
de-aia el era healthy.
Fix: adăugat itsdangerous==2.2.0 în requirements.txt, push → autodeploy a
reconstruit imaginea (commit 412102b).
404 vs 502: 404 = niciun backend sănătos / niciun router care să răspundă; 502 = portul din Traefik ≠ portul containerului. Aici api nu pornea deloc → 404.
3. Deploy eșuat la interpolare — variabile noi obligatorii lipsă din Dokploy
Simptom: deploy-ul pică înainte de build, cu error while interpolating services.<serviciu>.environment.<VAR>: required variable <VAR> is missing a value.
Cauză: un commit ulterior în docker-compose.yml a adăugat AUTOPASS_RAR_ENV,
AUTOPASS_SESSION_SECRET (api) și AUTOPASS_WORKER_SEND_ENABLED (worker) ca variabile
${VAR:?...} obligatorii, dar Environment-ul din Dokploy pentru serviciul autopass nu
fusese actualizat. Docker compose se oprește la prima variabilă lipsă, deci fixul
poate ieși în mai multe runde (adaugi una, redeploy, apare următoarea).
Fix: adaugă în Dokploy → service autopass → Environment toate cele 3 (vezi tabelul
de mai sus), apoi redeploy.
4. 404 la https://autopass.romfast.ro/ — api + worker crash-loop, DB readonly
Simptom: după fixul de la #3, deploy-ul trece de build, dar api și worker intră în
crash-loop (docker ps → Restarting), site-ul răspunde 404. Loguri:
sqlite3.OperationalError: attempt to write a readonly database.
Cauză: imaginea nouă rulează containerele ca user non-root app (uid 10001,
docker inspect --format '{{.Config.User}}' → app), dar volumul Docker
autopass-data (cu autopass.db) era deținut de root:root din deploy-urile vechi
(când containerul rula ca root) → userul app nu poate scrie nici fișierul, nici WAL-ul
din directorul volumului.
Fix:
ssh root@10.0.20.201 "pct exec 103 -- docker volume inspect autopass-roaautopass-jqqw1l_autopass-data --format '{{.Mountpoint}}'"
# chown pe mountpoint-ul returnat, la uid/gid-ul userului din imagine:
ssh root@10.0.20.201 "pct exec 103 -- chown -R 10001:10001 /var/lib/docker/volumes/autopass-roaautopass-jqqw1l_autopass-data/_data"
# apoi restart:
ssh root@10.0.20.201 "pct exec 103 -- sh -lc 'cd /etc/dokploy/compose/autopass-roaautopass-jqqw1l/code && docker compose -p autopass-roaautopass-jqqw1l -f ./docker-compose.yml restart api worker'"
Fără pierdere de date — doar schimbă proprietarul fișierului SQLite existent. Dacă
imaginea schimbă din nou uid-ul userului non-root, verifică din nou cu docker run --rm <image-api> id app înainte de chown.
5. (Nu era o problemă) / → 303
După fix, root-ul redirectează 303 → /login (auth pe sesiune). E comportament normal,
nu eroare.
Verificare post-deploy
# Stare containere
ssh root@10.0.20.201 "pct exec 103 -- docker ps --format '{{.Names}} -> {{.Status}}' | grep autopass"
# Așteptat: api Up (healthy), worker Up (healthy), autoheal Up (healthy)
# API direct în Traefik (host header), pe LXC 103
ssh root@10.0.20.201 'pct exec 103 -- sh -lc "curl -s -o /dev/null -w \"%{http_code}\n\" -H \"Host: autopass.roa.romfast.ro\" http://localhost/healthz"'
# Așteptat: 200
# Lanț complet de pe VM 201 (loopback, TLS real)
# autopass.roa.romfast.ro -> HTTP 303 (redirect /login) = OK
# Logs api dacă pică
ssh root@10.0.20.201 "pct exec 103 -- docker logs \$(ssh ... ) --tail 40"
Atenție: deploy de TEST, nu producție
docker-compose.yml are hardcodat:
AUTOPASS_RAR_ENV: testAUTOPASS_WORKER_SEND_ENABLED: "false"— worker-ul NU trimite efectiv la RAR.
Pentru producție (trimiteri reale către RAR, Legea 142/2023) acestea trebuie schimbate explicit — preferabil prin Environment în Dokploy, nu hardcodat în compose.
DNS
autopass.romfast.ro A 188.26.14.103
autopass.roa.romfast.ro A 188.26.14.103
autopass.roa… e acoperit de wildcard *.roa.romfast.ro. autopass.romfast.ro e
single-name → are site IIS + cert propriu (vezi mai jos).
Domeniu public autopass.romfast.ro (site IIS dedicat)
Spre deosebire de *.roa, domeniul public single-name are nevoie de site IIS propriu
pe VM 201 (model identic cu roa-qr — pattern din setup-new-iis-sites.ps1).
IIS (VM 201, 10.0.20.122) — Site ID 7, nume autopass:
- HTTP
:80+ HTTPS:443hostHeaderautopass.romfast.ro, SNI (SslFlags 1) C:\inetpub\autopass\web.config= catch-all rewrite →http://10.0.20.167/{R:1}(Traefik LXC 103) cuX-Forwarded-Proto/Host+X-Real-IP
Cert SSL — win-acme HTTP-01, auto-renew (la fel ca site-urile 1–5):
C:\Tools\win-acme\wacs.exe --source iis --siteid 7 --host autopass.romfast.ro `
--validationmode http-01 --validation selfhosting --installation iis `
--store certificatestore --accepttos --emailaddress admin@romfast.ro
- Validation
selfhosting(c7d5e050) — ascultă pe http.sys, nu e blocat de catch-all-ul din web.config. Installiis(ea6a5be3) → re-leagă automat binding-ul SNI la renew. - Renewal:
[IIS] autopass, autopass.romfast.ro, Scheduled Task "win-acme renew", next ~2026-08-23. - Monitorizat în
monitor-ssl-certificates.sh(Site ID 7) ca safety-net.
Pas necesar în Dokploy (Traefik rutează după Host → trebuie domeniul adăugat explicit):
Dokploy → service
autopass→ Domains → Add Domain
- Host:
autopass.romfast.ro, Service:api, Container Port:8010, Path:/- HTTPS: OFF (entrypoint
web) — TLS-ul public se termină la IIS; Certificate: None Save → Traefik hot-reload. Înainte de pas:https://autopass.romfast.ro/→ 404 (Traefik n-are router pe acest Host). După pas: 200.