Your organization is air-gapped and cannot reach services.gradle.org. How do you regenerate the wrapper so builds fetch Gradle from an internal mirror?
answer
- default URL = services.gradle.org
- set distributionUrl to internal mirror
- mirror the zip first
- pin distributionSha256Sum
- pre-seed dists/ on CI images
basics
~10 sConfigure the wrapper to use an internal URL: set distributionUrl (in the wrapper task or properties) to your mirror's gradle-9.0-bin.zip. Regenerate with the wrapper task and commit, so every build pulls from the mirror.
solid answer
~40 sBy default `distributionUrl` points at `https://services.gradle.org/distributions/...`, which an air-gapped network can't reach. The fix is to make the wrapper fetch from an internal mirror. Configure `distributionUrl` on the `Wrapper` task (or pass it through) to your hosted copy, e.g. `https://nexus.internal/gradle/gradle-9.0-bin.zip`, then run `./gradlew wrapper` and commit the regenerated `gradle-wrapper.properties`. Mirror the distribution zip into your artifact server first. For supply-chain safety, also set `distributionSha256Sum` so the wrapper verifies the downloaded archive. At fleet scale you'd standardize this via a shared convention/init script so every repo points at the mirror consistently, and you might pre-seed `~/.gradle/wrapper/dists` on CI images to avoid the download entirely.
code
kotlin · 6 linestasks.wrapper {
gradleVersion = "9.0"
// Point the bootstrap at the internal mirror instead of services.gradle.org
distributionUrl = "https://nexus.internal/repository/gradle/gradle-9.0-bin.zip"
}
// Then: ./gradlew wrapper and commit gradle/wrapper/gradle-wrapper.propertiesgo deeper
Recognize that distributionUrl can be changed to a different host.
Configure distributionUrl to a mirror via the wrapper task, regenerate, and commit.
Add checksum verification, pre-seeded CI caches, and explain the supply-chain reasoning end to end.
Design org-wide standardization (convention plugin/init script, governed URL changes, pre-baked CI images) for offline reproducible builds.
## The problem The wrapper bootstraps by downloading a Gradle distribution from the URL in `gradle-wrapper.properties`: ```properties distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-bin.zip ``` In an air-gapped or restricted corporate network, `services.gradle.org` is unreachable, so the first `./gradlew` invocation fails to download anything. ## Redirect the wrapper to an internal mirror 1. **Host the zip.** Mirror `gradle-9.0-bin.zip` (or `-all.zip`) into an internal artifact server (Nexus, Artifactory, S3, plain HTTP). 2. **Point the wrapper at it.** Configure the `Wrapper` task with an explicit `distributionUrl`: ```kotlin tasks.wrapper { gradleVersion = "9.0" distributionUrl = "https://nexus.internal/repository/gradle/gradle-9.0-bin.zip" } ``` 3. **Regenerate and commit.** Run `./gradlew wrapper` so the new `distributionUrl` is written into `gradle-wrapper.properties`, then commit it. Now every developer and CI agent fetches Gradle from the mirror. ## Verify what you download When you control the URL, also pin the checksum so a tampered or corrupt mirror copy is rejected: ```kotlin tasks.wrapper { distributionSha256Sum = "<sha-256 of the zip>" } ``` The wrapper validates the archive against this hash before unpacking. (Computing and storing that hash is a related concern to this task's job of writing the URL.) ## Scaling across an organization - **Convention plugin / shared init script** so every repo's wrapper points at the mirror without per-repo drift. - **Pre-seed CI images**: bake the unpacked distribution into `~/.gradle/wrapper/dists/<hash>/` so even the mirror download is skipped on CI, making cold builds fast and fully offline. - **Governance**: review changes to `distributionUrl` carefully — it's a supply-chain-sensitive line. ## Why the `wrapper` task, not hand-editing Running the task keeps the properties, scripts, and jar consistent and lets you set the URL/checksum together. Hand-editing only the URL is error-prone and skips the regeneration of the rest of the wrapper files.
- How can CI avoid the mirror download entirely?Pre-seed the unpacked distribution into `~/.gradle/wrapper/dists/<dirname>/<hash>/` on the CI image (or mount a cache). The wrapper finds the matching unpacked dist and skips the network call.
- Why also set `distributionSha256Sum` when using a custom mirror?It makes the wrapper verify the downloaded zip against a known hash, protecting against a tampered, corrupted, or swapped artifact on the mirror — a supply-chain safeguard.
- How would you keep dozens of repos pointed at the mirror consistently?Centralize the URL (and checksum) in a shared convention plugin or organization init script so each repo inherits it, avoiding per-repo drift and easing future migrations.
saying these in an interview costs you the question
- Suggesting you disable the wrapper and install Gradle manually on every machine — defeats reproducibility and is the opposite of the wrapper's purpose.
- Pointing `distributionUrl` at the mirror but not committing the regenerated properties.
- Ignoring checksum verification when sourcing from a self-hosted URL.