How to Install and Configure Drone CI on RHEL 7
Drone CI is a lightweight, container-native continuous integration platform built around the concept of pipelines-as-code. Unlike Jenkins, which requires significant plugin management and XML configuration, Drone uses a simple YAML file (.drone.yml) stored in your repository to define every aspect of a pipeline. Drone’s server handles webhook events from your source control system, while one or more runners execute pipeline steps inside Docker containers, ensuring perfect environment isolation for every build. This tutorial covers deploying the Drone server and a Docker runner on RHEL 7 using Docker Compose, configuring OAuth with Gitea or GitHub, writing .drone.yml pipelines, managing secrets, and using the Drone CLI.
Prerequisites
- RHEL 7 server with root or sudo access
- Docker CE installed and running (
systemctl status docker) - Docker Compose installed (
docker-compose --version) - A domain name or resolvable hostname pointing to this server (required for OAuth callbacks)
- A Gitea or GitHub organization/account for OAuth application registration
- Ports 80 and 443 open in firewalld, or a chosen custom port
Step 1: Install Docker and Docker Compose on RHEL 7
If Docker is not already present, install it from the Docker CE repository:
# Install required dependencies
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Add Docker CE repository
sudo yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io
# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker
# Install Docker Compose
sudo curl -L
"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)"
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
Step 2: Register an OAuth Application with Gitea or GitHub
Drone authenticates users via OAuth. You need to create an OAuth application in your source control system and note the Client ID and Client Secret.
For Gitea: Go to your Gitea instance → User Settings → Applications → OAuth2 Applications → Create. Set the redirect URI to https://drone.example.com/login.
For GitHub: Go to GitHub → Settings → Developer Settings → OAuth Apps → New OAuth App. Set the homepage URL and Authorization callback URL to https://drone.example.com/login.
Record the Client ID and Client Secret. You will also need a strong shared secret between the Drone server and its runners:
# Generate a secure shared secret
openssl rand -hex 32
# Example output: a7f3d91c8e2b456f1a2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
Step 3: Deploy the Drone Server with Docker Compose
Create a deployment directory and write a docker-compose.yml that starts both the Drone server and the Docker runner:
mkdir -p /opt/drone && cd /opt/drone
cat > docker-compose.yml <<'EOF'
version: '3.8'
services:
drone-server:
image: drone/drone:2
container_name: drone-server
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- /opt/drone/data:/data
environment:
- DRONE_GITEA_SERVER=https://gitea.example.com # or remove for GitHub
- DRONE_GITEA_CLIENT_ID=YOUR_CLIENT_ID
- DRONE_GITEA_CLIENT_SECRET=YOUR_CLIENT_SECRET
# For GitHub instead of Gitea, use:
# - DRONE_GITHUB_CLIENT_ID=YOUR_GITHUB_CLIENT_ID
# - DRONE_GITHUB_CLIENT_SECRET=YOUR_GITHUB_CLIENT_SECRET
- DRONE_RPC_SECRET=a7f3d91c8e2b456f1a2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
- DRONE_SERVER_HOST=drone.example.com
- DRONE_SERVER_PROTO=https
- DRONE_LOGS_PRETTY=true
- DRONE_LOGS_COLOR=true
drone-runner:
image: drone/drone-runner-docker:1
container_name: drone-runner
restart: always
depends_on:
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_RPC_PROTO=http
- DRONE_RPC_HOST=drone-server
- DRONE_RPC_SECRET=a7f3d91c8e2b456f1a2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
- DRONE_RUNNER_CAPACITY=4
- DRONE_RUNNER_NAME=docker-runner-01
- DRONE_LOGS_TRACE=true
EOF
Start the stack and verify both containers are healthy:
cd /opt/drone
docker-compose up -d
# Check container status
docker-compose ps
# Follow logs
docker-compose logs -f drone-server
Step 4: Open Firewall Ports on RHEL 7
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Navigate to https://drone.example.com in a browser. You will be redirected to Gitea or GitHub to authorize Drone. After authorization, you will be returned to the Drone dashboard where your repositories will be listed.
Step 5: Writing a .drone.yml Pipeline
Drone pipelines are defined in a .drone.yml file at the root of your repository. Each pipeline consists of steps that run sequentially inside Docker containers, with all steps sharing a workspace volume.
cat > .drone.yml <<'EOF'
---
kind: pipeline
type: docker
name: default
steps:
- name: install-dependencies
image: node:16-alpine
commands:
- npm ci
- name: lint
image: node:16-alpine
commands:
- npm run lint
- name: test
image: node:16-alpine
environment:
NODE_ENV: test
DATABASE_URL:
from_secret: test_db_url
commands:
- npm test
- name: build
image: node:16-alpine
commands:
- npm run build
when:
branch:
- main
- develop
- name: docker-build-push
image: plugins/docker
settings:
repo: quay.io/myorg/myapp
tags:
- latest
- ${DRONE_COMMIT_SHA:0:8}
username:
from_secret: registry_username
password:
from_secret: registry_password
when:
branch:
- main
trigger:
branch:
- main
- develop
- "feature/*"
event:
- push
- pull_request
EOF
Step 6: Using Volumes and Services in Pipelines
For integration tests that require a running database, Drone supports service containers that start alongside pipeline steps:
---
kind: pipeline
type: docker
name: integration
services:
- name: database
image: postgres:13-alpine
environment:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
steps:
- name: integration-test
image: python:3.9-alpine
environment:
DATABASE_HOST: database
DATABASE_PORT: 5432
DATABASE_NAME: testdb
DATABASE_USER: testuser
DATABASE_PASSWORD: testpass
commands:
- pip install -r requirements.txt
- python -m pytest tests/integration/
Step 7: Managing Secrets in Drone
Secrets are stored encrypted in the Drone database and injected as environment variables at runtime. Never hard-code credentials in .drone.yml.
# Install the Drone CLI
curl -L https://github.com/harness/drone-cli/releases/latest/download/drone_linux_amd64.tar.gz | tar zx
sudo mv drone /usr/local/bin/
# Configure the CLI
export DRONE_SERVER=https://drone.example.com
export DRONE_TOKEN=your_personal_access_token # from drone.example.com/account
# Create repository-level secrets
drone secret add
--repository myorg/myrepo
--name registry_username
--data "myregistryuser"
drone secret add
--repository myorg/myrepo
--name registry_password
--data "supersecretpassword"
# Create organization-level secrets (shared across repos)
drone orgsecret add myorg test_db_url "postgresql://testuser:testpass@localhost/testdb"
# List secrets
drone secret ls --repository myorg/myrepo
Step 8: Pipeline Triggers and Branch Restrictions
Trigger conditions control when a pipeline runs. You can filter by branch name, event type, commit author, file paths changed, and more:
trigger:
branch:
include:
- main
- "release/*"
exclude:
- "wip/*"
event:
include:
- push
- tag
- pull_request
target:
# Only on deployments targeting production
- production
Step 9: Self-Hosted Drone vs. Drone Cloud
Drone Cloud (cloud.drone.io) provides a free hosted tier for open-source GitHub repositories. Self-hosted Drone, as configured in this tutorial, offers complete control over your build environment — essential for proprietary code, air-gapped networks, or compliance requirements that prohibit sending source code to external services. On RHEL 7, self-hosted Drone also means you can use internally hosted Gitea instances and private container registries without any special configuration.
# Restart Drone after configuration changes
docker-compose restart drone-server
# View runner connection status
docker-compose logs drone-runner | grep "successfully pinged"
# Scale runners for more concurrent builds
docker-compose up -d --scale drone-runner=3
Conclusion
Drone CI provides a clean, container-native CI experience on RHEL 7 that scales from a single-developer setup to enterprise team deployments. The pipeline-as-code model ensures that CI configuration lives alongside your source code, making it reviewable, version-controlled, and testable. With Docker-based isolation for every step, reproducibility is guaranteed — the same pipeline that passes locally will pass in Drone. Secrets management, service containers, and fine-grained trigger conditions give you the tools to handle complex real-world workflows. As a next step, explore Drone’s cron scheduler for nightly builds, or configure matrix pipelines to test across multiple language versions simultaneously.