Containerised Web UI to run renovate on selfhosted git forges (e.g. Forgejo). Overview - Status, PRs, warnings, etc. and reactive runs on push or renovate PR and issue interactions.
  • Go 67.2%
  • HTML 29.5%
  • JavaScript 1.9%
  • Just 0.7%
  • Dockerfile 0.5%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-19 10:37:04 +00:00
.github build(deps): update https://code.forgejo.org/actions/checkout action to v7.0.1 2026-07-21 00:05:54 +00:00
.vscode feat!: add automatic webhook sync for all suported git providers 2026-07-07 08:38:45 +02:00
cmd feat(executor): mount containerbase cache as a second persistent volume 2026-08-04 12:35:30 +02:00
config feat(executor): mount containerbase cache as a second persistent volume 2026-08-04 12:35:30 +02:00
internal refactor(executor): extract hostBinds() helper for container bind mounts 2026-08-04 13:33:56 +02:00
static chore: pi-lens autoformat + backfill T9 SHA in plan 2026-08-01 23:34:55 +02:00
.env.example docs: document ROP_CONTAINERBASE_CACHE_VOLUME env var 2026-08-04 13:28:06 +02:00
.gitignore feat!: replace K8s operator with standalone Docker operator 2026-07-16 11:23:02 +02:00
.golangci.yml feat: add push event support to Forgejo webhook handler 2026-07-17 12:56:14 +02:00
CHANGELOG.md chore(version): v0.7.0 [skip ci] 2026-07-20 14:56:30 +00:00
CODEOWNERS chore: adding dennis to code owners 2026-05-29 15:29:20 +02:00
cog.toml ci: fix Forgejo workflow_call secrets compatibility 2026-07-20 12:42:22 +02:00
CONTRIBUTING.md docs: update/cleanup 2026-07-19 15:58:59 +02:00
docker-compose.yml docs: update/cleanup 2026-07-19 15:58:59 +02:00
Dockerfile fix(deps): update dependency react-dom to v19.2.8 2026-07-22 11:23:55 +00:00
DONE-questions.md chore: mark completed scan remediation files with DONE- prefix 2026-07-18 14:00:25 +02:00
go.mod feat(metrics): add metrics package with tunable project-label cardinality 2026-07-30 14:15:56 +02:00
go.sum feat(metrics): add metrics package with tunable project-label cardinality 2026-07-30 14:15:56 +02:00
Justfile fix(deps): update dependency react-dom to v19.2.8 2026-07-22 11:23:55 +00:00
LICENSE docs: update/cleanup 2026-07-19 15:58:59 +02:00
README-development.md docs: autoformat 2026-07-19 15:59:00 +02:00
README.md docs(readme): add cache-volumes runbook subsection 2026-08-04 14:13:33 +02:00
renovate.json chore(config): migrate config renovate.json 2026-07-18 12:04:26 +00:00
screenshot-logs.png docs: add screenshots 2026-07-20 16:25:26 +02:00
screenshot-main.png docs: add screenshots 2026-07-20 16:25:26 +02:00
USERS.md docs: update/cleanup 2026-07-19 15:58:59 +02:00

renovate-docker-operator

A standalone Docker-based operator for running Renovate against Forgejo/Gitea instances. Manages Renovate containers via Docker socket — no Kubernetes required.

Overview screenshot

Log view with opened log level selector

Origin & Motivation

This project is a fork of mogenius/renovate-operator, adapted for environments that don't run Kubernetes.

