Drone needs a way to authenticate its API requests from the server to the runner.
Let’s watch this happen. Imagine you’ve just spun up a fresh Drone server and a runner. The server is humming along, but the runner is just sitting there, unassigned. You check the runner’s logs, and it’s complaining it can’t connect to the server. It’s like a shy person at a party, wanting to join in but not having the courage (or the password) to approach the host.
# On the runner machine, tail the logs
sudo journalctl -u drone-runner -f
You’ll see something like this:
{"arch":"amd64","commit":"abcdef1234567890","level":"fatal","msg":"rpc: dial tcp [::1]:8080: connect: connection refused","os":"linux","time":"2023-10-27T10:00:00Z","version":"2.0.0"}
Or if you’re using the Docker image:
{"arch":"amd64","commit":"abcdef1234567890","level":"fatal","msg":"rpc: dial tcp 127.0.0.1:8080: connect: connection refused","os":"linux","time":"2023-10-27T10:00:00Z","version":"2.0.0"}
This connection refused is the core of the problem. The runner is trying to talk to the Drone server at [::1]:8080 (or 127.0.0.1:8080), which is the default RPC address for the server, but it’s not getting a response. It’s not that the server is down, but rather that it’s not configured to listen for these specific RPC connections from runners.
The magic word here is DRONE_RPC_SECRET. This is a shared secret, a password of sorts, that both the Drone server and the runner must know. When the runner tries to connect to the server, it presents this secret. If the server recognizes the secret, it allows the connection and starts assigning pipelines to the runner. Without it, the server just ignores the runner’s pleas.
Here’s how you set it up, step-by-step.
1. Generate a Strong Secret
First, you need a secret. Don’t use password123. Use something strong and random. You can generate one on Linux/macOS with:
openssl rand -hex 32
This will give you a string like a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890. Copy this.
2. Configure the Drone Server
You need to tell the Drone server what secret to expect. If you’re running Drone via Docker Compose, you’ll add this to your docker-compose.yml file:
version: '3.8'
services:
drone:
image: drone/drone:2.24.0 # Use your desired version
ports:
- 80:80
- 443:443
volumes:
- drone_data:/var/lib/drone/
restart: always
environment:
- DRONE_SERVER_HOST=your.drone.domain.com # Replace with your actual domain
- DRONE_SERVER_PROTO=https # Or http if you're not using SSL
- DRONE_GITHUB=true # Or DRONE_GITLAB, DRONE_BITBUCKET
- DRONE_GITHUB_CLIENT_ID=YOUR_GITHUB_CLIENT_ID
- DRONE_GITHUB_CLIENT_SECRET=YOUR_GITHUB_CLIENT_SECRET
- DRONE_SECRET=YOUR_LONG_RANDOM_SECRET_FOR_SERVER_COOKIE # Different from RPC secret
- DRONE_RPC_SECRET=YOUR_GENERATED_RPC_SECRET # <<< ADD THIS LINE
networks:
- drone
volumes:
drone_data:
networks:
drone:
Replace YOUR_GENERATED_RPC_SECRET with the hex string you generated in step 1.
If you’re running Drone directly on a host, you’ll pass this as an environment variable:
export DRONE_RPC_SECRET=YOUR_GENERATED_RPC_SECRET
drone-server
After updating the server configuration, restart the Drone server container or process.
# If using Docker Compose
docker-compose up -d --force-recreate drone
3. Configure the Drone Runner
Now, tell the runner which secret to use. If you’re using the Docker Compose runner, update its docker-compose.yml:
version: '3.8'
services:
drone-runner-docker:
image: drone/runner-docker:1.10.0 # Use your desired version
ports:
- 3000:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always
environment:
- DRONE_RPC_PROTO=http # Or https if your server uses SSL for RPC
- DRONE_RPC_ADDR=drone:3000 # If runner and server are on the same Docker network, use the service name. Otherwise, use the server's IP/domain and port.
- DRONE_RPC_SECRET=YOUR_GENERATED_RPC_SECRET # <<< ADD THIS LINE
- DRONE_RUNNER_CAPACITY=2 # Example capacity
- DRONE_RUNNER_NAME=my-docker-runner # Example name
networks:
- drone
networks:
drone:
Crucially, you need to set DRONE_RPC_SECRET here to the exact same value you used for the server.
If you’re running the runner directly on a host:
export DRONE_RPC_PROTO=http
export DRONE_RPC_ADDR=your.drone.domain.com:80 # Or the correct IP/port
export DRONE_RPC_SECRET=YOUR_GENERATED_RPC_SECRET
drone-runner exec
Important Note on DRONE_RPC_ADDR:
- If your Drone server and runner are on the same Docker network (like in the
docker-compose.ymlexamples above, sharing thedronenetwork), you can often use the Drone server’s service name (drone) and its internal RPC port (usually3000for the runner to connect to, not80or443which are for external web access). - If your runner is running outside the Docker network of the server, or on a different host, you must use the server’s publicly accessible IP address or domain name and the correct RPC port. The default RPC port the runner connects to is
3000. So,DRONE_RPC_ADDR=your.drone.domain.com:3000. - If your Drone server is configured with
DRONE_SERVER_PROTO=https, you should setDRONE_RPC_PROTO=httpson the runner. Otherwise, usehttp.
After updating the runner configuration, restart the runner container or process.
# If using Docker Compose
docker-compose up -d --force-recreate drone-runner-docker
Why it Works
The DRONE_RPC_SECRET acts as a pre-shared key. When the runner starts, it sends an RPC request to the Drone server’s RPC endpoint (defaulting to [::1]:3000 or 127.0.0.1:3000 if not specified, or whatever DRONE_RPC_ADDR is set to). This request includes the DRONE_RPC_SECRET in its headers. The Drone server receives this request, checks if the provided secret matches its own DRONE_RPC_SECRET configuration. If they match, the server trusts the runner and registers it. If they don’t match, the server rejects the connection, leading to the connection refused or similar authentication errors in the runner logs.
What’s Next?
Once the runner is connected, you’ll likely encounter the next common hurdle: the runner not having the necessary permissions or configurations to build your specific pipeline. This often manifests as build failures with messages about missing Docker daemons, unprivileged containers, or network access issues.