Drone CI is an open-source, container-native continuous integration and delivery platform that runs every pipeline step inside an isolated Docker container. It integrates natively with GitHub, Gitea, GitLab, and Bitbucket, making it a lightweight alternative to Jenkins for teams already working with containers. Drone’s configuration lives in a .drone.yml file committed alongside your code, keeping CI/CD logic version-controlled and auditable. This guide walks through installing and configuring Drone CI on RHEL 9 using Docker, connecting it to a GitHub repository, and running your first automated pipeline.

Prerequisites

  • RHEL 9 server with at least 2 CPU cores and 2 GB RAM
  • Docker and Docker Compose installed and running (systemctl enable --now docker)
  • A registered GitHub OAuth application (Settings → Developer settings → OAuth Apps) with the callback URL set to http://YOUR_SERVER_IP/login
  • Ports 80 and 443 reachable from the internet (or from your internal network)
  • A domain name or static IP for the Drone server

Step 1 — Install Docker on RHEL 9

# Add the Docker CE repository
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo

# Install Docker Engine
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Start and enable Docker
systemctl enable --now docker

# Verify the installation
docker version

Step 2 — Open Firewall Ports

# Allow HTTP and HTTPS through firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

# Confirm the rules are active
firewall-cmd --list-services

Step 3 — Generate a Shared RPC Secret

# Generate a cryptographically random secret used by server and runner
openssl rand -hex 16
# Example output: 8f2d4a7b9c1e3f05a6b8d2e4f7c9a1b3
# Save this value — you will use it as DRONE_RPC_SECRET below

Step 4 — Run the Drone Server Container

# Replace all placeholder values with your real credentials
docker run 
  --detach 
  --restart=always 
  --volume=/var/lib/drone:/data 
  --publish=80:80 
  --publish=443:443 
  --env=DRONE_GITHUB_CLIENT_ID=YOUR_GITHUB_CLIENT_ID 
  --env=DRONE_GITHUB_CLIENT_SECRET=YOUR_GITHUB_CLIENT_SECRET 
  --env=DRONE_RPC_SECRET=8f2d4a7b9c1e3f05a6b8d2e4f7c9a1b3 
  --env=DRONE_SERVER_HOST=drone.example.com 
  --env=DRONE_SERVER_PROTO=http 
  --env=DRONE_TLS_AUTOCERT=false 
  --env=DRONE_LOGS_PRETTY=true 
  --name=drone 
  drone/drone:2

# Verify the container is running
docker ps | grep drone

Step 5 — Run the Drone Docker Runner

# The runner polls the server for pending pipelines and executes them
docker run 
  --detach 
  --restart=always 
  --volume=/var/run/docker.sock:/var/run/docker.sock 
  --env=DRONE_RPC_PROTO=http 
  --env=DRONE_RPC_HOST=drone.example.com 
  --env=DRONE_RPC_SECRET=8f2d4a7b9c1e3f05a6b8d2e4f7c9a1b3 
  --env=DRONE_RUNNER_CAPACITY=2 
  --env=DRONE_RUNNER_NAME=rhel9-runner 
  --name=runner 
  drone/drone-runner-docker:1

# Confirm the runner connected successfully
docker logs runner 2>&1 | grep "successfully pinged"

Step 6 — Create a .drone.yml Pipeline File

# Commit this file to the root of your repository as .drone.yml

kind: pipeline
type: docker
name: default

steps:
  - name: install-deps
    image: node:20-alpine
    commands:
      - npm ci

  - name: test
    image: node:20-alpine
    commands:
      - npm test

  - name: build
    image: node:20-alpine
    commands:
      - npm run build
    when:
      branch:
        - main

services:
  - name: database
    image: postgres:15
    environment:
      POSTGRES_USER: testuser
      POSTGRES_PASSWORD: testpass
      POSTGRES_DB: testdb

trigger:
  event:
    - push
    - pull_request

Conclusion

You now have a fully functional Drone CI installation on RHEL 9. The Drone Server handles authentication and pipeline orchestration while the Docker Runner executes each pipeline step in an isolated container, keeping build environments clean and reproducible. The .drone.yml file committed to your repository ensures that pipeline changes go through the same code review process as application code. For production use, enable TLS by setting DRONE_TLS_AUTOCERT=true and pointing your domain’s DNS at the server, store secrets in Drone’s encrypted secret store rather than committing them to YAML, and consider running multiple runners across different hosts to handle parallel workloads.

Next steps: How to Install Jenkins on RHEL 9, How to Build and Push Docker Images in CI/CD Pipelines on RHEL 9, and How to Set Up a Local Container Registry with Harbor on RHEL 9.