Private CI using private docker registry with Drone.io (almost free)

fuksito profile image Vitaliy Yanchuk ・3 min read

Develop Privately (2 Part Series)

1) How to setup private docker registry for your projects to save money 2) Private CI using private docker registry with Drone.io (almost free)

In previous post I have described how you can set up your own private docker registry for your secret projects, now we want to add CI to this setup.

Currently I host both on single 5$ VPS, which is decent price, considering amount I would need to pay DockerHub for same number of private docker images and for private TravisCI which costs 69$/month for 1 Concurrent job, which they advertise as "IDEAL FOR HOBBY PROJECTS", well not for 69$ for sure.


Consider you have a domain example.com, and want to have CI on drone.example.com and private registry on registry.example.com

Setting up Drone

Drone requires that you use some external authentication provider, which is actually convenient, I would use GitHub as authentication provider. Also this way drone will import my private repositories on GitHub.

You should check official docs on how to get required credentials if you want to use GitHub as well:

The official doc shows only example how to start Drone with docker run, but I prefer to put it in the docker-compose.yml file, so it is easier to start/restart.

So the combined docker-compose.yml, including Drone and private docker registry would look like:

version: "3"
    image: drone/drone
      - "1080:80"
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/drone:/data
      - DRONE_USER_FILTER=your_user
      - DRONE_GITHUB_SERVER=https://github.com
      - DRONE_GITHUB_CLIENT_ID=<your id>
      - DRONE_GITHUB_CLIENT_SECRET=<your secret>
      - DRONE_SERVER_HOST=drone.example.com
    restart: always
    image: 'registry:2'
      - "5000:5000"
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      - /root/docker-volumes/registry/registry:/var/lib/registry
      - /root/docker-volumes/auth:/auth

Note important environment variable:
DRONE_USER_FILTER - only this user will be able to use your drone, you should limit it to your user so no other person can use your Drone.
DRONE_SERVER_HOST - the domain you have used to create OAuth authentication

Running specs

In order to make Drone run specs for your repo you need to add special file to your project .drone.yml

kind: pipeline
name: default

- name: test
  image: registry.example.com/rails_api
  - bundle exec rspec
    RAILS_ENV: 'test'
    REDIS_URL: redis://redis:6379/
    DATABASE_URL: postgres://postgres:@db/ourcodestyle_test
- name: db
  image: 'postgres:11.1-alpine'
  - 5432
    POSTGRES_USER: postgres
    POSTGRES_DB: rails_api_test
- name: redis
  image: 'redis:3.2-alpine'
  - 6379

- dockerconfigjson

There is several interesting parts in this file:

image: registry.example.com/rails_api
This way you specify which private docker image you would want your build to start. I have this image with all ruby gems already installed, so it dramatically reduces time before tests start to run.

Also note services section. Drone configuration mimics docker compose syntax so it is easy to configure.

The most important config line is the last one:

- dockerconfigjson

And it is not well described in the official docs. This setting says how Drone should get credentials for you private repository. You need to have a file /root/.docker/config.json on the machine where you run Drone. I did not have this file in place. You can create this file by yourself, or there is much easier way, just run:

docker login registry.example.com -u testuser

on the machine which would run Drone and it would create that file.

Domain for Drone

In order to share same server, your drone should have its subdomain, and also it is convenient and nice.

It can be done by adding nginx configuration like this:

upstream drone {

server {
    server_name drone.example.com;

    access_log /var/log/nginx/drone.example.com.access.log combined;
    error_log  /var/log/nginx/drone.example.com.error.log crit;

    server_name_in_redirect off;

    location / {
      proxy_pass                          http://drone;
      proxy_set_header  Host              $http_host;   # required for docker client's sake
      proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
      proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Proto $scheme;
      proxy_read_timeout                  900;

    listen 80;

Then don't forget to run CertBot in order to get https

certbot --nginx -d drone.example.com

Develop Privately (2 Part Series)

1) How to setup private docker registry for your projects to save money 2) Private CI using private docker registry with Drone.io (almost free)

Posted on by:

fuksito profile

Vitaliy Yanchuk


Started dev 10+ years ago with Perl and JavaScript, switched to Ruby 8 years ago, and love it still. Now really into ReactJS, GraphQL and Automation


markdown guide