Back to articles
Technology Insight

Building an Ultra-Lightweight On-Premise CI/CD System with Forgejo and Woodpecker CI

June 4, 2026

Introduction: The Quest for Lightweight On-Premise DevOps

In the modern software development lifecycle, Continuous Integration and Continuous Deployment (CI/CD) have transitioned from luxury frameworks to absolute necessities. However, for engineering teams managing internal source code, proprietary algorithms, or strictly regulated data, cloud-based solutions like GitHub Actions or GitLab SaaS are not always viable options. Concerns regarding compliance, data sovereignty, and recurring subscription costs frequently drive organizations back toward on-premise infrastructure.

Yet, traditional self-hosted heavyweights like GitLab Enterprise or Jenkins present their own challenges. These platforms are notorious resource hogs, often requiring multi-core CPUs and gigabytes of RAM just to idle. For small-to-medium enterprises (SMEs) or dedicated internal dev teams, dedicating substantial hardware resources merely to host version control and basic pipelines is inefficient. This is where the powerful, minimalist combination of Forgejo and Woodpecker CI comes into play, offering a robust, secure, and ultra-lightweight alternative.

Understanding the Stack: Why Forgejo and Woodpecker CI?

Before diving into the architecture and deployment steps, it is essential to understand why this specific pairing is becoming the go-to stack for resource-conscious DevOps engineers.

Forgejo: The Community-Driven Git Forge

Forgejo is a self-hosted software development platform, born as a community-driven hard fork of Gitea. It inherited Gitea’s core philosophy: being exceptionally fast, easy to install, and low on resource consumption. Written in Go, Forgejo can run seamlessly on everything from a low-powered Raspberry Pi to a high-end enterprise server, providing a familiar, GitHub-like user interface for repository management, issue tracking, and code reviews without the performance bloat.

Woodpecker CI: The Lean Pipeline Engine

Woodpecker CI is a community fork of Drone CI (specifically from its open-source era). Like Forgejo, it prioritizes simplicity and efficiency. Woodpecker utilizes a container-first architecture where every pipeline step is executed within an isolated Docker container. Configured completely via simple YAML files, it eliminates the plugin-hell frequently associated with Jenkins, while consuming only a fraction of the memory required by GitLab Runners.

Architectural Overview and Prerequisites

The proposed architecture separates the Git management layer from the pipeline execution layer. This ensures that a heavy CI/CD build load will not destabilize the primary source code repository interface.

  • Forgejo Server: Handles Git operations, SSH keys, user authentication, and webhooks.
  • Woodpecker Server: Acts as the orchestrator, receiving webhooks from Forgejo, managing the build queue, and communicating with agents.
  • Woodpecker Agent: The workhorse component that connects to the local Docker daemon to spin up ephemeral containers for building, testing, and deploying code.
System Requirement Note: While GitLab might demand a minimum of 4GB to 8GB of RAM, the combined Forgejo and Woodpecker stack can comfortably handle dozens of repositories and active developers on a simple VPS or internal VM with just 2GB of RAM.

Step-by-Step Deployment Blueprint via Docker Compose

To ensure maintainability and rapid deployment, we will utilize Docker Compose to orchestrate our ultra-lightweight CI/CD environment. Below is a comprehensive configuration file to bootstrap the entire system.

1. The Docker Compose Configuration

Create a directory named lightweight-devops and place the following docker-compose.yml file inside it:

version: '3.8'

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:7.0
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    volumes:
      - ./forgejo_data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
    restart: always

  woodpecker-server:
    image: woodpeckerci/woodpecker-server:v2.4
    container_name: woodpecker-server
    volumes:
      - ./woodpecker_server:/var/lib/woodpecker
    environment:
      - WOODPECKER_OPEN=true
      - WOODPECKER_FORGEJO=true
      - WOODPECKER_FORGEJO_URL=http://forgejo:3000
      - WOODPECKER_AGENT_SECRET=a_very_secure_random_string_here
    ports:
      - "8000:8000"
    restart: always
    depends_on:
      - forgejo

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:v2.4
    container_name: woodpecker-agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WOODPECKER_SERVER=woodpecker-server:8000
      - WOODPECKER_AGENT_SECRET=a_very_secure_random_string_here
    restart: always
    depends_on:
      - woodpecker-server

Execute docker compose up -d to initialize the services. Once running, access the Forgejo web interface at http://localhost:3000 and complete the initial setup wizard.

Integrating Woodpecker CI with Forgejo

To establish a secure handshake between Forgejo and Woodpecker, an OAuth2 application must be configured within Forgejo.

  1. Log into Forgejo, navigate to your User Settings (or Site Administration if configuring globally), and locate the Applications tab.
  2. Create a new OAuth2 Application. Set the application name to "Woodpecker CI".
  3. Set the Redirect URI to pointing to your Woodpecker server instance: http://:8000/authorize.
  4. Save the application to generate a Client ID and a Client Secret.

Update your docker-compose.yml file under the woodpecker-server environment section with these newly generated credentials, adding WOODPECKER_FORGEJO_CLIENT and WOODPECKER_FORGEJO_SECRET variables, then restart the containers to apply changes.

Writing Your First Pipeline: A Practical Example

With the integration complete, activate your repository within the Woodpecker dashboard. Woodpecker relies on a configuration file placed at the root of your repository, typically named .woodpecker.yaml. Let us examine a production-ready example designed to test and build a standard Node.js microservice:

pipeline:
  test:
    image: node:20-alpine
    commands:
      - npm ci
      - npm run test:unit

  build-image:
    image: plugins/docker
    settings:
      repo: internal-registry.local/my-app
      tags: latest,${CI_COMMIT_SHA:0:7}
      registry: internal-registry.local
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password
    when:
      branch: main
      event: push

Key Highlights of the Pipeline Structure:

  • Isolation: The test step runs inside an official, lightweight Alpine-based Node.js container, guaranteeing no environment pollution.
  • Native Plugins: The plugins/docker image is a pre-built Woodpecker utility that simplifies building and pushing Docker images securely without requiring root Docker-in-Docker privilege escalations manually.
  • Conditional Execution: The when clause ensures that the final production build and registry push only transpire when code is successfully merged into the main branch.

Best Practices for Maintaining On-Premise CI/CD

Operating an internal DevOps ecosystem requires proper maintenance to preserve its lightweight advantages. Consider adopting the following best practices:

First, implement aggressive artifact pruning. Because Woodpecker leverages Docker images, unused layers and old build containers can accumulate rapidly on your host storage. Automate a nightly cron job running docker system prune -af --volumes to keep disk usage to a minimum.

Second, safeguard secret management. Never hardcode API keys, passwords, or deployment credentials directly into your .woodpecker.yaml file. Always utilize the Woodpecker web UI to inject secrets securely into the pipeline runtime environment.

Conclusion: High Performance, Zero Bloat

By shifting from resource-intensive enterprise platforms to the combined synergy of Forgejo and Woodpecker CI, organizations can successfully establish a secure, performant, and completely isolated internal CI/CD workflow. This stack respects your system resources, demands negligible maintenance, and provides modern, containerized pipelines tailored perfectly for internal source code protection. It proves that enterprise-grade automation does not require enterprise-scale infrastructure spending.