Self-Hosted Bitbucket Runners: A Practical Guide
Self-hosted Bitbucket runners let you run Bitbucket Pipelines builds on machines you control instead of Atlassian's cloud infrastructure. You install a small runner agent on your own server, tag it with labels, and point specific pipeline steps at it with runs-on. The payoff is real: build minutes used by self-hosted runners aren't billed against your Pipelines quota, you can use bigger machines and warmer caches, and you can reach private resources inside your own network. The one tax nobody warns you about is disk space — a busy runner quietly fills up with old caches and images until builds fail. This guide walks through the setup end to end, then shows the weekly cleanup job that keeps it healthy.

What Are Self-Hosted Bitbucket Runners?
A runner is an agent that executes your pipeline steps. With Bitbucket's cloud runners, Atlassian supplies the compute. With self-hosted runners, you supply it — a VM, an EC2 instance, a bare-metal box, or a low-cost ARM machine. The runner connects outbound to Bitbucket, polls for work that matches its labels, runs the step, and streams logs back. You never have to open an inbound port.
Bitbucket offers several runner types:
- Linux Docker (x86_64 or arm64) — the most common; each step runs in a Docker container on your host.
- Linux Shell — runs steps directly on the host shell, without Docker-in-Docker.
- Windows and macOS — for platform-specific builds (an iOS build, for example, needs macOS).
Most teams start with a Linux Docker runner because it mirrors how cloud Pipelines already behaves.
Why Run Your Own Bitbucket Runners?
Self-hosting isn't only for large enterprises. The usual reasons:
- Lower CI cost. Build minutes consumed by self-hosted runners aren't billed against your Pipelines build-minute quota — you bring your own compute. For teams with long or frequent builds, that's the headline saving.
- Bigger, faster machines. Need 16 GB of RAM, a GPU, or a large disk for a monorepo build? Size the host however you like instead of being capped by cloud step sizes.
- Warm caches and artifacts. Because the host persists between builds, dependency caches and Docker layers can stay warm, cutting build times.
- Access to private resources. A self-hosted runner can reach databases, package registries, or staging servers that live inside your own VPC or network.
- Cheaper ARM compute. Linux ARM runners let you use cost-efficient arm64 instances for compatible workloads.
Keep in mind there can be a separate per-runner or per-build-slot licensing cost on some Bitbucket plans, distinct from build minutes — check Atlassian's current runner pricing for your tier.
How Do You Set Up a Self-Hosted Bitbucket Runner?
Here's the end-to-end flow for a Linux Docker runner. Atlassian's setup guide for Linux runners covers every option, but these are the steps that matter.
1. Prepare the host. You need a 64-bit Linux machine with Docker installed and at least 8 GB of RAM (allocate a minimum of 512 MB to the runner container itself, and more for heavy builds). Atlassian also recommends disabling swap and setting vm.swappiness = 1, because swap can make builds run out of memory non-deterministically.
2. Open the runner dialog. In Bitbucket, go to your repository's Settings → Runners → Add runner (you can also add workspace-level runners that any repo can use). Under System and architecture, choose Linux Docker (x86_64) or Linux Docker (arm64).

3. Copy the command. Bitbucket generates a docker run command containing one-time OAuth credentials that authenticate this runner to your account. Treat it like a secret — don't commit it to the repo or paste it in a public channel.
4. Start the runner detached. Paste it on your host, but swap the interactive -it flags for -d and add --restart=unless-stopped so the runner survives reboots and crashes:
docker run -d --restart=unless-stopped \
-v /tmp:/tmp \
-v /var/run/docker.sock:/var/run/docker.sock \
-e ACCOUNT_UUID={your-account-uuid} \
-e RUNNER_UUID={generated-uuid} \
-e OAUTH_CLIENT_ID=*** \
-e OAUTH_CLIENT_SECRET=*** \
-e WORKING_DIRECTORY=/tmp \
--name bb-runner \
docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner:1
5. Confirm it's online. Back in the Runners list, the runner should flip to Online. It's now ready to pick up work.
How Do You Run a Pipeline Step on the Runner?
Setting up a runner doesn't move any builds onto it automatically. You opt each step in with a runs-on block in bitbucket-pipelines.yml. A runs-on list must include the self.hosted label, plus whatever labels match your runner. Bitbucket adds linux for Docker runners, linux.shell for shell runners, linux.arm64 for ARM, windows, or macos automatically:
pipelines:
default:
- step:
name: Build and test
runs-on:
- self.hosted
- linux
script:
- npm ci
- npm run build
- npm test
The scheduler sends the step to the next available runner that has all the listed labels. If no online runner matches every label, the step fails — so make sure the labels in your YAML exactly match the labels on the runner. Add a custom label such as gpu or bigdisk when you want to target one specific machine. Atlassian documents the full syntax in configuring your runner in bitbucket-pipelines.yml.
Why Does a Self-Hosted Runner Run Out of Disk Space?
This is the problem most teams hit a few weeks in — and the one we ran into ourselves. Every build clones your repository and downloads caches, artifacts, and Docker images into the runner's working directory (/tmp by default for a Linux Docker runner). Nothing automatically cleans that up. Over many builds, old caches, dangling images, and stopped containers accumulate until the host hits:
no space left on device
…and the step dies mid-pipeline. It isn't a bug — it's simply the housekeeping the cloud used to do for you.

