9.1 KiB
Gitea Actions: quick notes 🔧
What this adds
.gitea/workflows/ci.yml— runs backend Maven tests and builds the frontend on everypush.
Requirements (quick checklist)
- Enable Actions for this repository: Repository Settings → Actions → Enable Repository Actions.
- Runner (act_runner): you must register at least one runner so jobs can execute.
- Prefer running the runner on a separate machine from the Gitea server.
- You can use the
gitea/act_runnerdocker image or the binaries from Gitea downloads.
Example runner registration (local machine)
- On your host, download or pull the runner image:
docker pull gitea/act_runner:latest. - Start a container for registration only (refer to docs for token and instance):
- Get a token from Gitea UI: Settings → Actions → Runners → Generate token (repo/org/instance level).
- Run the register command (example using container; adjust instance and token):
docker run --rm -it -v $PWD:/data gitea/act_runner register --instance https://your.gitea.host --token <TOKEN>
- Start the runner daemon (on the machine where you registered):
./act_runner daemon # or use the docker image as a long-lived container after registration
Secrets & env
- If tests or builds need credentials, add them to Settings → Secrets at repo/org/instance level and reference via
${{ secrets.MY_SECRET }}.
Notes & tips
- The workflow uses
actions/setup-javaandactions/setup-nodewhich fetch from public actions. If your runner has restricted network access, adjust steps to install local toolchains instead. - If you want to run integration tests or deploy artifacts, tell me which target host or container you'll use and I can add deploy steps.
Deploying the runner to all workers (recommended for docker-executor)
If you want the runner to run on every worker node, use the provided gitea-act-runner-stack.yml which runs the service in mode: global with a placement constraint for workers:
deploy:
mode: global
placement:
constraints:
- node.role == worker
Notes:
- This will start one runner instance on each worker node. If you need fewer runners, switch to
mode: replicatedand usereplicaswith a node label constraint (e.g.,node.labels.runner == true). - Mounting
/var/run/docker.sockgives the runner the ability to run job containers (docker-executor) but is a security-sensitive choice — only run this on trusted worker nodes.
Quick deploy
# from a manager node
docker stack deploy -c gitea-act-runner-stack.yml act-runner
Optional: label nodes instead of using node.role
If you prefer to run on a subset of workers, add a label to desired nodes and update the placement.constraints:
docker node update --label-add runner=true <node-id-or-hostname>
Then use:
placement:
constraints:
- node.labels.runner == true
Registration examples & troubleshooting 🔍
If you see errors like instance address is empty, it means the runner registration command wasn't given an instance URL (via --instance or GITEA_INSTANCE_URL). Use one of these approaches depending on your environment.
- One-shot CLI (internal Swarm network)
docker run --rm -it --network gitea -v act_runner-data:/data gitea/act_runner register \
--instance http://gitea_server:3000 --token <TOKEN> --no-interactive --name swarm-runner
Use the internal service name (gitea_server:3000) when registering from inside the Swarm gitea network.
- One-shot (public/Traefik URL)
docker run --rm -it -v act_runner-data:/data gitea/act_runner register \
--instance https://git.mariuszpacek.pl --token <TOKEN> --no-interactive --name swarm-runner
If you use an HTTPS URL, ensure the container trusts the cert (or use the internal HTTP address if available).
- Auto-register & run with env vars (recommended for simple Docker usage) This will register (if needed) and start the runner in one step:
docker run -d --name gitea-runner \
-v act_runner-data:/data -v /var/run/docker.sock:/var/run/docker.sock \
-e GITEA_INSTANCE_URL=https://git.mariuszpacek.pl \
-e GITEA_RUNNER_REGISTRATION_TOKEN=<TOKEN> \
-e GITEA_RUNNER_NAME=swarm-runner \
gitea/act_runner:latest
- Portainer notes
- For a temporary registration container, set image
gitea/act_runner:latest, Command to:register --instance http://gitea_server:3000 --token <TOKEN> --no-interactive - Or set environment variables
GITEA_INSTANCE_URLandGITEA_RUNNER_REGISTRATION_TOKENand start the container (detached) to auto-register.
- Debugging checks
- Test reachability from the registrator container:
docker run --rm --network gitea curlimages/curl curl -sS http://gitea_server:3000/api/v1/version - Verify
.runnerwritten to the volume:docker run --rm -v act_runner-data:/data alpine sh -c "ls -la /data && cat /data/.runner" - Check logs of the register container / service for precise errors.
If the error persists, paste the exact register command you ran and its container logs and I'll inspect them.
Portainer: secure register + deploy (recommended)
Use a one-shot registration stack (deploy it, wait for logs, then remove it) and then deploy the long-running daemon stack that uses a Docker secret for the registration token.
-
Create a secret in Portainer (or via CLI):
- Portainer: Secrets → Add secret → name:
registration_token→ value:<your_token> - CLI:
echo "<your_token>" | docker secret create registration_token -
- Portainer: Secrets → Add secret → name:
-
Register (one-shot) — Stack:
.gitea/act-runner-register-stack.yml- Deploy in Portainer → set stack variables:
INSTANCE_URL=http://gitea_server:3000(orhttps://git.mariuszpacek.pl)REGISTRATION_TOKEN= your token (or use a temporary secret and modify command to read it)
- Check service logs for success, then remove this stack.
- Deploy in Portainer → set stack variables:
-
Deploy daemon (global on workers) — Stack:
.gitea/act-runner-deploy-stack.ymlorgitea-stack-secured.yml- Ensure secret
registration_tokenexists (see step 1). - Deploy the secure stack (
gitea-stack-secured.yml) which references theregistration_tokensecret and applies Traefik TCP IP whitelist for SSH. - Important: the
act_runnerservice setsGITEA_RUNNER_LABELS=swarm-runner,self-hostedso runners register with theswarm-runnerlabel used by workflows. If you already had runners registered, redeploying the stack should update labels; if labels don't appear, re-register the runner (see steps below). - Deploy stack via Portainer and set
INSTANCE_URLandRUNNER_NAMEas environment variables in Portainer if needed. - Runner will start as a global service on workers and read the token from
/run/secrets/registration_token(no token stored in repo).
- Ensure secret
If labels do not update after redeploy
- Check current runner labels in Gitea UI: Settings → Actions → Runners. If
swarm-runneris missing, re-register the runner to apply labels:- One-shot register stack (Portainer stack or docker run) with
--labels "swarm-runner,self-hosted"or setGITEA_RUNNER_LABELSbefore registration.
- One-shot register stack (Portainer stack or docker run) with
- Alternatively, remove the existing
.runnerfile from theact_runner-datavolume and restart the service so it re-registers using the environment labels:docker run --rm -v act_runner-data:/data alpine sh -c "rm -f /data/.runner && echo removed" # then redeploy stack docker stack deploy -c gitea-stack-secured.yml gitea - After re-registration, confirm labels in Gitea UI and re-run a workflow to validate jobs are picked up.
Notes:
- Do not commit tokens to the repo. Use Docker secrets or Portainer's secret store.
- If you prefer a quick test, the register stack accepts
REGISTRATION_TOKENas an env var (less secure). After successful registration, remove the env token and rely on the Docker secret for the daemon stack.
Locking down SSH access via Traefik (recommended)
The provided gitea-stack-secured.yml deploys a TCP middleware ssh-ipwhitelist and assigns it to the SSH router for Gitea. It restricts which source IP ranges can reach the SSH service exposed through Traefik (this prevents most unsolicited SSH attempts from the Internet).
If you want to restrict only to your internal network and known IPs, ensure the following CIDRs are present in the stack file's labels (adjust as needed): 10.0.1.0/24, 192.168.0.0/24, and your public IP like 83.26.248.249/32.
You can edit the ssh-ipwhitelist ranges directly in gitea-stack-secured.yml under the gitea_server deploy.labels section:
- "traefik.tcp.middlewares.ssh-ipwhitelist.tcp.ipwhitelist.sourcerange=83.26.248.249/32,10.0.1.0/24,172.18.0.0/16,192.168.0.0/24"
After changing the ranges, redeploy the stack (Portainer: Update Stack → Deploy / CLI: docker stack deploy -c gitea-stack-secured.yml gitea).
If you prefer to fully disable SSH through Traefik, remove the Traefik TCP labels from the Gitea service and instead use direct host-level rules (firewall) to allow only specific hosts to connect.