Skip to content

nasraldin/OneDev

Repository files navigation

OneDev Production Docker Stack

This repository provides a production-oriented, headless Docker Compose setup for OneDev: a self-hosted Git server with CI/CD, Kanban, package management, and build agents.

The setup is designed so you can run one command, get a working OneDev instance, and manage the full lifecycle safely without committing secrets.

make up

Screenshot

After make up, OneDev is available from the browser and ready for the generated admin login:

OneDev login screen OneDev home screen

What This Stack Provides

  • OneDev server pinned to 1dev/server:16.0.1
  • PostgreSQL 17-alpine as the external production database
  • Dedicated OneDev runner using 1dev/agent:latest
  • Headless first-run provisioning
  • Remote Docker executor auto-created in OneDev
  • Local secrets generated automatically and never overwritten
  • Makefile-based lifecycle commands
  • Docker socket access isolated to the runner, not the main OneDev server

Architecture

The production stack uses three services:

  • onedev: the web UI, Git server, API, build scheduler, and application logic
  • postgres: persistent external database for OneDev metadata
  • onedev-agent: dedicated CI/CD runner that executes Docker-based jobs

The main OneDev server does not mount /var/run/docker.sock. Only the runner does. This keeps CI/CD Docker privileges away from the application server container and is safer than running builds directly on the server.

The provisioner configures OneDev with:

  • system server URL
  • SSH root URL
  • agent token
  • online runner
  • remote-docker job executor

Files

  • docker-compose.production.yml: recommended production stack
  • Makefile: operator interface
  • .env.production.example: production environment template
  • scripts/provision-production.sh: headless provisioning script used by make up
  • scripts/create-agent-token.sh: creates an agent token if missing
  • secrets/.gitkeep: keeps the secrets directory in git

Generated local files:

  • .env
  • secrets/db_password
  • secrets/admin_password
  • secrets/onedev_agent_token

These generated files are ignored by git and must not be committed.

Requirements

  • Linux or macOS host
  • Docker Engine
  • Docker Compose v2
  • make
  • bash
  • curl
  • openssl
  • python3

For Linux production hosts, Docker should be installed as a system service. For rootless Docker, set:

DOCKER_SOCK=/path/to/rootless/docker.sock

Usually this is:

DOCKER_SOCK=$XDG_RUNTIME_DIR/docker.sock

First Run

For local testing:

make up

This command is safe to run on a clean machine. It will:

  • create .env from .env.production.example if missing
  • create required secrets if missing
  • keep existing secrets if they already exist
  • start PostgreSQL and OneDev
  • configure OneDev system URLs
  • create an agent token if missing
  • start the runner
  • create/update the remote-docker executor
  • verify HTTP, PostgreSQL, executor, and runner status

After startup, open:

http://localhost:6610

The admin username comes from:

ONEDEV_ADMIN_USER=admin

The generated admin password is stored locally in:

secrets/admin_password

Production Domain Setup

For a real production server, edit .env before running make up:

ONEDEV_SERVER_URL=https://git.example.com
ONEDEV_SSH_ROOT_URL=ssh://git.example.com:6611

ONEDEV_SYSTEM_SERVER_URL=https://git.example.com
ONEDEV_SYSTEM_SSH_ROOT_URL=ssh://git.example.com:6611

ONEDEV_AGENT_SERVER_URL=https://git.example.com

Use real DNS, TLS, and firewall rules. Port 6611 is used for Git over SSH and must be reachable if SSH clone/push is required.

For local Docker-only testing, the default internal URLs are intentional:

ONEDEV_SYSTEM_SERVER_URL=http://onedev:6610
ONEDEV_SYSTEM_SSH_ROOT_URL=ssh://onedev:6611
ONEDEV_AGENT_SERVER_URL=http://onedev:6610

These allow the runner container to clone repositories from the OneDev server over the Docker network.

Daily Operations

Show commands:

make help

Start or provision:

make up

Stop containers while keeping data and secrets:

make down

Restart and reprovision:

make restart

Show container status:

make status

Follow logs:

make logs
make logs-server
make logs-runner

Verify runtime health:

make verify

Open shells:

make shell-server
make shell-runner
make db-shell

Pull configured images:

make pull

Validate rendered Compose config:

make config

Destructive Commands

Stop containers and remove Docker volumes, while keeping .env, database password, and admin password:

make destroy

make destroy removes secrets/onedev_agent_token because agent tokens are stored server-side in the OneDev database. After the database volume is deleted, the old token is no longer valid and must be regenerated on the next make up.

Remove containers, volumes, .env, and local secret files:

make destroy-secrets

Full local reset from scratch:

make reset

Use destructive commands carefully. They remove application data stored in Docker volumes.

CI/CD Runner Usage

The runner is provisioned automatically as:

runner-01

The job executor is provisioned automatically as:

remote-docker

In .onedev-buildspec.yml, reference it like this:

