Install Drone CI CD Pipeline on VPS

Install Drone CI CD Pipeline on VPS

June 2026 · 8 min read

Drone CI is a container-native continuous integration and continuous deployment (CI/CD) platform that is easy to use and highly flexible. It supports integration with GitHub, GitLab, Gitea, and Bitbucket, making it a popular choice for automating build, test, and deploy processes. In this guide, we'll walk you through installing Drone CI on a self-hosted VPS with Docker runner configuration to execute your pipelines effectively.

System Requirements

Before installing Drone CI, ensure your VPS meets the following requirements:

Install Docker and Docker Compose

Since Drone CI runs on Docker, you must install Docker first. If you don't have Docker installed, run the following commands:

For Ubuntu/Debian:

sudo apt-get update
sudo apt-get install -y docker.io docker-compose
sudo usermod -aG docker $USER
newgrp docker

For CentOS/RHEL 7:

sudo yum install -y docker
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo systemctl start docker
sudo usermod -aG docker $USER

For CentOS/RHEL 8+:

sudo dnf install -y docker podman-docker
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo systemctl start docker
sudo usermod -aG docker $USER

Verify Docker is working correctly:

docker --version
docker-compose --version
docker run hello-world

Download and Install Drone Server

Create a directory for Drone server and prepare the docker-compose configuration file:

mkdir -p ~/drone-ci
cd ~/drone-ci

Create docker-compose.yml with the following content:

cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  drone-server:
    image: drone/drone:latest
    container_name: drone-server
    ports:
      - "80:80"
      - "443:443"
    environment:
      DRONE_SERVER_HOST: ci.yourdomain.com
      DRONE_SERVER_PROTO: https
      DRONE_RPC_SECRET: $(openssl rand -hex 16)
      DRONE_GITHUB_CLIENT_ID: your_github_client_id
      DRONE_GITHUB_CLIENT_SECRET: your_github_client_secret
      DRONE_AGENTS_ENABLED: true
      DRONE_USER_CREATE: username:admin,machine:false,admin:true
    volumes:
      - ./data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always

  drone-runner:
    image: drone/drone-runner-docker:latest
    container_name: drone-runner
    depends_on:
      - drone-server
    environment:
      DRONE_RPC_HOST: drone-server
      DRONE_RPC_PROTO: http
      DRONE_RPC_SECRET: $(openssl rand -hex 16)
      DRONE_RUNNER_CAPACITY: 2
      DRONE_RUNNER_NAME: runner-1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always
    networks:
      - drone-network

networks:
  drone-network:
    driver: bridge
EOF
Important: Replace ci.yourdomain.com with your actual domain and add your GitHub OAuth credentials to the configuration.

Configure Drone Server with GitHub

To connect Drone with GitHub, you need to create an OAuth application:

  1. Go to GitHub Settings › Developer settings › OAuth Apps
  2. Click "New OAuth App"
  3. Fill in the following information:
    • Application name: Drone CI
    • Homepage URL: https://ci.yourdomain.com
    • Authorization callback URL: https://ci.yourdomain.com/login/oauth/github
  4. Click "Register application" to receive Client ID and Client Secret

Add the Client ID and Client Secret to your docker-compose.yml:

DRONE_GITHUB_CLIENT_ID: [your-github-client-id]
DRONE_GITHUB_CLIENT_SECRET: [your-github-client-secret]

For integration with Gitea, replace the environment variables with:

DRONE_GITEA_SERVER: https://gitea.yourdomain.com
DRONE_GITEA_CLIENT_ID: your_gitea_client_id
DRONE_GITEA_CLIENT_SECRET: your_gitea_client_secret

Start Drone Services

Once you've configured the docker-compose.yml file, start the services:

cd ~/drone-ci
docker-compose up -d

Verify that the containers are running:

docker-compose ps
docker logs drone-server
docker logs drone-runner

Install Drone Runner

The Drone Runner is the agent responsible for executing pipeline jobs. If you used the docker-compose setup above, the runner is already installed. However, if you need to install a runner on a separate machine, follow these steps:

mkdir -p ~/drone-runner
cd ~/drone-runner

cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  drone-runner:
    image: drone/drone-runner-docker:latest
    container_name: drone-runner
    environment:
      DRONE_RPC_HOST: drone-server-ip:80
      DRONE_RPC_PROTO: http
      DRONE_RPC_SECRET: your-rpc-secret-here
      DRONE_RUNNER_CAPACITY: 2
      DRONE_RUNNER_NAME: runner-remote-1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always
EOF

docker-compose up -d
Critical: The DRONE_RPC_SECRET must match exactly between the drone-server and drone-runner for them to communicate properly.

Create .drone.yml Pipeline Configuration

In your repository root, create a .drone.yml file to define your pipeline steps:

kind: pipeline
type: docker
name: default

