Deploy to Synology NAS (Container Manager) — LAN / HTTP
Target: run the ROLAC stack on a Synology NAS, reachable on the LAN at
http://<nas-ip>:8080, with images built & pushed to the local Gitea registry
(git.golife.love, same NAS) and auto-deployed by a Gitea act_runner on push to main.
browser (LAN) -> http://<nas-ip>: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)
Differences vs the Azure plan: no TLS/certbot, edge on 8080 (DSM owns 80/443), reuse the LAN database, deploy via the on-NAS runner (no SSH).
One-time NAS setup
-
Deploy dir + secrets (via SSH or File Station):
mkdir -p /volume1/docker/rolac/nginx/conf.d /volume1/docker/rolac/data/api-storage cp /path/to/repo/deploy/nas/.env.example /volume1/docker/rolac/.env # edit /volume1/docker/rolac/.env -> real DB user/password + JWT_SECRET + APP_ORIGIN -
Registry token — in Gitea: Settings → Applications → new token with
read:package+write:package. Log the NAS Docker in once:docker login git.golife.love -u ChrisChen # paste the token -
Install the act_runner on the NAS (Container Manager → Registry →
gitea/act_runner, ordocker run). It must:- mount the host Docker socket:
-v /var/run/docker.sock:/var/run/docker.sock - mount the deploy dir at the same path:
-v /volume1/docker/rolac:/volume1/docker/rolac - register against Gitea with the label
nas(this is whatruns-on: nastargets).
Get a registration token in Gitea: Site/Repo → Settings → Actions → Runners → "Create new runner". Example:
docker run -d --restart unless-stopped --name rolac-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /volume1/docker/rolac:/volume1/docker/rolac \ -e GITEA_INSTANCE_URL=https://git.golife.love \ -e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \ -e GITEA_RUNNER_LABELS=nas \ gitea/act_runner:latest - mount the host Docker socket:
-
Gitea repo secrets (Settings → Actions → Secrets):
REGISTRY_USER=ChrisChenREGISTRY_TOKEN= the package token from step 2
-
Enable Actions for the repo if not already (Settings → Advanced → Actions).
Day-to-day
git push to main → .gitea/workflows/ci-cd-nas.yml runs:
test → build both images → push to registry → sync compose/nginx → docker compose up -d → health check.
Open http://<nas-ip>:8080 and log in.
Manual deploy (no runner yet)
From a machine with Docker + docker login git.golife.love:
# repo root, build + push (uses deploy/build-push.ps1)
.\deploy\build-push.ps1
Then on the NAS:
cd /volume1/docker/rolac
docker compose up -d
curl -fsS http://localhost:8080/api/health
Notes
- First boot runs DB migrations against
192.168.68.55automatically (Program.cscallsMigrateAsync()+ seed). Make sure the DB user has DDL rights; back up before the first run. - Bind-mount paths: the runner deploys by running compose at
/volume1/docker/rolacon the host (socket-mounted), so./nginx/conf.dand./dataresolve to real NAS paths — that's why the runner mounts that dir at the same path. - Uploaded files persist under
/volume1/docker/rolac/data/api-storage. - To expose beyond the LAN later, put it behind DSM's reverse proxy (Application Portal)
or switch to the Azure
deploy/files with certbot.