Why Drone CI?
Drone CI is a modern, container-native continuous integration and continuous delivery (CI/CD) platform. Built on Docker, it provides a lightweight, scalable solution for automating your build, test, and deployment workflows.
Introduction
Architecture Overview
Drone consists of two main components:
- Drone Server: Handles webhooks from your Git provider, manages the web UI, and coordinates pipeline execution.
- Drone Runner: Executes the actual pipeline steps. Runners poll the server for work and can be deployed on the same or separate machines.
Note: This guide covers deploying Drone with the Docker runner, which executes pipeline steps inside Docker containers.
Prerequisites
VPS Requirements
- • OS: Ubuntu 22.04/24.04 LTS
- • RAM: 2 GB minimum (4 GB recommended)
- • Storage: 20 GB SSD
- • CPU: 2 vCPUs minimum
Network Requirements
- • Domain name (e.g., ci.yourdomain.com)
- • Open ports: 80 (HTTP), 443 (HTTPS)
- • Static IPv4 address
- • SSH access to server
Server Preparation
Step 1: Update System Packages
Connect to your RamNode VPS via SSH and update the system:
sudo apt update && sudo apt upgrade -yStep 2: Set System Hostname
sudo hostnamectl set-hostname ci.yourdomain.comStep 3: Configure Firewall
Install and configure UFW:
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableStep 4: Create Dedicated User (Optional)
For security, create a dedicated user for running Drone:
sudo adduser drone
sudo usermod -aG docker droneNote: Add the user to the docker group after installing Docker in the next section.
Installing Docker
Drone requires Docker to run both the server and execute pipeline containers.
Step 1: Install Docker Engine
# Install prerequisites
sudo apt install ca-certificates curl gnupg -y
# Add Docker GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add Docker repository
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin -yStep 2: Configure Non-Root Access
sudo usermod -aG docker $USER
newgrp dockerStep 3: Verify Installation
docker --version
docker run hello-worldGit Provider Integration
Drone requires OAuth credentials from your Git provider to authenticate users and receive webhooks.
GitHub Integration
Step 1: Create OAuth Application
Navigate to GitHub Settings → Developer settings → OAuth Apps → New OAuth App
- • Application name: Drone CI
- • Homepage URL: https://ci.yourdomain.com
- • Authorization callback URL: https://ci.yourdomain.com/login
Step 2: Save Credentials
Note the Client ID and generate a Client Secret.
Warning: Store credentials securely. The client secret is only shown once.
GitLab Integration
Navigate to User Settings → Applications → Add new application
- • Name: Drone CI
- • Redirect URI: https://ci.yourdomain.com/login
- • Scopes: Select
apiandread_user
Gitea Integration
Navigate to Settings → Applications → Create a new OAuth2 Application
Redirect URI: https://ci.yourdomain.com/login
Deploying Drone Server
Step 1: Create Directory Structure
sudo mkdir -p /opt/drone
sudo mkdir -p /opt/drone/data
cd /opt/droneStep 2: Generate Shared Secret
Generate a shared secret for communication between the server and runners:
openssl rand -hex 16Save this value for use in both server and runner configurations.
Step 3: Create Docker Compose File
# /opt/drone/docker-compose.yml
version: '3.8'
services:
drone-server:
image: drone/drone:2
container_name: drone-server
restart: always
ports:
- '8080:80'
volumes:
- ./data:/data
environment:
# Server Configuration
- DRONE_SERVER_HOST=ci.yourdomain.com
- DRONE_SERVER_PROTO=https
- DRONE_DATABASE_DRIVER=sqlite3
- DRONE_DATABASE_DATASOURCE=/data/database.sqlite
# GitHub Configuration (use GitLab vars for GitLab)
- DRONE_GITHUB_CLIENT_ID=your_client_id
- DRONE_GITHUB_CLIENT_SECRET=your_client_secret
# Security
- DRONE_RPC_SECRET=your_shared_secret_here
- DRONE_USER_CREATE=username:yourgithubusername,admin:true
# Logging
- DRONE_LOGS_DEBUG=false
- DRONE_LOGS_TRACE=falseImportant: Replace placeholder values with your actual OAuth credentials and shared secret.
GitLab Configuration Variant
For GitLab, use these environment variables instead:
- DRONE_GITLAB_SERVER=https://gitlab.com
- DRONE_GITLAB_CLIENT_ID=your_application_id
- DRONE_GITLAB_CLIENT_SECRET=your_secretStep 4: Start Drone Server
docker compose up -d drone-server
docker compose logs -f drone-serverDeploying Drone Runner
The Docker runner executes pipeline steps inside containers.
Step 1: Add Runner to Docker Compose
Append the runner service to your docker-compose.yml:
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=your_shared_secret_here
- DRONE_RUNNER_CAPACITY=2
- DRONE_RUNNER_NAME=drone-runner-1
- DRONE_RUNNER_NETWORKS=drone_defaultConfiguration Options
DRONE_RUNNER_CAPACITY– Number of concurrent pipelines (default: 2)DRONE_RUNNER_NAME– Unique identifier for this runnerDRONE_RPC_SECRET– Must match server's RPC secret
Step 2: Start the Runner
docker compose up -d
docker compose logs -f drone-runnerNginx Reverse Proxy with SSL
Step 1: Install Nginx and Certbot
sudo apt install nginx certbot python3-certbot-nginx -yStep 2: Create Nginx Configuration
# /etc/nginx/sites-available/drone
server {
listen 80;
server_name ci.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support for real-time logs
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
# Timeouts for long-running builds
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
}Step 3: Enable Site and Obtain SSL
sudo ln -s /etc/nginx/sites-available/drone /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# Obtain SSL certificate
sudo certbot --nginx -d ci.yourdomain.comStep 4: Verify SSL Auto-Renewal
sudo certbot renew --dry-runCreating Your First Pipeline
Drone pipelines are defined in a .drone.yml file at the root of your repository.
Basic Pipeline Example
kind: pipeline
type: docker
name: default
steps:
- name: test
image: node:20-alpine
commands:
- npm ci
- npm test
- name: build
image: node:20-alpine
commands:
- npm run build
depends_on:
- testPipeline with Secrets
Store sensitive values as secrets in the Drone UI, then reference them:
steps:
- name: deploy
image: alpine
environment:
SSH_KEY:
from_secret: deploy_ssh_key
commands:
- echo "$SSH_KEY" > /tmp/key
- chmod 600 /tmp/key
- ssh -i /tmp/key user@server 'deploy.sh'Conditional Execution
Run steps only on specific branches or events:
steps:
- name: deploy-production
image: alpine
commands:
- ./deploy.sh production
when:
branch:
- main
event:
- pushActivate Repository
- Log in to Drone at https://ci.yourdomain.com
- Click "Sync" to fetch your repositories
- Find your repository and click "Activate"
- Push a commit or create a pull request to trigger your first build
Security Best Practices
Restrict Admin Access
Limit admin users by setting DRONE_USER_CREATE:
DRONE_USER_CREATE=username:admin_user,admin:trueEnable Repository Filtering
Restrict which organizations or users can activate repositories:
DRONE_USER_FILTER=your-org,trusted-userSecrets Management
- Use Drone's built-in secrets: Never commit sensitive values to .drone.yml
- Limit secret scope: Restrict secrets to specific repositories or events
- Rotate secrets regularly: Update OAuth credentials and RPC secrets periodically
Resource Limits
Prevent resource exhaustion by adding limits:
services:
drone-runner:
deploy:
resources:
limits:
cpus: '2'
memory: 2GMaintenance and Troubleshooting
Common Issues
Runner Not Connecting
Verify the RPC secret matches between server and runner:
docker compose logs drone-server | grep -i secret
docker compose logs drone-runner | grep -i rpcOAuth Callback Errors
Ensure your callback URL exactly matches your Git provider configuration. Check for missing trailing slashes, incorrect protocol, or typos.
Webhooks Not Triggering
Check webhook delivery in your Git provider's settings. Verify the webhook URL is reachable and the repository is activated.
Useful Commands
# View all logs
docker compose logs -f
# Restart services
docker compose restart
# Update to latest version
docker compose pull
docker compose up -d
# Check container status
docker compose ps
# Access Drone server shell
docker compose exec drone-server shBackup Database
# Stop server before backup
docker compose stop drone-server
# Create backup
cp /opt/drone/data/database.sqlite /backup/drone-$(date +%Y%m%d).sqlite
# Restart server
docker compose start drone-serverLog Rotation
Configure log rotation to prevent disk space issues:
services:
drone-server:
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '3'Deployment Complete!
Your Drone CI installation is now ready. Access the web interface at your configured domain, authenticate with your Git provider, and start automating your builds!