How Do You Stop the Disk Filling Up?
The fix is a scheduled cleanup. Atlassian's own recommendation is a cron job that prunes unused Docker data on a regular schedule, and a weekly job is plenty for most teams:
# crontab -e (on the runner host)
0 0 * * 0 docker system prune -af
That runs every Sunday at midnight and removes unused images, stopped containers, networks, and build cache. If you build very frequently, run it nightly instead. For finer control, prune by age or size rather than clearing everything:
docker builder prune --keep-storage 10g --filter "until=48h" -f
A few more levers when space is tight:
- Move the working directory to a bigger disk by starting the runner with
-v /data:/data -e WORKING_DIRECTORY=/data. - Watch free space with
df -hon the host, and reviewrunner.logfor early warnings. - Right-size the disk up front — CI hosts are cheap insurance against 2 a.m. build failures.
That single weekly cron is what turns a flaky self-hosted runner into one you forget is even there.
Are Self-Hosted Bitbucket Runners Secure?
Running CI on your own hardware means you own its security too. The practices that matter most:
- Use self-hosted runners with private repositories only. On a public repo, a malicious pull request can execute arbitrary code on your runner. This is the single most important rule.
- Isolate the host. A runner shouldn't sit next to production databases or hold standing credentials to critical systems. Treat it as untrusted and give it least-privilege access.
- Prefer ephemeral or disposable hosts where you can, so every build starts clean and a compromise can't persist.
- Keep it patched. You now own OS updates, Docker updates, and runner updates — automate them.
Self-Hosted vs. Cloud Runners: Which Should You Use?
Use cloud runners when you want zero maintenance, your builds are modest, and you're comfortable within your build-minute plan. Use self-hosted runners when builds are long or frequent (cost), need lots of RAM/CPU or special hardware, must reach private network resources, or benefit from warm caches. Plenty of teams run both — cloud for simple steps, self-hosted for the heavy ones — choosing per step with runs-on. And if you'd rather not run CI infrastructure yourself at all, standing it up and keeping it healthy is exactly the kind of work our DevOps and cloud engineering team handles for clients.
Frequently Asked Questions
Do self-hosted runners use Bitbucket build minutes? No. Build minutes consumed by self-hosted runners aren't billed against your Pipelines minute quota — you supply the compute. Some plans may carry a separate per-runner or per-build-slot cost, so check current Atlassian runner pricing.
What are the requirements for a Linux Docker runner?
A 64-bit Linux host with Docker installed, at least 8 GB of RAM (512 MB or more allocated to the runner container), and ideally swap disabled with vm.swappiness = 1.
How do I send only some steps to a self-hosted runner?
Add a runs-on block containing self.hosted plus the matching labels (like linux) to those specific steps. Steps without runs-on keep using cloud runners.
Why is my self-hosted runner failing with "no space left on device"?
The working directory (/tmp by default) has filled with old caches and Docker images. Add a cron job running docker system prune -af, and/or move the working directory to a larger disk.
Can I run multiple runners on one host? Yes. You can run several runner containers on a capable host to handle parallel steps, as long as it has the RAM and disk to back them.
How do I update a self-hosted Bitbucket runner?
Pull the latest runner image and recreate the container: stop and remove the old one, then re-run your docker run command with the newest bitbucket-pipelines-runner image. The runner connects outbound and keeps no state you can't recreate, so replacing the container between builds is safe — automate a periodic pull-and-restart to stay on patched versions.
Are self-hosted runners safe for open-source repositories? Not by default. Use them with private repositories; running untrusted pull requests from public repos on your own hardware is a serious security risk.
Build Your CI/CD With Silver Hamster
Self-hosted runners are a quick win, but a fast, reliable pipeline is the difference between shipping weekly and shipping daily. Silver Hamster helps teams design CI/CD, containerise builds, and stand up the infrastructure behind real products — from custom software builds to MVPs that need to ship fast. Short-handed on DevOps? You can also augment your team with our engineers. Get in touch and we'll help you build a pipeline you don't have to babysit.