--- title: "Gitea Actions Runner: Boot Race Condition Fix" domain: troubleshooting category: general tags: [gitea, systemd, boot, dns, ci-cd] status: published created: 2026-04-02 updated: 2026-04-02 --- # Gitea Actions Runner: Boot Race Condition Fix If your `gitea-runner` (act_runner) service fails to start on boot — crash-looping and eventually hitting systemd's restart rate limit — the service is likely starting before DNS is available. ## Symptoms - `gitea-runner.service` enters a crash loop on boot - `journalctl -u gitea-runner` shows connection/DNS errors on startup: ``` dial tcp: lookup git.example.com: no such host ``` or similar resolution failures - Service eventually stops retrying (systemd restart rate limit reached) - `systemctl status gitea-runner` shows `(Result: start-limit-hit)` after reboot - Service works fine if started manually after boot completes ## Why It Happens `After=network.target` only guarantees that the network **interfaces are configured** — not that DNS resolution is functional. systemd-resolved (or your local resolver) starts slightly later. `act_runner` tries to connect to the Gitea instance by hostname on startup, the DNS lookup fails, and the process exits. With the default `Restart=always` and no `RestartSec`, systemd restarts the service immediately. After 5 rapid failures within the default burst window (10 attempts in 2 minutes), systemd hits the rate limit and stops restarting. ## Fix ### 1. Update the Service File Edit `/etc/systemd/system/gitea-runner.service`: ```ini [Unit] Description=Gitea Actions Runner After=network-online.target Wants=network-online.target [Service] User=deploy WorkingDirectory=/opt/gitea-runner ExecStart=/opt/gitea-runner/act_runner daemon Restart=always RestartSec=10 [Install] WantedBy=multi-user.target ``` Key changes: - `After=network-online.target` + `Wants=network-online.target` — waits for full network stack including DNS - `RestartSec=10` — adds a 10-second delay between restart attempts, preventing rapid failure bursts from hitting the rate limit ### 2. Add a Local /etc/hosts Entry (Optional but Recommended) If your Gitea instance is on the same local network or reachable via Tailscale, add an entry to `/etc/hosts` so act_runner can resolve it without depending on external DNS: ``` 127.0.0.1 git.example.com ``` Replace `git.example.com` with your Gitea hostname and the IP with the correct local address. This makes resolution instantaneous and eliminates the DNS dependency entirely for startup. ### 3. Reload and Restart ```bash sudo systemctl daemon-reload sudo systemctl restart gitea-runner sudo systemctl status gitea-runner ``` Verify it shows `active (running)` and stays that way. Then reboot and confirm it comes up automatically. ## Why `network-online.target` and Not `network.target` | Target | What it guarantees | |---|---| | `network.target` | Network interfaces are configured (IP assigned) | | `network-online.target` | Network is fully operational (DNS resolvers reachable) | Services that need to make outbound network connections (especially DNS lookups) on startup should always use `network-online.target`. This includes: mail servers, monitoring agents, CI runners, anything that connects to an external host by name. > [!note] `network-online.target` can add a few seconds to boot time since systemd waits for the network stack to fully initialize. For server contexts this is always the right tradeoff. ## Related - [Managing Linux Services with systemd](../01-linux/process-management/managing-linux-services-systemd-ansible.md) - [MajorWiki Setup & Publishing Pipeline](majwiki-setup-and-pipeline.md)