Gitness: Self-Hosted Git and CI/CD From the Makers of Drone
Running separate services for Git hosting and CI/CD works, but it means maintaining two systems, two sets of credentials, and an integration layer between them. Gitea plus Woodpecker is a proven combo, but what if a single service handled both?
Photo by Vitaly Sacred on Unsplash
Gitness (formerly Harness Open Source) is a lightweight, self-hosted platform that combines Git repository hosting with a built-in CI/CD pipeline engine. It comes from the team behind Drone CI, and it shows -- the pipeline syntax is clean, the system is container-native, and the resource footprint stays small.
Why Gitness Exists
Gitness fills a gap in the self-hosted development tool space. GitLab gives you everything but demands significant resources. Gitea and Forgejo are excellent Git forges but require a separate CI/CD system. Jenkins is powerful but complex. Gitness takes a middle path: a single binary that handles both code hosting and pipeline execution without consuming half your server's RAM.
It grew out of Harness's acquisition of Drone CI. Rather than continuing Drone as a standalone CI tool, Harness built Gitness as a unified platform that inherits Drone's pipeline philosophy while adding native Git hosting.
Gitness vs. Other Self-Hosted CI/CD and Git Platforms
| Feature | Gitness | Gitea + Woodpecker | GitLab CE | Forgejo + Drone |
|---|---|---|---|---|
| Git hosting | Built-in | Gitea | Built-in | Forgejo |
| CI/CD | Built-in | Separate service | Built-in | Separate service |
| Setup complexity | Single container | Two containers + OAuth | Heavy (requires 4 GB+ RAM) | Two containers + OAuth |
| RAM usage (idle) | ~150 MB | ~120 MB combined | ~2.5 GB | ~120 MB combined |
| Pipeline syntax | YAML (Drone-derived) | Woodpecker YAML | GitLab CI YAML | Drone YAML |
| GitHub Actions compat | No | No (Gitea Actions: Yes) | No | No |
| Container registry | No | Gitea packages | Built-in | No |
| Code review | Pull requests | Pull requests | Merge requests | Pull requests |
| Issue tracking | No | Yes | Yes | Yes |
| Plugin ecosystem | Drone plugins | Woodpecker plugins | Large | Drone plugins |
| License | Apache 2.0 | Apache 2.0 / GPL | MIT (CE) | GPL |
Choose Gitness if you want the simplest possible path to Git hosting with CI/CD and don't need issue tracking. Choose Gitea + Woodpecker if you want a full-featured forge with issue tracking and proven CI/CD. Choose GitLab CE if you need everything in one box and have resources to spare.
Installation
Gitness ships as a single Docker image. No database to configure, no separate agent to run.
Docker (Quickstart)
docker run -d \
--name gitness \
-p 3000:3000 \
-v /var/lib/gitness:/data \
harness/gitness:latest
Visit http://your-server:3000, create an admin account, and you are running.
Docker Compose (Production)
services:
gitness:
image: harness/gitness:latest
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- gitness_data:/data
environment:
GITNESS_PRINCIPAL_ADMIN_EMAIL: [email protected]
GITNESS_PRINCIPAL_ADMIN_PASSWORD: change-this-password
GITNESS_URL_BASE: https://git.yourdomain.com
GITNESS_HTTP_PORT: 3000
GITNESS_ENCRYPTER_SECRET: generate-a-random-32-char-string
GITNESS_CI_RESOURCES_PER_REPO: 2
volumes:
gitness_data:
Reverse Proxy Configuration
Put Gitness behind Caddy or Nginx for HTTPS. A minimal Caddy config:
git.yourdomain.com {
reverse_proxy localhost:3000
}
Gitness serves both the web UI and Git operations (clone, push, pull) on the same port, so a single reverse proxy entry handles everything.
Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.
Repository Management
Gitness supports the standard Git forge workflow:
- Spaces: Organize repositories into namespaces (like GitHub organizations)
- Branches and tags: Full branch management with protection rules
- Pull requests: Code review with inline comments, approvals, and merge strategies (merge commit, squash, rebase)
- Web editor: Edit files directly in the browser
- Webhooks: Trigger external services on push, PR, and tag events
Branch Protection
Space → Repository → Settings → Rules
Set rules per branch pattern:
- Require pull request reviews before merge
- Require status checks (CI pipelines) to pass
- Block force pushes
- Restrict who can push directly
Importing Repositories
Gitness can import from external Git URLs:
- Create a new repository
- Select "Import Repository"
- Enter the clone URL
- Gitness pulls the full history including all branches and tags
This works for migrating from GitHub, GitLab, Gitea, or any accessible Git remote.
Pipeline Configuration
This is where Gitness shines. Pipelines are defined in .harness/ directory as YAML files, using a syntax that will feel familiar to anyone who has used Drone CI.
Basic Pipeline
Create .harness/build.yaml in your repository:
kind: pipeline
spec:
stages:
- type: ci
spec:
steps:
- name: test
type: run
spec:
container: node:20-alpine
script: |
npm ci
npm test
- name: lint
type: run
spec:
container: node:20-alpine
script: |
npm ci
npm run lint
Push to the repository and the pipeline triggers automatically.
Parallel Steps
Steps within a stage run sequentially by default. Use the parallel group to run steps concurrently:
kind: pipeline
spec:
stages:
- type: ci
spec:
steps:
- name: install
type: run
spec:
container: node:20-alpine
script: npm ci
- type: parallel
spec:
steps:
- name: test
type: run
spec:
container: node:20-alpine
script: npm test
- name: lint
type: run
spec:
container: node:20-alpine
script: npm run lint
Multi-Stage Pipelines
Separate build, test, and deploy into stages that run sequentially:
kind: pipeline
spec:
stages:
- type: ci
name: build-and-test
spec:
steps:
- name: build
type: run
spec:
container: node:20-alpine
script: |
npm ci
npm run build
- name: test
type: run
spec:
container: node:20-alpine
script: npm test
- type: ci
name: deploy
spec:
steps:
- name: deploy-to-production
type: run
spec:
container: alpine
script: ./deploy.sh
when:
branch: main
event: push
Service Containers
Spin up databases and other services alongside your pipeline:
kind: pipeline
spec:
stages:
- type: ci
spec:
services:
- name: postgres
image: postgres:16-alpine
environment:
POSTGRES_DB: testdb
POSTGRES_USER: test
POSTGRES_PASSWORD: test
steps:
- name: migrate-and-test
type: run
spec:
container: node:20-alpine
envs:
DATABASE_URL: postgres://test:test@postgres:5432/testdb
script: |
npm ci
npm run db:migrate
npm test
Services are accessible by name as a hostname, just like Docker Compose networking.
Secrets Management
Add secrets through the Gitness UI at the space or repository level. Reference them in pipelines:
steps:
- name: deploy
type: run
spec:
container: alpine
envs:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
SERVER_HOST: ${{ secrets.SERVER_HOST }}
script: |
ssh -i "$DEPLOY_KEY" user@"$SERVER_HOST" "./restart.sh"
Secrets are masked in pipeline logs automatically.
Using Drone Plugins
Gitness is compatible with the Drone plugin ecosystem, which includes hundreds of community-maintained Docker images for common CI/CD tasks:
Docker Build and Push
steps:
- name: build-image
type: plugin
spec:
name: docker
inputs:
repo: registry.example.com/myapp
registry: registry.example.com
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
tags:
- latest
- ${{ build.commit_sha }}
Slack Notification
steps:
- name: notify
type: plugin
spec:
name: slack
inputs:
webhook: ${{ secrets.SLACK_WEBHOOK }}
channel: deployments
template: "Build {{build.status}} for {{repo.name}}"
Resource Management
Gitness uses an embedded SQLite database by default. For production:
- CPU: 2 cores minimum for concurrent pipeline execution
- RAM: 256 MB base, plus roughly 100 MB per concurrent pipeline step
- Disk: Depends on repository sizes and build artifacts
- Concurrent builds: Controlled via
GITNESS_CI_RESOURCES_PER_REPO
The embedded runner executes pipeline steps as Docker containers on the same host. For larger teams, this means the Gitness host needs enough resources for both the platform and the builds.
Limitations to Know
- No issue tracker: Gitness focuses on code and CI/CD. You will need a separate tool for issue tracking (GitHub Issues, Linear, or a self-hosted option like Gitea).
- No package registry: No built-in container registry or package hosting. Use a separate registry like Harbor or the Docker registry.
- Smaller community: Gitness is newer and has a smaller user base compared to Gitea or GitLab. Documentation is improving but not as comprehensive.
- Single-node runner: The built-in CI runner is local only. For distributed builds across multiple machines, you may need additional configuration.
- Harness branding: Gitness is backed by Harness (a commercial CI/CD company). The open-source commitment is real, but it is worth understanding the corporate backing when evaluating long-term bets.
Backup
Since Gitness uses an embedded database and stores everything under /data:
# Stop the container first for a consistent backup
docker stop gitness
tar czf gitness-backup-$(date +%F).tar.gz /var/lib/gitness
docker start gitness
For zero-downtime backups, use filesystem snapshots (ZFS, LVM, or Btrfs) on the data volume.
The Bottom Line
Gitness is the simplest path to a self-hosted Git forge with built-in CI/CD. A single container, a single port, and you have both repository hosting and pipeline execution. The Drone heritage shows in the clean pipeline syntax, and compatibility with Drone plugins gives you a practical ecosystem from day one.
If you are currently running Gitea plus a separate CI/CD tool and find the integration overhead annoying, Gitness collapses that into one service. If you need full forge features like issue tracking and a package registry, Gitea or GitLab are still better fits. But for teams that live in their IDE and just need a place to push code and run builds, Gitness does exactly what it needs to and nothing more.
