Files
ROMFASTSQL/proxmox/lxc103-dokploy/docs/autopass.md
Marius 4a73d0dd39 docs(lxc103): autopass - env vars noi obligatorii + fix DB readonly (uid non-root)
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>
2026-07-09 14:15:45 +03:00

11 KiB
Raw Blame History

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 stagingautopass-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, branch main

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 (entrypoint web)
  • worker — procesează coada; partajează volumul autopass-data și AUTOPASS_CREDS_KEY
  • autoheal — restartează worker-ul când probe-ul îl marchează unhealthy (proces agățat)

Deploy în Dokploy UI

1. Creare Service

  1. https://dokploy.romfast.roServicesCreate ServiceDocker Compose
  2. 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):

  1. Dokploy → General → copiază Webhook URL (https://dokploy.romfast.ro/api/deploy/compose/<token>)
  2. Gitea → repo → Settings → Webhooks → Add Webhook → Gitea:
    • Target URL: (URL-ul din Dokploy), Method POST, Content Type application/json
    • Branch filter: main, trigger Push Events, Active
    • Test Delivery → trebuie 200
  3. Doar ce e git push-uit pe main declanș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 psapi î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 psRestarting), 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: test
  • AUTOPASS_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 :443 hostHeader autopass.romfast.ro, SNI (SslFlags 1)
  • C:\inetpub\autopass\web.config = catch-all rewrite → http://10.0.20.167/{R:1} (Traefik LXC 103) cu X-Forwarded-Proto/Host + X-Real-IP

Cert SSL — win-acme HTTP-01, auto-renew (la fel ca site-urile 15):

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. Install iis (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 autopassDomainsAdd 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.