## Registry authentication (required — image is private)
The image is published as a **private** package on the Gitea Container Registry, so the Unraid host must authenticate before it can pull it. Do this once via the Unraid terminal (or SSH):
```bash
docker login registry.alwisp.com -u <gitea-user>
# password: a Gitea access token with at least read:package scope
```
Credentials are stored in `/root/.docker/config.json` and persist across container recreations (but not necessarily across a full Unraid reboot if `/root` is on tmpfs — re-run if pulls start failing with `unauthorized`). Alternatively, make the package public in Gitea (Packages → custom-gitea-runner → Settings) to allow unauthenticated pulls.
3. Check logs — look for `[BOOTSTRAP] Registration complete` or `[START] Starting act_runner daemon`.
4. In Gitea admin panel, verify the runner appears under **Admin → Runners**.
5. Trigger a test workflow and confirm job pickup.
---
## Update workflow
1. Pull the new image tag from the registry.
2. In Unraid, update the Repository field to the new pinned tag.
3. Stop → Start the container (Unraid recreates from the new image).
4. Confirm registration still valid in Gitea admin panel.
5. Run a smoke workflow.
---
## Rollback workflow
1. Stop the container.
2. Change the Repository field back to the prior known-good tag.
3. Start the container.
4. Verify registration and smoke workflow.
---
## Notes on Docker socket
Mounting `/var/run/docker.sock` gives the runner access to the host Docker daemon. This is intentional for build/push workflows. Understand this means jobs running on this runner can interact with all containers on the Unraid host. For a self-owned, trusted environment this is acceptable. Future hardening options are documented in `docs/architecture.md`.
`docker build`/`docker push` steps need the bundled Docker CLI and the mounted socket, which only exist in the runner container itself — not inside the `ubuntu-latest` job container (a plain `node` image). Run Docker-centric jobs with `runs-on: host`. Use `ubuntu-latest:docker://…` for jobs that should run in a clean throwaway container. Registering with both labels (`ubuntu-latest:…,host:host`) covers both patterns. This was validated end-to-end against `git.alwisp.com` (see `forgerunner.src/ROADMAP.md` Phase 3).