# Deploy to the Ubuntu VM (all-in-one) — LAN / HTTP Everything runs on **one Ubuntu VM, one Docker daemon**: Gitea, the container registry, the build, and the ROLAC runtime. So a single Gitea Actions job (the `ubuntu` runner) does the whole pipeline — no cross-machine pull, no Windows-runner quirks. ``` git push main │ ▼ Gitea (on the VM) ── triggers .gitea/workflows/ci-cd-vm.yml │ ▼ ubuntu runner (on the VM, same Docker daemon) dotnet test docker build ./API + ./APP -> :latest + : docker push -> git.golife.love/chrischen/rolac-{api,app} docker compose up -d (TAG=) curl /api/health │ ▼ browser -> http://:8080 │ nginx edge (container, 8080->80) ├── / -> app container (Angular static) └── /api/ -> api container (ASP.NET, :8080) api ──> existing PostgreSQL @ 192.168.68.55:49154 (not containerized) ``` No TLS yet — plain HTTP on port **8080**. Add Let's Encrypt later (see the Azure `deploy/` files) or front it with an existing reverse proxy. --- ## One-time setup — on the VM 1. **Deploy dir + secrets:** ```bash sudo mkdir -p /opt/rolac/nginx/conf.d /opt/rolac/data/api-storage sudo cp /path/to/repo/deploy/vm/.env.example /opt/rolac/.env sudo nano /opt/rolac/.env # real DB user/password + JWT_SECRET + APP_ORIGIN ``` Make sure the user the runner executes as can read/write `/opt/rolac`. 2. **Registry token** — in Gitea: Settings → Applications → new token with `read:package` + `write:package`. Log Docker in once on the VM: ```bash docker login git.golife.love -u ChrisChen # paste the token ``` 3. **Install act_runner on the VM** with the label **`ubuntu`** and access to the host Docker. The runner must be able to run `dotnet`, `docker`, and `docker compose`, and reach `/opt/rolac`: ```bash docker run -d --restart unless-stopped --name rolac-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /opt/rolac:/opt/rolac \ -e GITEA_INSTANCE_URL=https://git.golife.love \ -e GITEA_RUNNER_REGISTRATION_TOKEN= \ -e GITEA_RUNNER_LABELS=ubuntu \ gitea/act_runner:latest ``` > The job calls `dotnet test` and `docker build` directly. If act_runner runs in > a container, that image needs the .NET 8 SDK + docker CLI on PATH. Simplest: > install act_runner as a **native binary** on the VM (it then uses the host's > Docker + an installed .NET SDK). Either way the label must be `ubuntu`. 4. **Gitea repo secrets** (Settings → Actions → Secrets): - `REGISTRY_USER` = `ChrisChen` - `REGISTRY_TOKEN` = the package token from step 2 5. **Enable Actions** for the repo if needed (Settings → Advanced → Actions). --- ## Day-to-day `git push` to `main` → `.gitea/workflows/ci-cd-vm.yml`: **test → build both images → push to registry → sync compose/nginx → `compose up -d` → health check.** Open `http://:8080` and log in. Deploy pins `TAG=`, so the running containers match exactly the commit that was built (the images already exist in the local Docker, so this is instant). --- ## Manual deploy (no runner yet) On the VM, from a checkout of the repo: ```bash docker login git.golife.love -u ChrisChen docker build -t git.golife.love/chrischen/rolac-api:latest ./API docker build -t git.golife.love/chrischen/rolac-app:latest ./APP mkdir -p /opt/rolac/nginx/conf.d /opt/rolac/data/api-storage cp deploy/vm/docker-compose.yml /opt/rolac/docker-compose.yml cp deploy/vm/nginx/conf.d/rolac.conf /opt/rolac/nginx/conf.d/rolac.conf cd /opt/rolac && docker compose up -d curl -fsS http://localhost:8080/api/health ``` --- ## Notes - **First boot runs DB migrations** against `192.168.68.55` automatically (`Program.cs` calls `MigrateAsync()` + seed). The VM must reach that host and the DB user needs DDL rights; back up before the first run. - **Uploaded files** persist under `/opt/rolac/data/api-storage`. - **Same Docker daemon for build + run** means `docker compose up` finds the freshly built `:` images locally; `docker compose pull` is unnecessary here (but harmless if you add it). - To go HTTPS later: switch the edge to ports 80/443 and mount Let's Encrypt certs, or use the Azure `deploy/` files which already include certbot.