Drone CI is a lightweight, container-native continuous integration platform that runs every pipeline step inside an isolated Docker container. Its pipeline definition lives entirely in a .drone.yml file committed alongside your source code, making pipelines version-controlled and reproducible by default. In this tutorial you will install Docker CE on RHEL 8, deploy a Drone Server connected to GitHub OAuth, deploy a Drone Docker Runner, write your first .drone.yml pipeline, and connect a GitHub repository to start running automated builds.

Prerequisites

  • RHEL 8 server with a public IP or domain name (Drone Server requires an externally reachable callback URL for OAuth)
  • sudo privileges on the server
  • A GitHub account with permissions to register an OAuth application
  • Port 80 (or 443 for TLS) open in the firewall
  • Basic Docker familiarity

Step 1 — Install Docker CE on RHEL 8

RHEL 8 does not ship Docker CE in its default repositories. Add the official Docker repository and install the engine.

sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io

sudo systemctl enable --now docker

# Allow your user to run Docker without sudo
sudo usermod -aG docker $USER
newgrp docker

docker --version

Step 2 — Register a GitHub OAuth Application

Drone uses GitHub OAuth to authenticate users and receive webhook events. Create the OAuth app in your GitHub account settings before starting the server.

# Navigate in your browser to:
# GitHub → Settings → Developer settings → OAuth Apps → New OAuth App
#
# Fill in the fields:
#   Application name:    Drone CI
#   Homepage URL:        http://YOUR_SERVER_IP
#   Authorization callback URL: http://YOUR_SERVER_IP/login
#
# After saving, GitHub shows you:
#   Client ID:     (copy this → DRONE_GITHUB_CLIENT_ID)
#   Client Secret: (generate and copy → DRONE_GITHUB_CLIENT_SECRET)
#
# Also generate a shared secret for Drone internal RPC:
openssl rand -hex 16
# Save the output → DRONE_RPC_SECRET

Step 3 — Run the Drone Server Container

The Drone Server handles the web UI, user authentication, repository syncing, and pipeline orchestration. Run it as a Docker container, passing all configuration via environment variables.

docker run 
  --volume=/var/lib/drone:/data 
  --env=DRONE_GITHUB_CLIENT_ID=YOUR_CLIENT_ID 
  --env=DRONE_GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET 
  --env=DRONE_RPC_SECRET=YOUR_RPC_SECRET 
  --env=DRONE_SERVER_HOST=YOUR_SERVER_IP 
  --env=DRONE_SERVER_PROTO=http 
  --env=DRONE_LOGS_PRETTY=true 
  --env=DRONE_LOGS_COLOR=true 
  --publish=80:80 
  --publish=443:443 
  --restart=always 
  --detach=true 
  --name=drone 
  drone/drone:2

# Verify the server is running
docker ps
docker logs drone

Open http://YOUR_SERVER_IP in a browser. You should be redirected to GitHub for authorization. After approving, you land on the Drone dashboard.

Step 4 — Run the Drone Docker Runner

The Drone Runner polls the server for pending pipeline jobs and executes each step inside a Docker container. It needs access to the host Docker socket so it can spawn step containers.

docker run 
  --volume=/var/run/docker.sock:/var/run/docker.sock 
  --env=DRONE_RPC_PROTO=http 
  --env=DRONE_RPC_HOST=YOUR_SERVER_IP 
  --env=DRONE_RPC_SECRET=YOUR_RPC_SECRET 
  --env=DRONE_RUNNER_CAPACITY=2 
  --env=DRONE_RUNNER_NAME=rhel8-runner 
  --publish=3000:3000 
  --restart=always 
  --detach=true 
  --name=drone-runner 
  drone/drone-runner-docker:1

# Confirm the runner connected to the server
docker logs drone-runner | grep "successfully pinged"

Step 5 — Write a .drone.yml Pipeline

The .drone.yml file lives at the root of your repository. Each step runs inside its own Docker container; steps share the workspace volume so artifacts from one step are available to the next.

cat > .drone.yml << 'EOF'
kind: pipeline
type: docker
name: default

steps:
  - name: install-deps
    image: python:3.11-slim
    commands:
      - pip install -r requirements.txt

  - name: lint
    image: python:3.11-slim
    commands:
      - pip install flake8
      - flake8 src/

  - name: test
    image: python:3.11-slim
    commands:
      - pip install -r requirements.txt
      - python -m pytest tests/ -v

  - name: build-image
    image: plugins/docker
    settings:
      repo: YOUR_DOCKERHUB_USERNAME/myapp
      tags:
        - latest
        - ${DRONE_COMMIT_SHA:0:8}
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password

trigger:
  branch:
    - main
EOF

Step 6 — Activate the Repository and Trigger a Build

Activate the repository in the Drone UI so Drone registers a webhook on GitHub. Then push a commit to trigger the pipeline.

# In the Drone web UI:
# 1. Click "Sync" to refresh your repository list from GitHub
# 2. Find your repository and click "Activate"
# 3. Add secrets (docker_username, docker_password) under Repository → Settings → Secrets

# From your workstation — commit and push the pipeline file
git add .drone.yml
git commit -m "ci: add Drone pipeline"
git push origin main

# Watch the build in the Drone UI at http://YOUR_SERVER_IP
# Or tail the runner logs
docker logs -f drone-runner

Conclusion

You have installed Docker CE on RHEL 8, deployed a Drone Server and Docker Runner as containers, connected them to a GitHub OAuth application, and defined a complete CI/CD pipeline in a .drone.yml file that installs dependencies, lints, tests, and builds a Docker image on every push to main. Because every pipeline step runs inside a dedicated Docker container, builds are fully isolated, reproducible, and easy to debug locally by running the same images by hand. The entire Drone stack — server, runner, and pipelines — is defined in code and can be version-controlled alongside your application.

Next steps: Adding TLS to Drone CI with Let’s Encrypt on RHEL 8, Configuring Drone CI with Gitea for a Fully Self-Hosted Git and CI Stack, and Publishing Test Coverage Reports from Drone CI Pipelines.