Migrate from Build Cache Node: Gradle and Maven setup
+
Stand up a replacement cache, change one URL, check that it works. About 30 minutes for Gradle. There is no data to move.
+
+
Before you start
+
A build cache holds copies of things your builds can always rebuild, so there is nothing to export from the old node. Your first build on the new server just fills it. If you have not read why the node is going away, see Build Cache Node end of life.
+
+
Step 1: Run the new cache server
+
docker run -d -p 8080:8080 -v fscache-data:/home/nonroot ghcr.io/fosterstack/cache:latest
+
For anything beyond a first look, pin a specific version instead of latest. Put the server behind HTTPS before real builds use it. Other ways to run it (bare binary with systemd, Kubernetes, offline networks) are in the install guide.
+
If the server can be reached by anyone you do not trust, turn on Basic Auth. Anyone who can write to the cache can change what your later builds use.
+
+
Step 2: Gradle build cache setup
+
Turn the cache on, in gradle.properties:
+
org.gradle.caching=true
+
Then point Gradle at the new server in settings.gradle.kts. If you used the old node, you only change the URL:
Keep the comment lines: a cache block that points at an unfamiliar host looks like data theft to a reviewer without them. Keep the trailing slash on the URL. Leave the credentials block in even if the server has no password yet; it is ignored then.
+
+
Step 3: Maven build cache setup
+
Maven uses Apache's Build Cache Extension. FosterStack Cache implements the server side of it. The server part is built; its acceptance testing is still in progress.
+
Add the extension in .mvn/extensions.xml (check Maven Central for the current version):
If the server uses Basic Auth, add a matching <server> with the same id (fosterstack-cache) in ~/.m2/settings.xml. Then run mvn install.
+
The extension itself is Apache's project. If your hit rate looks low, start with the extension's own configuration guide.
+
+
Step 4: Check that it works
+
For Gradle, run the build twice:
+
./gradlew build --build-cache
+
On the second run, look for FROM-CACHE next to tasks. Gradle also has a local cache that gives hits even when the remote is broken, so to test the remote itself, clear the local one and run with -i:
For Maven, build twice from a clean checkout and look for cache hits in the log for unchanged modules.
+
+
Step 5: Retire the old node
+
Once builds hit the new server, stop the old Build Cache Node container.
+
+
What you give up
+
The old node had a small web page with a purge button. FosterStack Cache has no settings page. You set it with flags and environment variables, and a read-only status page shows size and hit counts. To empty the cache, remove its volume and start again.
+
+
+
+
diff --git a/sitemap.xml b/sitemap.xml
index 8c1e470..1f932e9 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -16,4 +16,8 @@
weekly1.0
+
+ https://fosterstack.com/migrate-build-cache-node/
+ 2026-10-08
+
From 9e597fa052ec31a89b0d6d1449c0a7d26918cb1e Mon Sep 17 00:00:00 2001
From: FosterStack Admin <317177128+fosterstack-admin@users.noreply.github.com>
Date: Thu, 8 Oct 2026 20:17:46 -0400
Subject: [PATCH 02/78] Page: Jenkins and CI build cache for Gradle and Maven
---
jenkins-ci-build-cache/index.html | 137 ++++++++++++++++++++++++++++++
sitemap.xml | 4 +
2 files changed, 141 insertions(+)
create mode 100644 jenkins-ci-build-cache/index.html
diff --git a/jenkins-ci-build-cache/index.html b/jenkins-ci-build-cache/index.html
new file mode 100644
index 0000000..2134259
--- /dev/null
+++ b/jenkins-ci-build-cache/index.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+Jenkins and CI build cache for Gradle and Maven
+
+
+
+
+
+
+
+
+
+
fosterstack
+
Infrastructure worth keeping — and kept patched.
+
+
+
Jenkins and CI build cache for Gradle and Maven
+
Point your Jenkins agents, GitHub Actions runners or GitLab runners at one shared build cache, so a fresh agent stops rebuilding what another agent already built.
+
+
How a CI runner uses a remote build cache
+
The cache is a plain web server. Your build tool (Gradle, or Maven with Apache's Build Cache Extension) asks it for finished task results and uploads new ones. Any runner that can reach the server over HTTP can use it. There is no plugin to install on the CI system.
+
We have not tested it with any particular CI product. Our own tests run in GitHub Actions. The protocol is the same everywhere, so what matters is that the runner can reach the server and holds the password.
+
+
Let CI write, let developers read
+
The simplest safe setup is that only CI uploads to the cache and laptops only download. In settings.gradle.kts:
+
isPush = System.getenv("CI") != null
+
This is the Gradle client choosing not to upload. It is not a permission on the server. Today the server has one password, and anyone holding it can write. Share it only with people and systems you already trust to change your code.
+
+
Runners inside your Kubernetes cluster
+
If your runners already run in the cluster that hosts the cache (including Jenkins agents), you need no load balancer and no ingress. Point the build at the cluster-internal name:
Replace fscache-ns with your namespace. Plain HTTP is acceptable here only because the traffic never leaves the cluster network. The manifests are in the Kubernetes guide.
+
+
Runners outside the cluster, or on plain servers
+
Run the server on a host the runners can reach and put HTTPS in front of it. Gradle sends the password with every request, so over plain HTTP it travels in the clear. Gradle refuses plain HTTP to anything but localhost unless you opt in, which is a useful warning, not a nuisance. Setup is in the install guide.
+
+
Give the runner the password
+
Store it in your CI system's secret store and expose it as the FSCACHE_PASSWORD environment variable. On a long-lived agent, Gradle's background daemon reads its environment once, when it starts. If you change the secret and builds quietly stop using the cache, run ./gradlew --stop so the next build starts a fresh daemon.
+
+
Check that CI is really using the cache
+
Run the same build twice on two different agents. The second should show FROM-CACHE next to tasks. A runner's local cache can hide a broken remote, so run once with -i, which prints remote errors. Gradle treats a broken remote as non-fatal, so it fails silently otherwise. On the server, the hit and miss counters at /metrics should move.
+
Maven on CI follows the same pattern with the extension and a <server> entry for the password. The server side for Maven is built; its acceptance testing is still in progress. See the Gradle and Maven setup page.
A build cache holds copies of things your builds can always rebuild, so there is nothing to export from the old node. Your first build on the new server just fills it. If you have not read why the node is going away, see Build Cache Node end of life.
Step 1: Run the new cache server
-
docker run -d -p 8080:8080 -v fscache-data:/home/nonroot ghcr.io/fosterstack/cache:latest
-
For anything beyond a first look, pin a specific version instead of latest. Put the server behind HTTPS before real builds use it. Other ways to run it (bare binary with systemd, Kubernetes, offline networks) are in the install guide.
+
docker run -d -p 127.0.0.1:8080:8080 -v fscache-data:/home/nonroot ghcr.io/fosterstack/cache:latest
+
For anything beyond a first look, pin a specific version instead of latest. This command listens on this machine only. For other machines to use it, put an HTTPS proxy in front. Other ways to run it: bare binary with systemd, Kubernetes, or a disconnected network.
If the server can be reached by anyone you do not trust, turn on Basic Auth. Anyone who can write to the cache can change what your later builds use.
Build Cache Node replacement: questions and answers
+
Short answers about the end of the free Build Cache Node and about FosterStack Cache.
+
+
What is happening to the Develocity Build Cache Node?
+
Gradle Inc. says the free standalone Build Cache Node "will no longer be distributed, supported or available after December 31, 2026." Read the vendor's official notice. We have a short page on what that means.
+
+
Do I have to move my cached data?
+
No. A build cache only holds results your build can always rebuild. Start the new server empty and your first builds fill it. If the cache is down or empty, builds are slower, not wrong.
+
+
What is FosterStack Cache?
+
A self-hosted remote build cache. It is one static binary or one container image, MIT licensed. It speaks Gradle's own HttpBuildCache protocol, and also the remote mode of Apache's Maven Build Cache Extension.
+
+
Does it work with Gradle?
+
Yes. Gradle talks to it with its normal remote build cache setting, so moving from the old node is mostly a URL change. Our CI builds a real multi-module Gradle project against it on every change and checks that a second build gets real cache hits. See the setup page.
+
+
Does it work with Maven?
+
The Maven side is built, but its acceptance testing is still in progress, so treat it as newer than the Gradle side. The Maven client is Apache's Build Cache Extension, not ours.
+
+
Is it free?
+
Yes. Everything you can download today is the free MIT core, including eviction, size limits and metrics. Paid tiers are described for the future but are not built or sold yet.
+
+
Is it ready for production?
+
It is early. Nobody runs it in a real build pipeline yet except us. A cache fails safe, since a missing cache means slower builds, but decide for yourself with that in mind. The README lists what has shipped and what has not.
+
+
Who can write to the cache?
+
Anyone holding the password. The server has one password and one permission level today. Turn on Basic Auth anywhere untrusted people could reach the port, and share the password only with CI and developers you trust to change your code. Telling Gradle not to upload is a client choice, not a server rule.
+
+
Does it have a web page like the old node?
+
No settings page, on purpose. You configure it with flags and environment variables. A read-only status page shows version, size, entries and hit counts, and metrics are available for Prometheus. To empty the cache, remove its volume and start again.
+
+
How do I check a release is the real one?
+
Container images are signed and releases carry build provenance, a software bill of materials and vulnerability statements. The commands are under "Verifying a release" in RELEASING.md. No account is needed for the signature check.
+
+
Does the server send anything out?
+
No. The server sends no telemetry and needs no connection to FosterStack. It can run on a network with no route to the internet; see the disconnected network guide.
+
+
Can I run it on Kubernetes?
+
Yes, with plain manifests in the Kubernetes guide. There is no Helm chart yet.
Every release is built by an automated pipeline, checked, signed, and published with files you can verify yourself. This page says what that means today.
+
+
Releases are built only in CI
+
No release file is ever made on a person's laptop, ours included. A release starts when a signed tag is pushed, and there is no manual release path. That is what makes the signatures mean something: nobody can forge a release that GitHub's own build machines never built.
+
+
The steps a release goes through
+
+
Source check. The tag and the commit must be signed by an allowed signer, sit on the main branch, and have every required check green.
+
Build. The binaries are built, with checksums and a software bill of materials for each archive.
+
Container images. Each image is the unmodified distroless base plus one binary.
+
Reproducibility check. The image is assembled a second time on a separate machine. The results must be identical, or the release fails.
+
Scans and tests. Every scanner on our list runs against the exact images. A finding blocks the release unless a published VEX statement explains why it does not apply. The Gradle and Maven acceptance tests run against the same images.
+
Authorization. One step checks that every earlier step produced signed proof for these exact files. Anything missing stops the release.
+
Publish. The approved images are copied to the public registry without a rebuild, and checked again the way a customer would check them.
+
+
The full description, as the pipeline actually runs, is in RELEASING.md.
+
+
What you get with each release
+
+
Container images on GitHub's registry, signed without a stored key (Sigstore), with build provenance.
+
Plain binaries and a checksums.txt with its own signature file.
+
A software bill of materials (SBOM) for each binary archive.
+
A VEX file saying which known vulnerabilities do and do not affect the release.
+
A release-manifest.json listing every file and its digest.
+
+
All of it is public. You do not need an account or a purchase to check any of it. The commands are under "Verifying a release" in RELEASING.md.
+
+
Kept patched
+
Every published image is scanned again every day, so a vulnerability disclosed against something we already shipped raises an issue without anyone having to remember to look.
+
+
What we do not claim
+
+
Nobody runs it in a real build pipeline yet except us.
+
Scan results are visible in our public CI logs. They are not yet attached to each release as permanent evidence.
+
We aim to ship fixes for dependency vulnerabilities within 48 hours of public disclosure. That is an intention, not a promise you can hold us to.
+
The paid tiers are not built. Everything here is the free MIT core.