# Dyolink Monorepo: **NestJS** backend (`backend/`), **Next.js** frontend (`frontend/`), **Docker** stack under `infrastructure/`.. Local development: see **`backend/README.md`** and **`frontend/README.md`**. --- ## Deploy on your own server (Docker + Gitea) High level: **build container images → push to a registry → server pulls images and runs Compose**. Optionally **Gitea Actions** automates that on every merge to `main` / `master`. ### 1. One-time server preparation 1. Install **Docker** and **Docker Compose** on the server. 2. Run **Gitea** with the **container registry** enabled (same host/port you use for `docker login`, e.g. `178.131.50.201:3000`). 3. Copy the repo (or deploy only `infrastructure/` + secrets). You need at least: - `infrastructure/docker-compose.registry.yml` - `infrastructure/nginx/` configs referenced by that compose file - `infrastructure/database/init.sql` if used by your Postgres service 4. **Secrets on the server** (never commit real values): - Copy `infrastructure/database.staging.env.example` → **`database.staging.env`** (Postgres user/password/db). - Copy `infrastructure/backend.staging.env.example` → **`backend.staging.env`** (e.g. `DATABASE_URL`, JWT, pointing at the compose Postgres service name). - Put both files in one directory on the server, e.g. `/opt/dyolink/secrets/`. 5. **Registry login from the server** (same credentials you use for `docker push`): ```bash docker login : -u ``` For HTTP registries, Docker may require **`insecure-registries`** on the daemon. ### 2. Manual deploy (build images elsewhere, run on server) On your **dev machine** (after successful local builds): ```powershell $REG = ":" $OWN = "" $TAG = "manual" docker build -t "${REG}/${OWN}/dyolink-backend:${TAG}" -t "${REG}/${OWN}/dyolink-backend:latest" ./backend docker build ` --build-arg NEXT_PUBLIC_API_URL="http://:/api" ` --build-arg NEXT_PUBLIC_APP_URL="http://:" ` --build-arg NEXT_PUBLIC_APP_NAME="Dyolink" ` -t "${REG}/${OWN}/dyolink-frontend:${TAG}" ` -t "${REG}/${OWN}/dyolink-frontend:latest" ` ./frontend docker push "${REG}/${OWN}/dyolink-backend:${TAG}" docker push "${REG}/${OWN}/dyolink-backend:latest" docker push "${REG}/${OWN}/dyolink-frontend:${TAG}" docker push "${REG}/${OWN}/dyolink-frontend:latest" ``` On the **server**, from `infrastructure/`: 1. Create **`deploy.registry.env`** (see `infrastructure/deploy.registry.env.example`): - `REGISTRY_PREFIX=:/` (no `http://`, no trailing slash) - `IMAGE_TAG=latest` or the tag you pushed - `STAGING_HTTP_PORT=` (e.g. `8088` — browser uses `http://:8088`) 2. Set **`DEPLOY_SECRETS_DIR`** to the absolute path of the folder containing `database.staging.env` and `backend.staging.env` (you can export it in the shell or add it to `deploy.registry.env` if your Compose setup expects it). 3. Pull and start: ```bash docker compose -f docker-compose.registry.yml --env-file deploy.registry.env pull backend frontend docker compose -f docker-compose.registry.yml --env-file deploy.registry.env up -d ``` The backend container runs **`prisma migrate deploy`** on startup (via entrypoint) when `NODE_ENV=production`, so schema updates apply after you deploy a new image that includes new migrations. ### 3. Automatic deploy (Gitea Actions) Workflow file: **`.gitea/workflows/registry-build-deploy.yml`**. **Requirements:** - **Gitea Actions** enabled for the repository. - A **self-hosted runner** (with Docker) registered to Gitea — the workflow uses `runs-on: self-hosted`. - **Windows runners:** the workflow uses **PowerShell** (not Bash). Gitea’s runner was failing with `execvpe(/bin/bash) failed` when Bash was routed through WSL without a real `/bin/bash`. If your runner is **Linux**, switch `.gitea/workflows/registry-build-deploy.yml` to `defaults.run.shell: bash` and use Bash syntax instead. - **Repository → Actions → Variables** (examples): - `REGISTRY_HOST` — e.g. `178.131.50.201:3000` - `REGISTRY_OWNER` — image namespace (same as Docker image path after the host), e.g. `admin` - `PUBLIC_BASE_URL` — URL users open in the browser, e.g. `http://178.131.50.201:8088` (no trailing slash) - `DEPLOY_SECRETS_DIR` — **absolute path on the runner machine** to the folder containing `database.staging.env` and `backend.staging.env` - Optional: `STAGING_HTTP_PORT` (defaults to `8088`) - **Repository → Actions → Secrets:** - `REGISTRY_USERNAME` - `REGISTRY_PASSWORD` — access token with package read/write (or equivalent) **Trigger:** push to **`main`** or **`master`**, or run the workflow manually (**workflow_dispatch**). The pipeline clones from your Gitea instance, builds and pushes backend/frontend images, then on the runner runs **`docker compose pull`** and **`up -d`** using `infrastructure/docker-compose.registry.yml`. --- ## Related paths | Path | Role | |------|------| | `backend/Dockerfile` | API image | | `frontend/Dockerfile` | Web image | | `infrastructure/docker-compose.registry.yml` | Pull-only staging stack (registry images + nginx + postgres) | | `infrastructure/deploy.registry.env.example` | Template for `deploy.registry.env` |