version: 27
jobs:
  - name: Hello World
    jobExecutor: remote-docker
    steps:
      - !CheckoutStep
        name: checkout
        cloneCredential: !DefaultCredential {}
        withLfs: false
        withSubmodules: false
        condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL

      - !CommandStep
        name: Print Environment
        runInContainer: true
        image: alpine:latest
        interpreter: !DefaultInterpreter
          commands:
            - apk add --no-cache git
            - echo "Hello from OneDev"
            - pwd
            - ls -la
            - git rev-parse HEAD
        useTTY: false
        condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL

    triggers:
      - !BranchUpdateTrigger {}

    retryCondition: never
    maxRetries: 3
    retryDelay: 30
    timeout: 3600

Secrets Policy

Secrets are local runtime files only.

Ignored by git:

.env
secrets/*
!secrets/.gitkeep

Do not commit:

  • secrets/admin_password
  • secrets/db_password
  • secrets/onedev_agent_token
  • .env

Secrets are generated only if missing. Existing secrets are preserved by default.

To rotate only the agent token:

make rotate-agent-token

Backup and Restore

Back up both:

  • PostgreSQL data volume: onedev_postgres_data
  • OneDev data volume: onedev_onedev_data

Recommended backup approach:

docker compose -f docker-compose.production.yml exec -T postgres \
  pg_dump -U onedev -d onedev > backups/onedev-$(date +%F).sql

Also back up OneDev data:

docker run --rm \
  -v onedev_onedev_data:/data:ro \
  -v "$PWD/backups:/backup" \
  alpine tar czf /backup/onedev-data-$(date +%F).tar.gz -C /data .

Create backups before upgrades, migrations, or destructive operations.

Upgrades

  1. Back up PostgreSQL and OneDev volumes.
  2. Update image versions in .env:
ONEDEV_IMAGE=1dev/server:<version>
ONEDEV_AGENT_IMAGE=1dev/agent:latest
  1. Pull and restart:
make pull
make up
make verify

OneDev agents are designed to be updated by the server as needed, but using the latest 1dev/agent image is recommended.

Capacity Guidance

Official OneDev documentation says OneDev can run on a small 2 CPU / 2 GB RAM machine. That is suitable for evaluation, small teams, or light Git hosting.

This stack is designed for small to mid-size production use. A realistic starting point:

  • 4 CPU / 8 GB RAM: small team, light CI/CD
  • 8 CPU / 16 GB RAM: moderate team, more repositories, regular CI/CD
  • separate runner hosts: recommended when CI jobs are heavy or untrusted
  • fast SSD storage: strongly recommended for Git repositories and PostgreSQL

For approximately 500 registered users, this setup can be appropriate if usage is moderate:

  • not all users are active concurrently
  • CI/CD concurrency is limited
  • repositories are not extremely large
  • PostgreSQL and Docker volumes are on SSD storage
  • runners are scaled separately for build load

Do not treat 500 users as a hard guarantee. Capacity depends more on concurrent activity, repository size, build frequency, artifact volume, and CI job weight than on registered user count.

For heavier production usage, scale by:

  • adding more OneDev agents on separate machines
  • increasing CPU/RAM for PostgreSQL and OneDev
  • using external managed PostgreSQL
  • placing Git/data volumes on high-performance SSD storage
  • limiting concurrent builds per runner
  • monitoring CPU, RAM, disk I/O, PostgreSQL latency, and Docker job queue time

Security Notes

The Docker socket is powerful. Any container with /var/run/docker.sock can effectively control the Docker host.

This stack reduces risk by:

  • not mounting Docker socket into the main OneDev server
  • mounting Docker socket only into the runner container
  • using a remote Docker executor
  • separating CI execution from the application server container

For untrusted users or public registration:

  • disable open signup unless required
  • restrict who can create projects and edit build specs
  • run runners on dedicated worker machines
  • do not run untrusted builds on the same host as production data
  • consider Kubernetes executors or isolated runner hosts for stronger boundaries

Troubleshooting

Check stack health:

make status
make verify

View server logs:

make logs-server

View runner logs:

make logs-runner

If checkout fails with a domain error such as:

Could not resolve host: git.example.com

then OneDev system URLs are wrong for the runner. For local testing, use:

ONEDEV_SYSTEM_SERVER_URL=http://onedev:6610
ONEDEV_SYSTEM_SSH_ROOT_URL=ssh://onedev:6611
ONEDEV_AGENT_SERVER_URL=http://onedev:6610

Then rerun:

make up

If jobs say:

No applicable executor discovered for current job

ensure your buildspec uses:

jobExecutor: remote-docker

and run:

make verify

If the runner is not online:

make logs-runner
make rotate-agent-token

About

Self-Host OneDev Powerful. Simple. Git server with CI/CD, kanban, and packages. Seamless integration. Unparalleled experience.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages