Checkpoint Lab — Hosted, Proxy, and Group Repositories: Design Patterns, Routing, Caching, and Promotion Flows
Build an independent dev/release/public-read topology, publish a synthetic artifact, promote the exact accepted bytes into release, prove checksum identity through the public-read group, exercise proxy caching, capture an evidence packet, and clean up only the disposable lab state.
Learning objectives
- Build and verify a complete disposable hosted/proxy/group topology from a clean preflight.
- Predict repository, metadata, blob and cache changes before causing them.
- Publish to dev and prove the release-read group cannot see the candidate before promotion.
- Promote by copying the exact Nexus-accepted bytes and prove checksum identity after release.
- Capture an evidence packet and clean up only the known disposable repositories through supported Nexus controls.
Checkpoint safety boundary: use only a disposable
loopback Community instance. Do not run this against employer
repositories, production databases/blob stores, real package
namespaces, or public endpoints other than the small Maven Central
proxy request. The checkpoint has its own
academy-ch04-cp-* names and does not depend on Lessons
2–4 being left behind.
1. Exact assumptions and preflight
- Nexus Repository self-hosted Community Edition baseline: 3.94.1-06; re-check current official download/status/release notes before starting.
-
Java 21; one non-production instance bound to
127.0.0.1:8081. - Embedded H2 is acceptable only for this disposable local learning instance; PostgreSQL is the production-oriented choice discussed elsewhere.
- Default file blob store is used; no direct blob/database files are edited.
- Administrative credential is temporary for this learning checkpoint. Later security chapters replace it with scoped roles and service identities.
# POSIX/Bash. Windows PowerShell guidance follows this block.
LAB="$HOME/nexus-ch04-checkpoint"
NX_URL="http://127.0.0.1:8081"
mkdir -p "$LAB/evidence" "$LAB/payload" "$LAB/promote"
umask 077
read -rsp "Disposable Nexus admin password: " NX_PASS; printf "\n"
printf 'machine 127.0.0.1 login admin password %s\n' "$NX_PASS" > "$LAB/nexus.netrc"
unset NX_PASS
NETRC="$LAB/nexus.netrc"
# Never print, commit, or reuse this temporary credential file.
curl -fsS "$NX_URL/service/rest/v1/status/writable" | tee "$LAB/evidence/01-writable.txt"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositories" | tee "$LAB/evidence/02-before.json"
python3 - <<'PY'
import json, pathlib
wanted = {f"academy-ch04-cp-{x}" for x in [
"dev","release","central","dev-read","public-read"
]}
p=pathlib.Path.home()/"nexus-ch04-checkpoint/evidence/02-before.json"
found={r["name"] for r in json.loads(p.read_text())} & wanted
print("checkpoint collisions:", sorted(found))
PY
Windows PowerShell: keep the same loopback URLs
and use curl.exe for the multipart examples. Store
credentials in a temporary user-only file or Windows credential
mechanism rather than embedding them in command history. Use
Get-FileHash -Algorithm SHA256 instead of
sha256sum. The repository and HTTP semantics are
unchanged.
Proceed only if the five names are absent or you have positively identified them as your own abandoned disposable checkpoint.
2. Write predictions before actions
Record at least these four predictions in
$LAB/evidence/predictions.txt before changing Nexus:
-
Creating the five repositories changes repository configuration
but does not create
topology-democomponent assets. -
Publishing
com.example.academy:topology-demo:2.0.0to cp-dev writes component/asset metadata and blob bytes in the hosted repository and makes it readable through cp-dev-read. - Before promotion, cp-public-read returns not-found for the internal artifact because cp-dev is not a member.
- After exact-byte promotion to cp-release, cp-public-read returns the same JAR bytes and SHA-256 as the accepted cp-dev artifact.
cat > "$LAB/evidence/predictions.txt" <<'EOF'
1. Repository creation changes configuration only; topology-demo assets remain absent.
2. Dev publication creates hosted component/assets/blob state and dev-read can resolve it.
3. Public-read cannot resolve topology-demo before promotion because dev is not a member.
4. Public-read returns an identical SHA-256 after exact-byte promotion to release.
EOF
3. Create the independent checkpoint topology
| Repository | Type | Configuration | Expected role |
|---|---|---|---|
academy-ch04-cp-dev |
Maven2 hosted | Mixed, strict, default blob | Candidate publication. |
academy-ch04-cp-release |
Maven2 hosted | Release, strict, allow-once | Accepted release publication. |
academy-ch04-cp-central |
Maven2 proxy | Maven Central, auto-blocking, default blob | Public dependency cache. |
academy-ch04-cp-dev-read |
Maven2 group | cp-dev → cp-release → cp-central | Development reads. |
academy-ch04-cp-public-read |
Maven2 group | cp-release → cp-central | Release/public reads. |
Create those repositories in
Settings → Repository → Repositories using the same
field semantics as Lesson 2. For the proxy remote use
https://repo1.maven.org/maven2/. Preserve the exact
group order shown above. Do not use a Pro-only staging workflow; the
checkpoint must be completable on Community Edition.
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositorySettings" > "$LAB/evidence/03-settings-after-create.json"
Save a UI screenshot or text note of the two group member lists and the proxy cache settings in addition to the API evidence. This is architecture/runbook evidence, not a substitute for component checks later.
4. Build once and record the candidate identity
The build is intentionally deterministic enough for this exercise because you will not rebuild it later. The crucial invariant is that the exact file produced here becomes the candidate, then the exact file accepted by cp-dev becomes the release input.
python3 - <<'PY'
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
root=Path.home()/"nexus-ch04-checkpoint/payload"
root.mkdir(parents=True, exist_ok=True)
(root/"NOTICE.txt").write_text("Chapter 04 checkpoint artifact\n", encoding="utf-8")
with ZipFile(root/"topology-demo-2.0.0.jar","w",ZIP_DEFLATED) as z:
z.write(root/"NOTICE.txt","NOTICE.txt")
(root/"topology-demo-2.0.0.pom").write_text("""<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.academy</groupId>
<artifactId>topology-demo</artifactId>
<version>2.0.0</version>
</project>
""", encoding="utf-8")
PY
sha256sum "$LAB/payload/topology-demo-2.0.0.jar" | tee "$LAB/evidence/04-build-sha256.txt"
5. Publish candidate only to cp-dev
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" -X POST "$NX_URL/service/rest/v1/components?repository=academy-ch04-cp-dev" -F "maven2.groupId=com.example.academy" -F "maven2.artifactId=topology-demo" -F "maven2.version=2.0.0" -F "maven2.asset1=@$LAB/payload/topology-demo-2.0.0.jar" -F "maven2.asset1.extension=jar" -F "maven2.asset2=@$LAB/payload/topology-demo-2.0.0.pom" -F "maven2.asset2.extension=pom" -o "$LAB/evidence/05-dev-upload-body.txt" -w "%{http_code}\n" | tee "$LAB/evidence/05-dev-upload-status.txt"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-dev&group=com.example.academy&name=topology-demo&version=2.0.0" > "$LAB/evidence/06-dev-assets.json"
The expected state is now: cp-dev database metadata describes the component/assets; its blob store contains the JAR/POM bytes; cp-release still has no such component; the groups still only own routing configuration.
6. Prove serving path before promotion
ART_PATH="com/example/academy/topology-demo/2.0.0/topology-demo-2.0.0.jar"
curl --fail-with-body --silent --show-error "$NX_URL/repository/academy-ch04-cp-dev-read/$ART_PATH" -o "$LAB/evidence/07-dev-read.jar"
sha256sum "$LAB/evidence/07-dev-read.jar" | tee "$LAB/evidence/07-dev-read-sha256.txt"
curl --silent --show-error -o "$LAB/evidence/08-public-before-body.txt" -w "%{http_code}\n" "$NX_URL/repository/academy-ch04-cp-public-read/$ART_PATH" | tee "$LAB/evidence/08-public-before-status.txt"
Expected: dev-read succeeds and its checksum matches the build; public-read reports not-found. If public-read succeeds, do not continue. Inspect its member order and check for a stale duplicate artifact in release or an unintended public collision.
7. Promote the exact Nexus-accepted bytes
Do not use the original build files for the release upload. First retrieve the candidate from the authoritative cp-dev hosted repository. That proves the bytes accepted by Nexus are the bytes you promote.
POM_PATH="com/example/academy/topology-demo/2.0.0/topology-demo-2.0.0.pom"
curl --fail-with-body --silent --show-error "$NX_URL/repository/academy-ch04-cp-dev/$ART_PATH" -o "$LAB/promote/topology-demo-2.0.0.jar"
curl --fail-with-body --silent --show-error "$NX_URL/repository/academy-ch04-cp-dev/$POM_PATH" -o "$LAB/promote/topology-demo-2.0.0.pom"
sha256sum "$LAB/promote/topology-demo-2.0.0.jar" | tee "$LAB/evidence/09-accepted-dev-sha256.txt"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" -X POST "$NX_URL/service/rest/v1/components?repository=academy-ch04-cp-release" -F "maven2.groupId=com.example.academy" -F "maven2.artifactId=topology-demo" -F "maven2.version=2.0.0" -F "maven2.asset1=@$LAB/promote/topology-demo-2.0.0.jar" -F "maven2.asset1.extension=jar" -F "maven2.asset2=@$LAB/promote/topology-demo-2.0.0.pom" -F "maven2.asset2.extension=pom" -o "$LAB/evidence/10-release-upload-body.txt" -w "%{http_code}\n" | tee "$LAB/evidence/10-release-upload-status.txt"
This is a teaching simulation of the promotion invariant, not a claim that manual copy/upload is the preferred enterprise workflow. Nexus Repository Pro staging can provide richer lifecycle controls. The Community exercise intentionally focuses on the invariant that the release receives the accepted candidate bytes.
8. Verify exact identity through the public-read group
curl --fail-with-body --silent --show-error "$NX_URL/repository/academy-ch04-cp-public-read/$ART_PATH" -o "$LAB/evidence/11-public-after.jar"
sha256sum "$LAB/payload/topology-demo-2.0.0.jar" "$LAB/promote/topology-demo-2.0.0.jar" "$LAB/evidence/11-public-after.jar" | tee "$LAB/evidence/12-three-way-sha256.txt"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-release&group=com.example.academy&name=topology-demo&version=2.0.0" > "$LAB/evidence/13-release-assets.json"
All three JAR checksums must match. If they do not, stop: the checkpoint has demonstrated a supply-chain identity break. Do not “fix” it by editing checksums or overwriting release state. Determine which bytes changed and repeat the controlled release process with a fresh disposable coordinate if necessary.
9. Exercise the proxy and prove cached state
PUBLIC_PATH="org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar"
curl --fail-with-body --silent --show-error "$NX_URL/repository/academy-ch04-cp-public-read/$PUBLIC_PATH" -o "$LAB/evidence/14-public-dependency.jar"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/search/assets?repository=academy-ch04-cp-central&group=org.apache.commons&name=commons-lang3&version=3.12.0" > "$LAB/evidence/15-proxy-assets.json"
sha256sum "$LAB/evidence/14-public-dependency.jar" | tee "$LAB/evidence/15-public-dependency-sha256.txt"
This evidence proves the public artifact flowed through the group
into the proxy cache. It does not imply the internal
com.example.academy namespace should ever fall through
to Maven Central; production topology should protect owned
namespaces with routing/client governance.
10. Required evidence packet and independent verification
Your packet should contain:
- preflight status and repository inventory;
- repository settings/member-order evidence;
- written predictions;
- build, accepted-dev and public-release SHA-256 evidence;
- cp-dev and cp-release repository-scoped asset search responses;
- public-read HTTP status before and retrieval after promotion;
- proxy repository asset evidence for the public dependency;
- a short runbook note explaining which repository was authoritative for each artifact and which group served each consumer.
Independently verify at least two predictions by comparing the evidence packet rather than relying on UI memory. The strongest pair is the pre-promotion public-read 404 and the three-way checksum identity after promotion.
11. Safe cleanup and rollback
Cleanup must be exact and supported. In the Nexus UI, first verify
each repository name begins with academy-ch04-cp- and
contains only this lab’s synthetic/cache content. Delete the two
groups first, then the two hosted repositories and
the proxy. Do not delete database files, blob-store files or the
shared default blob store.
After repository deletion, verify the five names are absent from the repository inventory. Then remove only the local checkpoint directory, including the temporary netrc credential file. If your operating system cannot safely confirm the exact local path, delete the directory manually rather than using a broad recursive command copied from a lesson.
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositories" > "$LAB/evidence/16-before-local-cleanup.json"
python3 - <<'PY'
import json, pathlib
p=pathlib.Path.home()/"nexus-ch04-checkpoint/evidence/16-before-local-cleanup.json"
remaining=[r["name"] for r in json.loads(p.read_text()) if r["name"].startswith("academy-ch04-cp-")]
print("remaining checkpoint repositories:", remaining)
PY
# After the UI shows no academy-ch04-cp-* repositories:
rm -f "$NETRC"
unset NETRC
The local evidence directory may be retained for study after the credential file is removed. Repository deletion may mark/reclaim storage according to Nexus cleanup/blob semantics rather than instantly producing the exact filesystem free-space change you expect; Chapter 18 teaches cleanup/reclamation in detail.
Knowledge check
Why did the checkpoint download the candidate from cp-dev before uploading to cp-release?
To make the release input the exact bytes Nexus accepted as the candidate, proving promotion identity rather than accidentally using a rebuild or different local file.
Public-read returned the candidate before promotion. What should you inspect first?
The group member list/order and whether the same coordinate already exists in cp-release or an unintended member. Do not continue until the routing contradiction is explained.
All three SHA-256 values match after promotion. What does that prove—and not prove?
It proves byte identity across the build/candidate/release retrievals. It does not prove trusted provenance, vulnerability safety, authorization correctness or policy compliance.
Why are the checkpoint groups deleted before their member repositories?
It removes read aggregations/references first and makes the intended cleanup order explicit. Cleanup remains limited to disposable Nexus-managed repositories.
A public dependency is cached in cp-central. Does that make cp-central authoritative for your organization’s release?
No. The proxy is a managed cache of a remote source. Your organization-controlled release authority is cp-release.
If a release checksum differs, why should you not overwrite the release to “make it match”?
That hides the identity failure and may violate release immutability/write policy. Preserve evidence, determine what changed, and repeat the controlled process with a fresh disposable identity if needed.
12. What Chapter 04 adds to the production operating model
You can now describe an artifact platform as explicit publication origins, controlled upstream proxies and ordered consumer views. You can prove which repository owns bytes, distinguish cache availability from authority, protect internal namespaces from unsafe fallback, and require release promotion to preserve artifact identity.
Chapter 05 moves below that routing graph. It asks where the database and blob bytes live, how capacity and data separation work, and why storage design must preserve the relationship between metadata and binary content.
13. Checkpoint summary
A successful checkpoint ends with five disposable repositories created and removed safely, a synthetic artifact promoted without rebuild, identical checksums across candidate/release retrieval, proxy cache evidence, and a concise runbook explaining the routing graph.
Official references and version notes
- Download Nexus Repository and Nexus Repository 3 Versions Status — re-check the self-hosted release line before running the pinned lab.
- Repository Types — hosted, proxy and group semantics, nested/transitive groups, ordered member lookup, and direct-member privilege boundaries.
- Configurable Repository Fields — proxy remote storage, component/metadata age, negative cache, blocking, and auto-blocking.
- Repository Actions — current cache invalidation behavior and what it does not delete.
- Repositories API — repository inventory and format/type-specific repository configuration endpoints.
- Components API, Assets API, and Search API — upload plus independent component/asset evidence.
- Maven Repositories — Maven hosted/proxy/group configuration semantics and Central proxy use.
- Routing Rules — controlling proxy requests and preventing internal namespaces from falling through to public remotes.
- Staging and the current feature matrix — Nexus staging/build-promotion is a Pro capability; the mandatory Community lab uses exact-byte copy semantics instead.
Version-sensitive statements were rechecked against Sonatype primary documentation on 2026-08-26. The mandatory path pins the same self-hosted Community lab baseline used by Chapters 02–03: Nexus Repository 3.94.1-06, Java 21, one loopback single-node instance, embedded H2 only for disposable learning, and the default file blob store. Production database/storage decisions are deferred to Chapter 05. Re-check the current download/status/release-note pages before execution.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.