Why does this exist?

  1. Renovate CE/EE does not support Forgejo. The feature request (mend-io/renovate-ce-ee#173) was locked and closed without resolution. If you self-host Forgejo, Mend's commercial offering simply won't work.

  2. The upstream renovate-operator is Kubernetes-only. It relies on CRDs, controller-runtime, and Kubernetes Jobs for container orchestration — a non-starter if your infrastructure is Docker Compose, Podman, or a single VM.

  3. This project extracts the core logic into a standalone binary that talks directly to the Docker socket. Same features (priority queues, parallelism, webhooks, discovery, UI), zero Kubernetes dependencies, single ~20 MB binary + SQLite for state.

Credit: The Forgejo webhook handling, repository discovery agent, priority queue, and web UI patterns all originate from the excellent work by the mogenius team. Thank you for building this in the open.

Features

  • Docker-native: No Kubernetes required. Manages Renovate containers via Docker socket.
  • SQLite state: Lightweight persistence with WAL mode for concurrent access.
  • Webhook-driven: Forgejo webhooks trigger immediate Renovate runs on PR/issue changes.
  • Cron scheduling: Automatic discovery and execution on configurable cron schedules.
  • Web UI: Dashboard showing job status, project runs, and streaming logs.
  • OIDC auth (planned): Optional authentication via any OIDC provider.
  • RENOVATE_*w pass-through: All RENOVATE_* env vars on the operator are injected into spawned containers.
  • Image caching: Configurable TTL avoids redundant Docker image pulls.
  • Access logging: HTTP access log middleware with webhook auth enrichment.
  • CSRF protection: Origin-based CSRF middleware on state-changing requests.

Quick Start

# 1. Clone
git clone https://git.h.oluflorenzen.de/finkregh/renovate-docker-operator.git
cd renovate-docker-operator

# 2. Copy and edit environment file
cp .env.example .env
# Edit .env — set RENOVATE_TOKEN at minimum

# 3. Start with Docker Compose
docker compose up -d

The UI is available at http://localhost:8081

Example: Running against Forgejo

cp .env.example .env

Edit .env:

ROP_PLATFORM_ENDPOINT=https://git.example.com
RENOVATE_TOKEN=<your-forgejo-token>
RENOVATE_PLATFORM=forgejo

Then:

docker compose up -d
# View logs
docker compose logs -f
# Open UI
open http://localhost:8081

See docker-compose.yml for all available options and .env.example for the full variable reference.

Configuration

All configuration is via environment variables:

Variable Default Description
RENOVATE_* All envvars beginning with RENOVATE_ are passed throug to spawned renovate containers
RENOVATE_PLATFORM forgejo Platform type (forgejo, gitea, github, gitlab) — passed to containers
RENOVATE_TOKEN (required) Platform access token for Renovate
ROP_PLATFORM_ENDPOINT (required) Forgejo/Gitea instance URL
ROP_IMAGE renovate/renovate:latest Docker image for Renovate
ROP_CRON_SCHEDULE 0 */4 * * * Cron expression for discovery+run cycles
ROP_PARALLELISM 2 Max concurrent Renovate containers
ROP_SERVER_PORT 8081 HTTP server port (UI + webhook + API)
ROP_SQLITE_PATH /data/renovate.db Path to SQLite database
ROP_CACHE_VOLUME renovate-cache Docker volume for Renovate cache
ROP_CONTAINERBASE_CACHE_VOLUME renovate-containerbase-cache Docker volume for Containerbase tool caches (uv, nix, pip, cargo, gradle, m2, gem, …). Safe to delete; refilled on next run.
ROP_CONTAINER_NETWORK (empty) Docker network for Renovate containers
ROP_IMAGE_PULL_POLICY if-not-present When to pull image (always, if-not-present, never)
ROP_IMAGE_CACHE_TTL 24h Duration to cache the pulled image (0 disables)
ROP_JOB_TIMEOUT 1800 Max runtime per Renovate container (seconds)
ROP_SHUTDOWN_GRACE_PERIOD 300 Grace period for stopping containers on shutdown (seconds)
ROP_MAX_REQUEST_BODY 2097152 Max webhook/API request body size in bytes (2 MiB)
ROP_LOG_LEVEL info Log level (debug, info, warn, error)

Any environment variable prefixed RENOVATE_* on the operator process is passed through 1:1 to spawned Renovate containers.

Cache volumes

The operator mounts two Docker volumes into every spawned Renovate container:

Volume (env var) Container path What it holds
renovate-cache (ROP_CACHE_VOLUME) /tmp/renovate Renovate's own base/cache dir — repo checkouts, repos.json, and the manager caches Renovate itself wires here via ensureCacheDir (others/{go,npm,pnpm,yarn,berry}).
renovate-containerbase-cache (ROP_CONTAINERBASE_CACHE_VOLUME) /tmp/containerbase/cache Containerbase-managed tool caches: uv, pip, poetry, nix (via the baked NIX_STORE_DIR, so the public binary substituter stays valid), cargo, gradle, m2, gem, nuget, sbt, cocoapods, conan, dart, flutter, hex, mix, and $HOME/.cache/* in general (the image symlinks /home/ubuntu/.cache into this tree).

Podman/Docker auto-seeds an empty named volume from the image's baked skeleton on first mount, preserving the root:root drwxrwxr-x permissions Containerbase requires. Both volumes are safe to delete to reclaim disk — Renovate refills them on the next run.

GID 0 requirement. Child Renovate containers run as 12021:0 (UID 12021, GID 0). Containerbase's install/prep steps write into /tmp/containerbase/cache as root:root with group-writable perms, so the non-root user needs the root group to write there. Do not override this with a custom --user flag; it will silently break tool caching and you'll see Permission denied errors for uv, nix, and friends.

Reclaiming disk. To wipe caches:

docker volume rm renovate-cache renovate-containerbase-cache

Or, targeted — e.g. only the large containerbase volume:

docker volume rm renovate-containerbase-cache

Both are recreated automatically on the next Renovate run.

Webhook Configuration

Variable Default Description
ROP_WEBHOOK_ENABLED true Enable webhook endpoint
ROP_WEBHOOK_SECRET (auto-generated) HMAC secret for webhook validation, needs to be set in providers config (optional — auto-generated on first startup, comma-separated for rotation)

Configure your Forgejo instance to send webhooks to:

http://renovate-operator:8081/webhook/v1/forgejo?job=default

Events to enable: Push, Issues (edited), and Pull Requests (edited, closed, reopened).

System Webhook Setup

For Forgejo instances where you want all repositories covered automatically, use a system webhook (Site Administration → Webhooks → Add Webhook → Forgejo):

  1. Target URL: http://renovate-operator:8081/webhook/v1/forgejo?job=default
  2. Content Type: application/json
  3. Secret: Your HMAC secret (retrieve from the operator — see below). This provides HMAC-SHA256 signature authentication via X-Forgejo-Signature.
  4. Branch Filter: main (or {main,master} to match multiple default branches). This filter is applied server-side by Forgejo, so only pushes to matching branches are delivered.
  5. Events: Select "Custom Events", then enable:
    • Push — triggers Renovate on code changes to the default branch
    • Pull Request (Modification) — triggers on PR edits/close/reopen for Renovate checkbox interactions
    • Issues enables Renovate Dependency Dashboard checkbox interactions

Note

: The branch filter is applied server-side by Forgejo before delivery. Tag pushes and branch deletions are also filtered out by the operator as defense-in-depth.

Generating the Webhook Secret

On first startup, the operator auto-generates a random 40-character HMAC secret and stores it in the database. The full secret is logged on first generation. Retrieve it later with:

sqlite3 data/renovate.db "SELECT value FROM settings WHERE key='webhook_secret'"

Paste this value into your Forgejo webhook's Secret field.

To override with a custom secret (e.g., for infrastructure-as-code):

ROP_WEBHOOK_SECRET=$(openssl rand -hex 20)

When ROP_WEBHOOK_SECRET is set, it takes precedence over the auto-generated value and is stored in the sqlite database. So starting once with the envvar is enough for e.g. secret rotation.

Authentication (Planned)

OIDC authentication is not yet implemented but is planned. The following environment variables will be supported:

Variable Default Description
ROP_OIDC_ISSUER_URL (empty) OIDC provider URL (leave empty for no-auth)
ROP_OIDC_CLIENT_ID (empty) OAuth2 client ID
ROP_OIDC_CLIENT_SECRET (empty) OAuth2 client secret
ROP_OIDC_REDIRECT_URL (empty) OAuth2 redirect URL
ROP_SESSION_SECRET (auto-generated) AES key for session cookies

Tip: When implemented, you'll be able to use Forgejo itself as your OIDC provider! Forgejo 1.22+ has built-in OAuth2 provider support.

Scheduling

Variable Default Description
ROP_CRON_SCHEDULE 0 */4 * * * Cron expression for discovery+run cycles
ROP_CRON_SKIP_DISCOVERY false Skip discovery on cron (only run known projects)

Discovery Filters

Variable Default Description
ROP_DISCOVERY_FILTERS (empty) Comma-separated repo patterns (e.g., org/*,user/repo-*)
ROP_DISCOVER_TOPICS (empty) Comma-separated topics to filter by
ROP_SKIP_FORKS false Skip forked repositories

Resilience & Metrics

The operator includes a rapid-fail circuit breaker that protects against cascading failures when the underlying environment is unhealthy (e.g., invalid token, unreachable registry). Per-project exponential backoff prevents a single broken repository from monopolising dispatch slots. Operators can issue a manual bypass for individual projects, and the system exposes Prometheus metrics on /metrics for alerting and dashboards.

Configuration

Variable Default Description
ROP_RAPID_FAIL_THRESHOLD 10 Number of rapid failures within the window to trip the breaker
ROP_RAPID_FAIL_WINDOW 5m Sliding window for counting rapid failures
ROP_FAILURE_MIN_RUNTIME 30s Containers exiting before this duration are classified as rapid failures
ROP_BACKOFF_BASE 30s Base delay for per-project exponential backoff
ROP_BACKOFF_MAX 30m Maximum per-project backoff cap
ROP_REPLAY_QUEUE_CAP 10000 Maximum queued webhook events when the breaker is open
ROP_METRICS_PROJECT_LABEL all Project label cardinality on metrics (all, breaker, off)

API Surface

  • GET /api/v1/breaker/state — current breaker snapshot (state, per-project backoffs, replay queue depth)
  • POST /api/v1/breaker/reset — full reset: closes breaker, clears all backoffs, drains replay queue
  • POST /api/v1/breaker/bypass/{org/repo} — single-shot manual override for one project
  • GET /metrics — Prometheus text exposition format

Webhook Behaviour When Breaker Is Open

When the breaker is open, webhooks return 202 Accepted and their events are queued; the queue drains automatically on reset (up to ROP_REPLAY_QUEUE_CAP, defaults 10 000, beyond which a 503 is returned).

Ops runbook: See unipi/docs/runbooks/breaker.md for diagnosis and recovery procedures.

API Endpoints

Method Path Description
GET /healthz Health check
GET /api/v1/version Server version
GET /api/v1/renovatejobs List all jobs with project statuses
POST /api/v1/renovate Trigger Renovate for a project
POST /api/v1/renovate/all Trigger all projects
POST /api/v1/renovate/cancel Cancel a running project
GET /api/v1/logs?renovate=X&project=Y Stream logs (SSE)
POST /api/v1/discovery/start Trigger discovery
POST /api/v1/executionOptions Update debug mode
POST /webhook/v1/forgejo?job=X Forgejo webhook receiver
POST /webhook/v1/schedule?project=X&job=Y Manual schedule trigger

Architecture

┌─────────────────────────────────────────┐
│          renovate-docker-operator       │
├─────────────────────────────────────────┤
│  HTTP Server (port 8081)                │
│  ├── /webhook/v1/* (Forgejo hooks)      │
│  ├── /api/v1/*     (REST API)           │
│  ├── /healthz      (health)             │
│  └── /*            (static UI)          │
├─────────────────────────────────────────┤
│  Scheduler (robfig/cron)                │
│  └── Discovery → Schedule → Dispatch    │
├─────────────────────────────────────────┤
│  Docker Executor                        │
│  ├── Container create/start/wait/logs   │
│  ├── Priority queue dispatch            │
│  └── Docker Events API (exit detect)    │
├─────────────────────────────────────────┤
│  SQLite State Store (WAL mode)          │
│  └── Jobs, Projects, Logs, Webhooks     │
└─────────────────────────────────────────┘
         │
         ▼ Docker Socket
┌─────────────────────────────────────────┐
│  renovate/renovate containers           │
│  (one per project, max parallelism)     │
└─────────────────────────────────────────┘

Development

For development documentation — project structure, coding conventions, architectural decisions, and build/test instructions — see README-development.md.

Differences from Upstream

Aspect mogenius/renovate-operator renovate-docker-operator
Runtime Kubernetes (CRDs, controller-runtime) Docker (socket API)
State store Kubernetes CRDs + etcd SQLite (WAL mode)
Container orchestration Kubernetes Jobs Docker containers
Configuration CRDs + ConfigMaps Environment variables
Image size ~50 MB (requires K8s cluster) ~20 MB standalone binary
Dependencies controller-runtime, client-go Docker SDK, modernc.org/sqlite
Auth OIDC + GitHub OAuth Planned (OIDC + no-auth; not yet implemented)
Platforms Forgejo, Gitea, GitHub, GitLab Same
Env var prefix Mixed ROP_* (operator) / RENOVATE_* (pass-through)
Renovate features Priority queue, parallelism, webhooks, UI Same
Deployment Helm chart, K8s cluster docker-compose or bare binary

We share the same Forgejo webhook logic, discovery agent, and UI patterns as upstream. This means improvements from mogenius/renovate-operator can be cherry-picked into this project when relevant.

License

MIT — see LICENSE.