Post

Automated dependency updates with Renovate

Automated dependency updates with Renovate

Purpose

Renovate scans the repositories on the self-hosted Gitea and opens pull requests that bump container image tags, Helm charts, GitHub Actions and similar dependencies. It proposes changes. The review and CI gates decide, the same split as in the compliance fixer post and the docs pipeline post.

Deployment

Renovate runs on the Gitea host from a clone of its own repo, using the upstream ghcr.io/renovatebot/renovate image against the Gitea API. It autodiscovers every repository the renovate Gitea user can see.

A systemd timer starts it every 2 hours (at 15 minutes past the even hours, with 5 minutes of jitter, and Persistent=true so a missed run happens at boot). Each run is a fresh container started with docker compose run --rm renovate. Renovate does one pass and exits. The dependency cache and working clones persist in a local data directory.

flowchart LR
    T["systemd timer<br/>every 2 hours"] --> R["Renovate container<br/>one pass, then exit"]
    R --> G["Gitea repos"]
    G --> P["Update pull request"]
    P --> H["Human review and CI"]
    H --> M["Merge"]
    M --> A["ArgoCD sync<br/>on k3s branches"]

Configuration

Each repo carries its own renovate.json. The shared preset in the Renovate repo automerges minor, patch, pin and digest updates. The rules that matter are per repo.

No automerge on the k3s deploy branches. ArgoCD deploys that branch, so a merge is a deploy. The k3s deploy repos set automerge: false for the k3s base branch:

1
2
3
4
5
{
  "description": "k3s is what ArgoCD deploys: never automerge there, a merge is a deploy",
  "matchBaseBranches": ["k3s"],
  "automerge": false
}

The exceptions are our own images, such as the doc-site image, where a bump is safe to automerge. For the doc-site that rule is a second package rule matching the image name on the k3s branch with automerge: true. A merge to Doc-Site-Build publishes the site anyway.

Noise filters. linuxserver.io images carry old Ubuntu-release tags (18.04.1, 20.04.1) that Renovate sorts above real versions. Once it proposed moving qBittorrent from 5.2.4 to 20.04.1, a 2021 image. The Arr repo now ignores date-style tags for linuxserver images and limits qBittorrent to versions below 10:

1
2
3
4
{
  "matchPackageNames": ["lscr.io/linuxserver/qbittorrent"],
  "allowedVersions": "<10"
}

Postgres gets no major-version pull requests, because a major bump can break data-directory compatibility (brief #112).

Storage

The Renovate container keeps its cache and working clones in a local data directory on the Gitea host. Nothing else is stored. The Gitea and GitHub tokens come from a git-ignored .env file on the host and are not in the repo.

Access

There is no web UI. The output is the pull requests in each repo. To look at a run, read the journal for renovate.service on the Gitea host, or start a pass by hand with systemctl start renovate.service.

Notes

  • Until 2026-10-19 the compose file had restart: unless-stopped, so Docker restarted the container as soon as a pass ended. That produced 2,569 back-to-back passes in three weeks, a full 45-repo pass every 12 to 35 minutes, and constant load on the Gitea API and disk. The timer fixed it. The cost is that pull requests now appear within two hours of a merge instead of within minutes.
  • Before the first sync of a new app, re-diff it against what is already deployed, so a bump that Renovate has queued does not land unreviewed (brief #112).
  • Both tokens once sat as literals in the compose file’s git history. They were rotated and the old ones are treated as public.
This post is licensed under CC BY 4.0 by the author.