Buildfarm
Overview
Bazel Buildfarm is an open-source remote build cache and remote execution service that implements Bazel's Remote Execution API (REAPI). When your Bazel builds point at the farm, build actions are cached centrally and executed on the farm's worker instead of on every developer machine and CI runner. A shared cache and offloaded compilation make incremental builds faster and CI cheaper and more consistent.
The SecureAnyCloud image delivers a complete single-node farm, fully installed and wired together, so a working Remote Execution endpoint is reachable within minutes of launch. Buildfarm is a gRPC API service with no web UI. You drive it from Bazel by pointing --remote_executor and --remote_cache at it. This guide uses the bazel client (through bazelisk) to demonstrate a real build offloaded to the farm.
What you get:
- Bazel Buildfarm (verified at 2.17.1) as the official
buildfarm-serverandbuildfarm-workercontainer images, run under systemd - A Redis SHARD backplane, bound to loopback and protected by a per-VM secret. Buildfarm 2.x is a sharded architecture, so it needs a Redis backplane that holds the content-addressable storage, the action cache and the execution queue
buildfarm-server.serviceexposing the Remote Execution API on:8980, the endpoint your clients dial, andbuildfarm-worker.serviceexecuting actions on:8981- No default secret. A unique backplane secret is generated on each VM's first boot and written to a root-only file. Redis is bound to the loopback interface and protected by that secret. No two VMs share a credential, and none is baked into the image
buildfarm-firstboot.service, which mints the per-VM backplane secret, renders the config and writes the fail-secure bootstrap marker- Fail secure. The server and worker both carry a bootstrap gate that clears only after first boot has minted the per-VM secret and rendered the configuration. If first boot were interrupted, the farm would not serve, rather than coming up with a build-time or default secret
- A firewall guard that keeps the internal worker port and the backplane off the public network while leaving the server endpoint your build fleet uses reachable
- Ubuntu 24.04 LTS base, patched at build time, with a swapfile sized for the two JVMs and Redis
- 24/7 SecureAnyCloud support with a 24-hour response SLA
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet.
The recommended VM size is Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small teams. Choose Standard_D4s_v5 or larger for busy CI fleets that run many parallel actions. The worker executes actions on the node, so more vCPU and RAM directly raise how much work the farm can run at once.
Deploy from the Azure Portal
Search the Marketplace for Bazel Buildfarm on Ubuntu 24.04 and choose your VM size.
Attach a network security group (NSG) that allows TCP 22 (SSH) from your management network and TCP 8980 (the Remote Execution endpoint) from the build and CI machines that will use the farm.
Clients need to reach only the server port 8980. The worker port 8981 and the Redis backplane are internal, and the built-in firewall guard keeps them off the public network.
Deploy from the Azure CLI
RG="buildfarm-prod"; LOCATION="eastus"; VM_NAME="buildfarm-01" IMAGE_URN="sac1647283583153:buildfarm-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name bf-vnet --address-prefix 10.90.0.0/16 --subnet-name bf-subnet --subnet-prefix 10.90.1.0/24 az network nsg create -g "$RG" --name bf-nsg az network nsg rule create -g "$RG" --nsg-name bf-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name bf-nsg --name allow-farm --priority 110 \
--source-address-prefixes "<your-build-cidr>" --destination-port-ranges 8980 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:buildfarm-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name bf-vnet --subnet bf-subnet --nsg bf-nsg --public-ip-sku StandardConnect via SSH
ssh azureuser@<vm-ip>Verify the services and listeners
The farm is three services: the Redis backplane, the Buildfarm server on :8980, and the Buildfarm worker on :8981. Confirm that all three are active, that the server and worker are listening, and that the loopback backplane requires the per-VM secret.
sudo systemctl is-active redis-server buildfarm-server buildfarm-worker ss -tln | grep -E ':8980|:8981' echo "redis (no credential) -> $(redis-cli -h 127.0.0.1 ping 2>&1)"You should see all three services active and listeners on 8980 and 8981. The unauthenticated Redis ping returns NOAUTH Authentication required, which confirms that the backplane is protected.
Run a real build on the farm (remote execution)
Create a small Bazel workspace and build it, pointing Bazel at the local farm. The Buildfarm worker executes the build action instead of this machine, and Bazel reports it as a remote process.
mkdir -p /tmp/buildfarm-demo && cd /tmp/buildfarm-demo printf 'module(name = "demo")\n' > MODULE.bazel printf 'genrule(name = "demo", outs = ["demo.txt"], cmd = "echo built-on-the-farm > $@")\n' > BUILD.bazel echo 7.4.1 > .bazelversion bazelisk build //:demo \
--remote_executor=grpc://127.0.0.1:8980 \
--remote_cache=grpc://127.0.0.1:8980 \
--remote_instance_name=shard cat bazel-bin/demo.txtBazel reports the genrule as 1 remote in its process summary (INFO: ... processes: ... 1 remote.). The build completes successfully, and demo.txt holds the output the worker produced.
The first time you run bazelisk, it downloads the pinned Bazel release, so allow a few extra seconds. If the worker has only just started, it can take a few seconds to register with the backplane. Run the build again and the action is dispatched remotely.
Rebuild from the remote cache
The farm now stores the action result, so a fresh build of the same target is served from the remote cache instead of being executed again. Clean the local state and build again.
cd /tmp/buildfarm-demo bazelisk clean bazelisk build //:demo \
--remote_executor=grpc://127.0.0.1:8980 \
--remote_cache=grpc://127.0.0.1:8980 \
--remote_instance_name=shardBazel now reports 1 remote cache hit in its process summary. This proves that the result came back from the farm instead of being rebuilt. This is how a shared cache speeds up your team: once one machine builds a target, every other machine and CI runner pulls the result from the farm.
Point your own project at the farm
Add the farm to your project's .bazelrc, or pass the flags on the command line. The endpoint and instance name for this VM are in the root-only info note:
sudo grep -E '^BUILDFARM_ENDPOINT|^BUILDFARM_INSTANCE_NAME' /root/buildfarm-info.txtThen, in your project's .bazelrc, point Bazel at the server. Use the VM's reachable address for <vm-ip>:
# .bazelrc — offload build actions to the farm and share the cache build --remote_executor=grpc://<vm-ip>:8980 build --remote_cache=grpc://<vm-ip>:8980 build --remote_instance_name=shard
# optional: keep building locally if the farm is briefly unreachable build --remote_local_fallbackRun any build twice across your fleet. The first run populates the cache and offloads execution, and later builds on any machine reuse the cached results.
For traffic across untrusted networks, restrict the NSG to networks you control and terminate TLS in front of the endpoint. Alternatively, enable Buildfarm's own gRPC TLS (see the Buildfarm documentation).
The per-VM backplane secret and security
This VM's first boot generates the backplane secret, writes it to a root-only file, and uses it to protect the loopback Redis backplane. The server and worker are gated on a bootstrap marker that first boot writes only after the secret exists, so the farm is fail secure.
sudo stat -c '%n perms=%a owner=%U:%G' /root/buildfarm-info.txt
PW=$(sudo grep '^BUILDFARM_REDIS_PASSWORD=' /root/buildfarm-info.txt | cut -d= -f2-)
echo "redis (no credential) -> $(redis-cli -h 127.0.0.1 ping 2>&1)"
echo "redis (per-VM secret) -> $(redis-cli -h 127.0.0.1 -a "$PW" ping 2>/dev/null)"The info note is 0600 root:root. The unauthenticated ping is rejected with NOAUTH, and the per-VM secret returns PONG. An nftables guard drops the internal worker port 8981 and Redis 6379 off-box, while the server endpoint 8980 stays reachable for your clients.
Sizing, persistence and first boot
The worker's content-addressable storage lives on the OS disk under /var/lib/buildfarm/worker with a size cap. Raise the cap or attach a larger disk for bigger build graphs.
Scale the farm by choosing a larger VM size, so that the worker can execute more actions in parallel.
The first-boot service generates the per-VM secret, renders the configuration and writes the fail-secure marker. It then disables itself, so later reboots are unaffected. The OS is patched at build time and ships with unattended security upgrades enabled.
sudo systemctl is-enabled buildfarm-firstboot.service buildfarm-server.service buildfarm-worker.service
sudo docker ps --format ' {{.Names}} {{.Status}}' export DEBIAN_FRONTEND=noninteractive;
sudo apt-get update -y >/dev/null 2>&1 echo "held packages: $(apt-mark showhold | tr '\n' ' ')[none]"Support
Every SecureAnyCloud deployment includes 24/7 support with a 24-hour response SLA. Contact sales@secureanycloud.com for help with deployment, configuration or scaling.
This is a repackaged open-source software product with additional charges for SecureAnyCloud support services. Bazel and Bazel Buildfarm are trademarks of their respective owners. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on Azure
Launch Bazel Buildfarm on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This guide covers deploying and using Bazel Buildfarm on AWS with SecureAnyCloud's preconfigured Amazon Machine Image. Bazel Buildfarm is an open-source remote build cache and remote execution service that implements Bazel's Remote Execution API (REAPI). Point your Bazel builds at it, and actions are cached and executed on the farm instead of on every developer laptop and CI runner. A shared content-addressable cache and offloaded compilation make builds faster and CI cheaper.
The SecureAnyCloud image ships the free, Apache-2.0-licensed Bazel Buildfarm (bazelbuild/buildfarm 2.17.1). It runs the officially supported way, as the upstream container images, in a complete single-node farm.
What you get:
- A Redis SHARD backplane bound to the loopback interface. Buildfarm 2.x is a sharded architecture, so Redis is required, and the image configures it for you.
- A Buildfarm server that exposes the Remote Execution API on gRPC port 8980, the endpoint your build clients dial.
- A Buildfarm worker on gRPC port 8981 that executes actions.
- A content-addressable cache store on a dedicated, independently resizable EBS data volume mounted at /var/lib/buildfarm, kept off the OS disk.
- No known credential. A unique Redis backplane secret is generated on each instance at first boot. A fail-secure gate stops the server and worker from starting until that secret exists, so the farm never comes up with a build-time or default secret.
- 24/7 SecureAnyCloud support.
Bazel and Bazel Buildfarm are trademarks of their respective owners. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by them. It ships the free, Apache-2.0-licensed software, unmodified.
Before you start: the Remote Execution endpoint is a privileged compute plane
Read this before you use the farm.
The Buildfarm Remote Execution API on port 8980 runs arbitrary build actions that clients submit. That is what remote execution is. An unauthenticated, world-open Remote Execution endpoint is therefore a public remote-code-execution cluster. Treat 8980 as a privileged compute plane.
For that reason, this image ships its security group with only SSH (port 22) open. Port 8980 is not open to the world. Open it deliberately, and only to the machines that should reach it:
- In the EC2 console, open the instance's security group.
- Add an inbound rule: Custom TCP, port 8980, with the source set to your build fleet's CIDR (your CI runners, your developer network, or both). Never use
0.0.0.0/0.
If you later want the worker reachable for a multi-node farm, note that the built-in nftables guard drops the internal worker port 8981 and Redis 6379 off-box by design. A single-node farm needs neither exposed.
Connecting to your instance
Connect over SSH as the default login user for your AMI variant. For Ubuntu 24.04, the user is ubuntu. For example, ssh -i your-key.pem ubuntu@<instance-public-ip>.
Run everything below on the instance.
Retrieve your farm endpoint and details
On first boot, the image resolves this instance's address and writes a root-only info file. Read it:
sudo cat /root/buildfarm-info.txtThe file contains your farm endpoint (grpc://<instance-ip>:8980), the Remote Execution instance name (shard), and the internal Redis backplane secret. Use the secret for on-box administration only. Redis is bound to loopback and never exposed.
Check the three services and their listeners at any time:
systemctl status buildfarm-server buildfarm-worker redis-server ss -tln | grep -E ':8980|:8981|:6379'The server listens on 8980, the worker on 8981, and Redis on 127.0.0.1:6379 (loopback only).
Point your Bazel client at the farm
After you have opened port 8980 to your build clients (see above), point Bazel at the farm from any client machine. Add these flags to your bazel build or bazel test command, or put them in your project's .bazelrc:
bazel build //your:target \
--remote_executor=grpc://<public-ip>:8980 \
--remote_cache=grpc://<public-ip>:8980 \
--remote_instance_name=shard--remote_executor offloads action execution onto the worker. --remote_cache shares the content-addressable cache, so no client rebuilds what another has already built.
The first build populates the cache. Later builds of unchanged targets are served as remote cache hits.
Prove the farm executes and caches actions
The image ships a self-contained proof that you can run on the instance at any time. It runs a real Bazel build against the local farm, forces remote execution on the first pass, and checks for a remote cache hit on the second:
sudo /usr/local/sbin/buildfarm-proof.sh 127.0.0.1A healthy farm prints FARM_PROOF_OK (remote execution + remote cache hit).
Security model
- No default secret. The Redis backplane password, which protects the cache store and the execution queue, is generated uniquely on each instance's first boot. It is stored 0600 root-only in
/root/buildfarm-info.txtand never shipped in the image. A fail-secure bootstrap gate stops the server and worker from starting until that per-instance secret exists. - Redis is loopback-only and authenticated. An unauthenticated
redis-cliconnection is rejected withNOAUTH. Only the per-instance secret authenticates. - The Remote Execution endpoint is closed by default. The shipped security group opens only SSH, and you scope 8980 to your build fleet. A defense-in-depth nftables guard also drops the internal worker port 8981 and Redis 6379 off-box.
- Encryption at rest. The dedicated cache data volume at
/var/lib/buildfarmcan use AWS EBS encryption. Enable it when you launch, or use encrypted snapshots.
The cache data volume
The Buildfarm worker's content-addressable cache and Action-Cache filesystem store live on a dedicated EBS volume mounted at /var/lib/buildfarm (ext4, mounted by filesystem UUID). Keep it off the OS disk and resize it independently as your build fleet's cache footprint grows. Inspect the mount:
df -h /var/lib/buildfarm findmnt /var/lib/buildfarmSizing
The recommended instance type is m5.large (2 vCPU / 8 GB). It comfortably runs the server JVM, the worker JVM, the Redis backplane and a Bazel client for the single-node farm. Scale up for higher action concurrency or a bigger working set.
24/7 SecureAnyCloud Support
Technical support by email and live chat covers deployment, endpoint sizing, network scoping of the Remote Execution port, connecting your Bazel clients, cache and worker administration, and troubleshooting.
Email sales@secureanycloud.com or reach us through live chat. For any issue, including a refund request, contact sales@secureanycloud.com.
Licence
Bazel Buildfarm is licensed under Apache-2.0. The licence text is included in the image at /opt/buildfarm/LICENSE.
The Redis backplane is the Ubuntu 24.04 redis-server package (7.0.x), which is BSD-3-Clause. The Buildfarm server and worker run from the official upstream container images bazelbuild/buildfarm-server:2.17.1 and bazelbuild/buildfarm-worker:2.17.1. They are captured into the AMI, so your instance never needs to pull them.
Deploy on AWS
Launch Bazel Buildfarm on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com