# Deploying همکادر / hamkadr.ir CI/CD via the **soroush method**: push to Gitea → Gitea Actions builds (through the Nexus mirror) and the self-hosted runner deploys with Docker Compose. nginx (already on the server) terminates TLS for `hamkadr.ir` and reverse-proxies to the app. ## Architecture & open ports ``` Internet ─443/80─► central nginx (container) ─► http://171.22.25.73:2569 ─► hamkadr_api (container :8080) (nexus/mirror/gitea/meezi…) host-published port │ internal docker net ▼ hamkadr_db (postgres, no host port) ``` Matches the existing soroush pattern: the **containerized** central nginx reaches each app via the **host IP + published port** (`171.22.25.73:`), not localhost. So hamkadr publishes `2569` on the host (like meezi 5080, draletaha 5010…). | Port | Open? | Purpose | |------|-------|---------| | 22 | ✅ (ideally IP-restricted) | SSH | | 80 / 443 | ✅ (already open) | central nginx — serves `hamkadr.ir` too | | 2569 | host-published | app; only nginx proxies to it. Optionally firewall to the nginx host. | | 5432 | ❌ internal docker net only | Postgres — never published | No firewall change needed for 80/443 (nginx already serves git./mirror./meezi). 2569 is published on the host like the other apps. ## Files in this repo | File | Role | |------|------| | `Dockerfile` | multi-stage build, images + NuGet via `mirror.soroushasadi.com` | | `nuget.docker.config` | NuGet → Nexus `nuget-group` | | `docker-compose.yml` | production stack: `api` (host :${HOST_PORT}) + `db` (internal) + named volume | | `docker-compose.dev.yml` | local-dev Postgres only (host 5433) for `dotnet run` | | `.gitea/workflows/ci-cd.yml` | build job + self-hosted deploy (backup → rollback tag → recreate → health-wait) | | `deploy/nginx-hamkadr.ir.conf` | nginx vhost for hamkadr.ir | ## One-time setup ### 1. DNS A records → 171.22.25.73: ``` hamkadr.ir A 171.22.25.73 www.hamkadr.ir A 171.22.25.73 ``` ### 2. Gitea runner Confirm the `act_runner` on this server has the **`self-hosted:host`** label (the deploy job needs it) and its user is in the `docker` group. (Already true if other soroush projects deploy here.) ### 3. ENV_FILE secret Set at `https://git.soroushasadi.com/soroushdes/hamkadr/settings/secrets` → key **`ENV_FILE`**: `docker-compose.yml` substitutes these into the `api`/`db` services (it derives `ConnectionStrings__Default` and `Auth__AdminPhone` for you), so the secret is just: ```dotenv # host port nginx proxies to (must match deploy/nginx-hamkadr.ir.conf) HOST_PORT=2569 # Postgres — generate a strong password: openssl rand -hex 24 POSTGRES_DB=hamkadr POSTGRES_USER=hamkadr POSTGRES_PASSWORD=__CHANGE_ME__ # Platform admin phone (gets the Admin role on login) ADMIN_PHONE=09XXXXXXXXX ``` > **That's the whole secret.** Everything else — the **AI audit layer** *and* the **channel > sources** (Telegram channels, Bale bot token, Divar queries, auto-ingest on/off + interval) — is > configured at runtime in the admin panel (`/Admin/Settings`), stored in the DB. No redeploy to > change them. Defaults: AI off, mode = Manual, all sources off ⇒ nothing publishes without admin > review. > `ASPNETCORE_ENVIRONMENT=Production` is set by the compose file ⇒ only **reference data** > (roles/cities/districts) is seeded — no demo facilities/shifts. ### 4. TLS cert + nginx vhost Your central nginx is a **single monolithic `nginx.conf`** with **manually-placed certs** (no certbot). Match that: 1. Put the hamkadr.ir cert where nginx expects (same convention as your other domains): ``` /etc/ssl/hamkadr/fullchain.pem /etc/ssl/hamkadr/privateKey.pem ``` 2. Paste the two `server { }` blocks from `deploy/nginx-hamkadr.ir.conf` **into the `http { }` block** of your central nginx.conf (next to meezi/draletaha). They proxy to `http://171.22.25.73:2569` and reuse the global `$connection_upgrade` map. 3. Reload: ```bash nginx -t && nginx -s reload # or: docker exec nginx -s reload ``` ### 5. First deploy ```bash git push gitea main # add the gitea remote first if needed ``` Watch `https://git.soroushasadi.com/soroushdes/hamkadr/actions`. The app auto-applies EF migrations on startup and seeds reference data; nginx already proxies hamkadr.ir to it. ## Operations - **Backups:** every deploy runs `pg_dump` → `/opt/hamkadr-backups/hamkadr-.sql` before touching containers. - **Rollback:** the previous image is tagged `mirror.soroushasadi.com/hamkadr/api:rollback` each deploy: ```bash docker stop hamkadr_api && docker rm hamkadr_api API_TAG=rollback docker compose up -d --no-deps api ``` - **Rotate a secret:** edit `ENV_FILE` in Gitea, push any commit to redeploy. - **Logs:** `docker logs -f hamkadr_api` - **Restore a backup:** `cat /opt/hamkadr-backups/.sql | docker exec -i hamkadr_db psql -U hamkadr -d hamkadr` ## Safety (never do these) - ❌ `docker compose down -v` — deletes the database volume. - ❌ bare `docker compose down` / `restart` — would stop other projects on the shared host. The workflow always uses `--no-deps ` and explicit `stop`/`rm`.