steps:
  - name: test
    image: node:16
    commands:
      - npm install
      - npm run test

  - name: build
    image: node:16
    commands:
      - npm run build

  - name: deploy
    image: alpine:latest
    commands:
      - echo "Deploying to production..."
      - apk add --no-cache curl
      - curl -X POST https://deploy.yourdomain.com/webhook

trigger:
  branch:
    - main
  event:
    - push
    - pull_request

Here's a more advanced pipeline example with multiple steps and conditions:

kind: pipeline
type: docker
name: full-pipeline

steps:
  - name: checkout
    image: alpine/git
    commands:
      - git clone $DRONE_GIT_HTTP_URL .
      - git checkout $DRONE_COMMIT

  - name: lint
    image: node:16
    commands:
      - npm install
      - npm run lint

  - name: unit-tests
    image: node:16
    commands:
      - npm test

  - name: build-image
    image: plugins/docker
    settings:
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password
      repo: your-docker-repo/app
      tags: latest,${DRONE_COMMIT_SHA:0:7}

  - name: deploy-staging
    image: alpine:latest
    environment:
      DEPLOY_TOKEN:
        from_secret: deploy_token
    commands:
      - apk add --no-cache curl
      - curl -X POST https://staging-deploy.yourdomain.com/webhook -d "token=$DEPLOY_TOKEN"
    when:
      branch: main
      event: push

  - name: notify
    image: plugins/slack
    settings:
      webhook:
        from_secret: slack_webhook
      message: "Pipeline completed for $${DRONE_BRANCH}"
    when:
      status:
        - success
        - failure

trigger:
  branch:
    - main
    - develop
  event:
    - push
    - pull_request
    - tag

Verify Drone is Working

Once installation is complete, verify that Drone is functioning correctly using the following commands:

Check Drone Server API:

curl -s http://localhost/api/version | jq .

Expected output:

{
  "version": "2.11.0"
}

Check Docker Logs:

docker logs drone-server | tail -20
docker logs drone-runner | tail -20

Access Web Interface:

Open your browser and navigate to https://ci.yourdomain.com, then log in using your GitHub or Gitea account.

Test Pipeline:

cd /path/to/your-repo
git add .drone.yml
git commit -m "Add Drone CI configuration"
git push origin main

Go to the Drone web UI and verify that the pipeline triggers automatically when you push code.

Tip: To view pipeline logs while running, click the build number in the Drone UI to see real-time execution details.

Troubleshooting Common Issues

Error: DRONE_RPC_SECRET Mismatch

If drone-runner cannot connect to drone-server, the logs will show:

ERROR client: 401 Unauthorized: invalid rpc secret

Solution: Ensure that DRONE_RPC_SECRET in both the server and runner docker-compose.yml files are identical. Both services must use the same secret value to communicate.

Error: GitHub OAuth Not Working

If you encounter OAuth authentication errors, check the logs:

docker logs drone-server | grep -i "oauth\|auth\|github"

Solution: Verify that the Client ID and Client Secret are correct and match those in GitHub Developer Settings. Additionally, ensure the Authorization callback URL is exactly https://ci.yourdomain.com/login/oauth/github

Error: Pipeline Not Triggering

If you've created a .drone.yml file and pushed code but the pipeline doesn't trigger, check:

docker logs drone-server | grep webhook
docker logs drone-server | grep trigger

Solution: Go to your GitHub repository Settings › Webhooks and verify that a Drone webhook exists. If not, perform a re-sync in the Drone UI by navigating to repository settings and clicking "Sync".

Error: Docker Image Pull Timeout

If the pipeline fails with an error like:

Error response from daemon: pull access denied for node:16, repository does not exist

Solution: Check your VPS internet connectivity to ensure it can pull Docker images. Test this manually with:

docker pull node:16

Frequently Asked Questions

Can I use Drone CI with multiple repositories simultaneously?

Yes, Drone CI supports multiple repositories. However, the number of jobs that can run concurrently depends on the DRONE_RUNNER_CAPACITY setting. If set to 2, only 2 jobs can execute in parallel. To handle more concurrent jobs, either increase this value or add additional runners.

How do I secure Drone CI with HTTPS and Let's Encrypt SSL?

You can use a reverse proxy like Nginx or Caddy to terminate SSL. Here's an example using Caddy:

cat > ~/drone-ci/Caddyfile << 'EOF'
ci.yourdomain.com {
    reverse_proxy localhost:80
}
EOF

Then add Caddy as a service in your docker-compose.yml file.

How do I connect Drone CI to a self-hosted Git server like Gitea?

Replace the GitHub environment variables with these Gitea settings:

DRONE_GITEA_SERVER: https://gitea.yourdomain.com
DRONE_GITEA_CLIENT_ID: [your-gitea-oauth-client-id]
DRONE_GITEA_CLIENT_SECRET: [your-gitea-oauth-client-secret]

To create an OAuth application in Gitea, navigate to Admin › Applications › Create OAuth 2.0 Application and follow a similar process to GitHub.