Flux de lucru pentru mediu staging autopass: un branch = un environment (main->prod, staging->test), serviciu Dokploy separat autopass-test, domeniu via wildcard *.roa (fara IIS/cert nou), env care opreste trimiterile reale la RAR. Link incrucisat din autopass.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
189 lines
8.1 KiB
Markdown
189 lines
8.1 KiB
Markdown
# 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](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.ro → **Services** → **Create Service** → **Docker 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 |
|
||
|
||
```bash
|
||
# Generare AUTOPASS_CREDS_KEY:
|
||
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||
```
|
||
Fără cheie, compose pică explicit (`:?seteaza AUTOPASS_CREDS_KEY`).
|
||
|
||
### 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:
|
||
|
||
```xml
|
||
<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. (Nu era o problemă) `/` → 303
|
||
După fix, root-ul redirectează `303 → /login` (auth pe sesiune). E comportament normal,
|
||
nu eroare.
|
||
|
||
---
|
||
|
||
## Verificare post-deploy
|
||
|
||
```bash
|
||
# 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 1–5):
|
||
```powershell
|
||
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 `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**.
|