# Dyolink — Staging deploy (Gitea + Windows) Automatic staging on a **self-hosted Gitea** machine: merge (or push) to **`master`** → build Docker images → push to Gitea Container Registry → deploy on the same host. **Example:** Gitea at `http://178.131.50.201:3000`, staging app at `http://178.131.50.201:8088`. Production (`nudentic.ir` on Linux, tag-based releases) is documented in [`DEPLOY.md`](DEPLOY.md). --- ## Architecture ``` Push / merge to master ↓ Gitea Actions (self-hosted act_runner on Windows) ↓ Build backend + frontend → push to Gitea registry ↓ docker compose pull + up -d (docker-compose.registry.yml) ↓ http://:8088 → nginx → frontend / backend → postgres ``` | Service | Image source | |----------|---------------------------------------------------| | postgres | `postgres:15-alpine` (pulled from Docker Hub) | | backend | `//dyolink-backend:` | | frontend | `//dyolink-frontend:` | | nginx | `nginx:alpine` | Frontend public URLs are **baked in at build time** via `PUBLIC_BASE_URL`. --- ## Triggers | Event | Staging deploy? | |-------|-----------------| | Push to `master` | Yes | | PR merged into `master` | Yes (merge = push to `master`) | | Push to other branches only | No | | Git tag (e.g. `v1.0.0`) | No — reserved for production later | | Manual | Gitea → Actions → **Registry — build, push, deploy** → Run workflow | Workflow file: [`.gitea/workflows/registry-build-deploy.yml`](../.gitea/workflows/registry-build-deploy.yml) --- ## One-time setup (Windows host) ### 1. Docker Desktop - Install and keep **Docker Desktop running** during builds/deploys. - **Settings → Docker Engine** — allow HTTP registry: ```json { "insecure-registries": ["178.131.50.201:3000", "127.0.0.1:3000"] } ``` Apply & restart Docker. ### 2. Gitea Actions runner Download [act_runner](https://gitea.com/gitea/act_runner/releases) → e.g. `C:\gitea-runner\act_runner.exe`. Register (use **localhost** when Gitea runs on the same PC — public IP often fails locally): ```powershell cd C:\gitea-runner .\act_runner.exe register ` --instance "http://127.0.0.1:3000" ` --token "" ` --name "windows-staging" ` --labels "self-hosted,windows" ``` Start (leave running, or install as a Windows service later): ```powershell .\act_runner.exe daemon ``` Gitea → repo → **Settings → Actions → Runners** should show **Online**. **Requires:** `git` on PATH (for workflow checkout step). ### 3. Secret env files (not in git) ```powershell New-Item -ItemType Directory -Force -Path "C:\dyolink\secrets" ``` Copy examples and edit: - `infrastructure/database.staging.env.example` → `C:\dyolink\secrets\database.staging.env` - `infrastructure/backend.staging.env.example` → `C:\dyolink\secrets\backend.staging.env` Rules: - `DATABASE_URL` password must match `POSTGRES_PASSWORD`. - `FRONTEND_URL` must match `PUBLIC_BASE_URL` (e.g. `http://178.131.50.201:8088`). - Replace JWT secrets with long random values (not `CHANGE_ME`). ### 4. Gitea repository Variables **Settings → Actions → Variables** | Name | Example | Notes | |------|---------|--------| | `REGISTRY_HOST` | `178.131.50.201:3000` | No `http://` | | `REGISTRY_OWNER` | `admin` | Gitea user/org owning packages | | `PUBLIC_BASE_URL` | `http://178.131.50.201:8088` | No trailing `/` | | `DEPLOY_SECRETS_DIR` | `C:/dyolink/secrets` | Forward slashes OK on Windows | | `CLONE_HOST` | `127.0.0.1:3000` | When runner and Gitea are same machine | | `STAGING_HTTP_PORT` | `8088` | Optional (8088 is default) | **Naming note:** Gitea rejects variable names starting with `GITEA_` or `GITHUB_`. Use `CLONE_HOST`, not `GITEA_CLONE_URL`. ### 5. Gitea repository Secrets **Settings → Actions → Secrets** | Name | Value | |------|--------| | `REGISTRY_USERNAME` | Gitea username | | `REGISTRY_PASSWORD` | Gitea access token with **package read/write** | Create token: profile → **Settings → Applications → Generate New Token**. ### 6. Firewall (once) ```powershell New-NetFirewallRule -DisplayName "Dyolink Staging 8088" -Direction Inbound -Protocol TCP -LocalPort 8088 -Action Allow ``` --- ## Test the pipeline ### Before first run - [ ] Docker Desktop running - [ ] `act_runner.exe daemon` running - [ ] All Variables + Secrets set (including `CLONE_HOST`) - [ ] Secret env files exist under `DEPLOY_SECRETS_DIR` - [ ] Workflow enabled on `master` (see repo) ### Option A — Manual workflow (safest first test) 1. Gitea → repo → **Actions** 2. **Registry — build, push, deploy** → **Run workflow** → branch `master` 3. Watch jobs: **build-and-push** → **deploy** (first run ~15–30 min) ### Option B — Push to master ```bash git push origin master ``` Or merge a PR into `master` — same result. ### Verify success **On Windows (PowerShell):** ```powershell docker ps ``` Expect: `dyolink_nginx_staging`, `dyolink_backend_staging`, `dyolink_frontend_staging`, `dyolink_postgres_staging`. **From browser or another machine:** ```text http://178.131.50.201:8088 ``` **Health check:** ```powershell curl http://178.131.50.201:8088/api/health ``` Expected: `{"status":"ok",...}` **Gitea packages:** profile/org → **Packages** — should list `dyolink-backend` and `dyolink-frontend` after first build. --- ## Manual deploy (without CI) Useful when debugging registry/compose without re-running the full workflow. On the Windows host, from repo `infrastructure/`: 1. Create `deploy.registry.env` from [`deploy.registry.env.example`](deploy.registry.env.example) 2. Set `REGISTRY_PREFIX`, `IMAGE_TAG`, `STAGING_HTTP_PORT`, `DEPLOY_SECRETS_DIR` 3. `docker login 178.131.50.201:3000 -u ` 4. `docker compose -f docker-compose.registry.yml --env-file deploy.registry.env pull backend frontend` 5. `docker compose -f docker-compose.registry.yml --env-file deploy.registry.env up -d` --- ## Troubleshooting | Symptom | Fix | |---------|-----| | Runner can't register on public IP | Use `http://127.0.0.1:3000` for `--instance` | | Variable name rejected in Gitea | No `GITEA_*` / `GITHUB_*` prefixes; use `CLONE_HOST` | | `server gave HTTP response to HTTPS client` | Add registry to Docker **insecure-registries**, restart Docker | | `Missing database.staging.env` | Check `DEPLOY_SECRETS_DIR` path and file names | | `docker login` denied | Token needs package permissions; check username/secret | | Git clone fails in workflow | Set `CLONE_HOST=127.0.0.1:3000` | | Port 8088 unreachable | Windows firewall rule; confirm nginx container is up | | Backend restart loop | JWT secrets still placeholder; fix `backend.staging.env` | | Backend DB auth error | `DATABASE_URL` password ≠ `POSTGRES_PASSWORD` | **Logs:** ```powershell docker logs dyolink_backend_staging --tail 50 docker logs dyolink_nginx_staging --tail 50 docker logs dyolink_frontend_staging --tail 50 ``` --- ## File reference | Path | Role | |------|------| | `.gitea/workflows/registry-build-deploy.yml` | CI: build, push, deploy | | `infrastructure/docker-compose.registry.yml` | Staging stack (pull-only images) | | `infrastructure/deploy.registry.env.example` | Manual deploy env template | | `infrastructure/database.staging.env.example` | Postgres secrets template | | `infrastructure/backend.staging.env.example` | API secrets template | | `infrastructure/nginx/http-only.conf` | HTTP reverse proxy for staging | --- ## Production (later) | Environment | Trigger | Host | |-------------|---------|------| | Staging | Push/merge to `master` | Windows + Gitea | | Production | Git tag `v*.*.*` | Linux + `nudentic.ir` | Production flow will use Docker Hub (or registry) + [`DEPLOY.md`](DEPLOY.md) — not yet wired to the same workflow.