How to Self-Host Gitness: Modern Open Source CI/CD 2026
TL;DR
Gitness (Apache 2.0, ~32K GitHub stars, Go) is Harness's open source unified Git + CI/CD platform. It combines Git repository hosting, pipeline execution, a container registry, secret management, and a modern web UI into a single lightweight binary. Compare it to: Drone CI (simpler, older), Woodpecker CI (community Drone fork), or Forgejo + forgejo-runner (more feature-rich Git hosting but separate CI). Gitness excels at clean YAML pipeline definitions and low resource usage.
Key Takeaways
- Gitness: Apache 2.0, ~32K stars, Go — unified Git + CI/CD in one binary
- Pipeline YAML: GitHub Actions-compatible syntax (stages, steps, services)
- Container registry: Built-in, no separate Harbor/registry needed
- Secrets: Built-in secret management per pipeline
- Resource use: ~100MB RAM — significantly lighter than GitLab (~4GB)
- vs Woodpecker CI: Gitness is newer with a better UI; Woodpecker has a larger ecosystem
Gitness vs Drone vs Woodpecker vs Forgejo+Runner
| Feature | Gitness | Drone CE | Woodpecker | Forgejo + Runner |
|---|---|---|---|---|
| License | Apache 2.0 | Apache 2.0 | Apache 2.0 | GPL 3.0 |
| GitHub Stars | ~32K | ~11K | ~4K | ~10K |
| Git hosting | Yes | No (separate) | No (separate) | Yes |
| Container Registry | Yes | No | No | Yes |
| Secret management | Yes | Yes | Yes | Yes |
| UI quality | Excellent | Basic | Good | Good |
| RAM | ~100MB | ~50MB | ~50MB | ~150MB |
Part 1: Docker Setup
# docker-compose.yml
services:
gitness:
image: harness/gitness:latest
container_name: gitness
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- gitness_data:/data
- /var/run/docker.sock:/var/run/docker.sock # For running pipelines
environment:
GITNESS_URL_BASE: "https://git.yourdomain.com"
GITNESS_TOKEN_EXPIRE_DURATION: "720h"
volumes:
gitness_data:
docker compose up -d
Visit http://your-server:3000 → register admin account.
Part 2: HTTPS with Caddy
git.yourdomain.com {
reverse_proxy localhost:3000
}
Update GITNESS_URL_BASE to https://git.yourdomain.com after configuring HTTPS.
Part 3: Create a Repository
- + New Repository
- Name:
my-app - Initialize with README
- Clone:
git clone https://git.yourdomain.com/admin/my-app.git
Part 4: CI/CD Pipelines
Create a pipeline with .gitness/pipeline.yaml:
Basic Pipeline (Node.js app)
# .gitness/pipeline.yaml
kind: pipeline
type: docker
name: ci
steps:
- name: test
image: node:20-alpine
commands:
- npm ci
- npm test
- name: build
image: node:20-alpine
commands:
- npm ci
- npm run build
when:
branch:
- main
- name: docker-build
image: docker:dind
privileged: true
environment:
REGISTRY_USERNAME:
from_secret: registry_username
REGISTRY_PASSWORD:
from_secret: registry_password
commands:
- docker login git.yourdomain.com -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD
- docker build -t git.yourdomain.com/admin/my-app:${DRONE_COMMIT_SHA} .
- docker push git.yourdomain.com/admin/my-app:${DRONE_COMMIT_SHA}
when:
branch:
- main
Pipeline with Services (PostgreSQL for tests)
kind: pipeline
type: docker
name: ci-with-db
services:
- name: db
image: postgres:16-alpine
environment:
POSTGRES_DB: testdb
POSTGRES_USER: test
POSTGRES_PASSWORD: testpass
steps:
- name: test
image: golang:1.22-alpine
environment:
DATABASE_URL: "postgres://test:testpass@db:5432/testdb?sslmode=disable"
commands:
- go test ./...
Multi-Stage Deploy Pipeline
kind: pipeline
type: docker
name: deploy
steps:
- name: test
image: python:3.12-alpine
commands:
- pip install -r requirements.txt
- pytest
- name: build
image: docker:dind
commands:
- docker build -t git.yourdomain.com/admin/api:${DRONE_COMMIT_SHA} .
- docker push git.yourdomain.com/admin/api:${DRONE_COMMIT_SHA}
- name: deploy-staging
image: alpine:3.19
environment:
SSH_KEY:
from_secret: deploy_ssh_key
commands:
- apk add openssh-client
- echo "$SSH_KEY" > /tmp/key && chmod 600 /tmp/key
- ssh -i /tmp/key deploy@staging.yourdomain.com "docker pull git.yourdomain.com/admin/api:${DRONE_COMMIT_SHA} && docker compose up -d api"
when:
branch:
- main
- name: deploy-production
image: alpine:3.19
commands:
- echo "Deploy to production"
when:
branch:
- main
event:
- tag
Part 5: Secrets Management
Add secrets per repository:
- Repository → Settings → Secrets → + New Secret
- Name:
registry_password,deploy_ssh_key,stripe_key - Value: (encrypted at rest)
Reference in pipeline:
environment:
MY_SECRET:
from_secret: my_secret_name
Part 6: Container Registry
Use the built-in container registry:
# Login:
docker login git.yourdomain.com
# Username: your-gitness-username
# Password: your-gitness-password (or API token)
# Push image:
docker tag myapp git.yourdomain.com/username/repo:tag
docker push git.yourdomain.com/username/repo:tag
# Pull:
docker pull git.yourdomain.com/username/repo:tag
Part 7: Webhooks
Trigger external services on push/PR:
- Repository → Settings → Webhooks → + New Webhook
- URL:
https://n8n.yourdomain.com/webhook/gitness - Events: push, pull_request, tag
Payload includes branch, commit SHA, repository info — use with n8n to trigger deploys, notify Slack, etc.
Part 8: Runner Setup (External)
For CI jobs that need more resources or a different host:
# On a runner machine:
services:
gitness-runner:
image: harness/gitness-runner:latest
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
GITNESS_URL: "https://git.yourdomain.com"
GITNESS_TOKEN: "${RUNNER_TOKEN}" # From Gitness → Admin → Runners → New Runner
GITNESS_RUNNER_MAX_PROCS: "4"
Maintenance
# Update Gitness:
docker compose pull
docker compose up -d
# Backup:
tar -czf gitness-backup-$(date +%Y%m%d).tar.gz \
$(docker volume inspect gitness_gitness_data --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f gitness
See all open source CI/CD and developer tools at OSSAlt.com/categories/devops.