Checkpoint Lab — Blob Stores, Storage Layout, Database Choices, Capacity Planning, and Data Separation
Model capacity, place disposable repositories on two blob stores, generate measurable content, prove checksum identity and recovery dependencies, then remove only the lab state through supported Nexus operations.
Learning objectives
- Build an independent two-blob-store lab without relying on state left by earlier lessons.
- Model one year of growth and choose capacity from an explicit utilization/headroom target.
- Predict repository, database, blob-store, checksum, and authorization effects before publishing.
- Generate measurable synthetic content, preserve exact release bytes, and collect an evidence packet.
- Prove the database/blob recovery dependency and clean up the entire checkpoint through supported Nexus operations.
Current lab baseline (reviewed 2026-08-26): Nexus
Repository Community Edition 3.94.1-06, Java 21, loopback-only HTTP,
a dedicated non-root/non-administrator process identity, and
embedded H2 only for the disposable local instance. Sonatype
currently recommends external PostgreSQL for production deployments.
The lab never treats a blob store as a database backup or
manipulates $data-dir/blobs or database files directly.
Independent checkpoint: use a disposable
single-node Community instance on 127.0.0.1. This lab
creates only academy-ch05-hot-store,
academy-ch05-release-store,
academy-ch05-builds, and
academy-ch05-releases. If any name already exists, stop
and choose a fresh disposable instance rather than deleting unknown
state.
1. Record exact assumptions
| Dimension | Checkpoint assumption |
|---|---|
| Nexus | Self-hosted Community Edition 3.94.1-06; re-check current GA/download before use. |
| Runtime | Java 21; dedicated non-root/non-administrator Nexus process account. |
| Network | Loopback HTTP only; no public exposure. |
| Database | Embedded H2 for this disposable lab only; PostgreSQL is the production-preferred direction. |
| Blob backend | Two file blob stores with relative disposable paths. No cloud account required. |
| Repository format | Raw hosted for deterministic, protocol-simple byte measurement. |
| Credentials | Disposable admin only for local configuration; stored in a temporary permission-restricted credential file. |
| Safety | No direct database/blob-file edits, no real disk exhaustion, no production backup/migration. |
2. Preflight and collision check
# POSIX/Bash. Use only against the disposable loopback instance.
LAB="$HOME/nexus-ch05-checkpoint"
NX_URL="http://127.0.0.1:8081"
mkdir -p "$LAB/evidence" "$LAB/payload" "$LAB/move"
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/blobstores" | tee "$LAB/evidence/02-blobstores-before.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositories" | tee "$LAB/evidence/03-repositories-before.json"
python3 - <<'PY'
import json, pathlib, sys
root = pathlib.Path.home()/"nexus-ch05-checkpoint/evidence"
blobs = json.loads((root/"02-blobstores-before.json").read_text())
repos = json.loads((root/"03-repositories-before.json").read_text())
wanted_b = {"academy-ch05-hot-store","academy-ch05-release-store"}
wanted_r = {"academy-ch05-builds","academy-ch05-releases"}
present_b = {x.get("name") for x in blobs} & wanted_b
present_r = {x.get("name") for x in repos} & wanted_r
if present_b or present_r:
print("Collision:", sorted(present_b | present_r))
sys.exit(2)
print("No checkpoint name collisions.")
PY
df -h "$HOME" | tee "$LAB/evidence/04-disk-before.txt"
Windows PowerShell: use the same loopback URLs
with curl.exe. Keep the disposable credential in a
user-only temporary credential mechanism rather than embedding a
password in command history. Use
Get-FileHash -Algorithm SHA256 for hashes and
Get-Volume/Get-PSDrive for free-space
evidence. Do not run Nexus as Administrator merely to bypass a
permissions problem.
If the collision script exits non-zero, stop. Do not delete the matching object unless you independently proved that it belongs to this exact checkpoint run.
3. Predict state changes before acting
Write your predictions into
$LAB/evidence/05-predictions.txt before you create
anything:
- Creating a blob store changes Nexus configuration/database state but does not create repository assets.
- Creating a repository mapped to a blob store changes repository configuration but does not add payload bytes.
-
Uploading three files to
academy-ch05-buildsincreases blob count/used size inacademy-ch05-hot-store, not the release store. -
Publishing the exact retrieved release candidate to
academy-ch05-releasesadds bytes to the release store while preserving SHA-256 identity.
The checkpoint passes only if you later compare these predictions with independent API and checksum evidence.
4. Capacity model before storage creation
Assume the organization produces 18 GiB/month of build/release bytes and removes 8 GiB/month after supported retention. Releases retained separately add another 6 GiB/month. For twelve months:
\[\text{hot net growth}=(18-8)\times12=120\text{ GiB}\]
\[\text{release growth}=6\times12=72\text{ GiB}\]
Total projected retained bytes are 192 GiB. Add a 10% allowance for blob properties/allocation/estimation uncertainty: 211.2 GiB. Reserve another 100 GiB for operating growth, temporary work, cleanup/recovery and forecast error. If the target is at most 70% utilization:
\[(211.2+100)/0.70\approx444.6\text{ GiB}\]
This is a planning exercise, not a universal Nexus sizing formula. Real environments measure actual growth, package formats, cleanup lag, filesystem allocation, database/data-directory growth, and recovery staging.
5. Create two stores and two hosted repositories
Through Settings → Repository → Blob Stores, create file stores:
-
academy-ch05-hot-storewith relative pathacademy-ch05-hot-store -
academy-ch05-release-storewith relative pathacademy-ch05-release-store
Then create Raw hosted repositories:
-
academy-ch05-builds→academy-ch05-hot-store, write policy Allow -
academy-ch05-releases→academy-ch05-release-store, write policy Allow once
flowchart TD CI[Synthetic producer] -->|PUT build assets| R1[academy-ch05-builds] R1 --> B1[(academy-ch05-hot-store)] CI -->|exact accepted release bytes| R2[academy-ch05-releases] R2 --> B2[(academy-ch05-release-store)] R1 --> DB[(Nexus database / repository metadata)] R2 --> DB B1 -. recovery dependency .-> DB B2 -. recovery dependency .-> DB DB -. recovery dependency .-> B1 DB -. recovery dependency .-> B2
The diagram is deliberately asymmetric: repository configuration/metadata is relational database state; asset bytes live in the mapped blob stores. A recovery point must preserve their relationship.
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/blobstores" | tee "$LAB/evidence/06-blobstores-created.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositorySettings" | tee "$LAB/evidence/07-repository-settings-created.json"
6. Generate and publish measurable build content
Create three harmless files totaling 12 MiB. Record hashes before Nexus accepts them.
python3 - <<'PY'
from pathlib import Path
import hashlib
root = Path.home()/"nexus-ch05-checkpoint/payload"
root.mkdir(parents=True, exist_ok=True)
for mib, byte in [(3,b"D"), (5,b"E"), (4,b"R")]:
p = root/f"checkpoint-{mib}MiB.bin"
p.write_bytes(byte * (mib*1024*1024))
print(p.name, p.stat().st_size, hashlib.sha256(p.read_bytes()).hexdigest())
PY
sha256sum "$LAB"/payload/*.bin | tee "$LAB/evidence/08-local-sha256.txt"
for f in "$LAB"/payload/*.bin; do
name="$(basename "$f")"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" --upload-file "$f" "$NX_URL/repository/academy-ch05-builds/builds/$name"
done
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/blobstores" | tee "$LAB/evidence/09-blobstores-after-builds.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/assets?repository=academy-ch05-builds" | tee "$LAB/evidence/10-build-assets.json"
Compare evidence 06 and 09. The hot store should show new blobs/used bytes; the release store should not contain the build assets merely because it exists.
7. Preserve exact release bytes
Treat the 4 MiB object as the accepted release candidate. Retrieve it from Nexus, hash it, then upload those exact bytes to the release repository. Do not rebuild or regenerate the file for the release stage.
SRC="$NX_URL/repository/academy-ch05-builds/builds/checkpoint-4MiB.bin"
DST="$NX_URL/repository/academy-ch05-releases/releases/checkpoint-4MiB.bin"
curl --fail-with-body --silent --show-error "$SRC" -o "$LAB/move/accepted-release.bin"
sha256sum "$LAB/payload/checkpoint-4MiB.bin" "$LAB/move/accepted-release.bin" | tee "$LAB/evidence/11-release-source-sha256.txt"
cmp "$LAB/payload/checkpoint-4MiB.bin" "$LAB/move/accepted-release.bin"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" --upload-file "$LAB/move/accepted-release.bin" "$DST"
curl --fail-with-body --silent --show-error "$DST" -o "$LAB/move/retrieved-release.bin"
sha256sum "$LAB/move/accepted-release.bin" "$LAB/move/retrieved-release.bin" | tee "$LAB/evidence/12-release-destination-sha256.txt"
cmp "$LAB/move/accepted-release.bin" "$LAB/move/retrieved-release.bin"
This models exact-artifact promotion in Community using ordinary hosted repository operations. It does not claim to be Nexus Pro staging or the Pro-only Change Repository Blob Store task.
8. Verify placement, headroom, and predictions independently
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/blobstores" | tee "$LAB/evidence/13-blobstores-final.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/assets?repository=academy-ch05-releases" | tee "$LAB/evidence/14-release-assets.json"
for b in academy-ch05-hot-store academy-ch05-release-store; do
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/blobstores/$b/quota-status" | tee "$LAB/evidence/15-$b-quota.json"
done
df -h "$HOME" | tee "$LAB/evidence/16-disk-after.txt"
Now compare each prediction from step 3 with the API outputs. A correct mental model explains why a store changed, not merely that numbers differ.
9. Recovery dependency matrix
| State | Checkpoint evidence | Needed for real recovery? | Why |
|---|---|---|---|
| Repository mappings/configuration | 07-repository-settings-created.json |
Yes | Defines which repositories and blob stores Nexus expects. |
| Relational database | Recorded H2 mode for lab / PostgreSQL in production design | Yes | Contains Nexus repository/component/configuration state. |
| Hot blob content |
09/13-blobstores*.json plus asset evidence
|
Depends on RPO/retention | Contains build assets; some may be reconstructable but do not assume. |
| Release blob content | Release asset + SHA-256 evidence | Yes for retained authoritative releases | Contains exact accepted release bytes. |
| Application directory | Pinned release/version evidence | Reinstallable software, not sufficient backup | Needed to run Nexus but does not replace persistent state. |
| Client cache | Not part of checkpoint backup | No | A consumer cache is not an authoritative repository recovery source. |
For this checkpoint, you are not performing a real backup. The acceptance requirement is to identify the pieces a future Chapter 25 backup must coordinate and to reject “we copied the blob folder” as sufficient proof.
10. Evidence packet
Your checkpoint packet should contain:
- Nexus version/runtime/database-mode note and loopback/edition assumptions.
- Before/after blob-store and repository lists.
- Repository-to-blob mappings.
- Capacity model and chosen headroom target.
- Local payload hashes and asset listings.
- Source/destination release SHA-256 proof.
- Final blob counts/used sizes, quota status, and OS free-space evidence.
- The prediction-vs-observation review and recovery dependency matrix.
Do not include the temporary credential file in the evidence packet.
11. Cleanup and rollback
Cleanup order proves you understand dependencies. Through Nexus UI/API, delete the two disposable repositories first. Then confirm no repository uses the two checkpoint blob stores and delete those stores through Nexus. Do not remove their backing directories manually.
# After deleting the two repositories and then the two blob stores in Nexus:
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/repositories" | tee "$LAB/evidence/17-repositories-after-cleanup.json"
curl --fail-with-body --silent --show-error --netrc-file "$NETRC" "$NX_URL/service/rest/v1/blobstores" | tee "$LAB/evidence/18-blobstores-after-cleanup.json"
rm -f "$NETRC"
unset NETRC
# Remove only the local client/evidence workspace after saving the evidence you need.
# rm -rf "$LAB" # optional; this is NOT a Nexus data/blob path.
If Nexus refuses to delete a blob store because it is still in use, treat that as useful dependency evidence. Find the remaining repository reference; do not force-delete filesystem content.
Knowledge check
Why must repositories be deleted before their blob stores in checkpoint cleanup?
A blob store that is still referenced by a repository is in use; Nexus prevents normal deletion until the dependency is removed.
What proves the release promotion preserved artifact identity?
The SHA-256 of the Nexus-accepted source bytes matches the bytes retrieved from the release repository, with byte comparison succeeding.
If the release blob store survives but the database is lost, is the checkpoint service recoverable as-is?
No. Blob content alone does not recreate the relational repository/configuration state.
Why is the calculated 444.6 GiB target not a universal Nexus requirement?
It comes from this scenario’s growth, allowance, reserve and 70% utilization policy. Real capacity must use measured workload and recovery requirements.
A soft quota is below current used size. Should Nexus block the next upload?
No. Current blob-store soft quotas are alerts, not write-enforcement limits.
What production topic follows naturally from this chapter?
Chapter 06 applies the storage/repository mental model to Maven 2 releases, snapshots, metadata, checksums, and Maven client configuration.
12. What Chapter 05 adds to the operating model
The artifact platform now has an explicit storage contract: application software is separate from persistent state; database and blob stores are distinct but recovery-coupled; repository mappings are configuration evidence; capacity has headroom and emergency thresholds; IO/permissions/file handles are integrity dependencies; and cleanup/migration occurs through supported Nexus mechanisms.
13. Summary
You can now predict where a Nexus change lands, measure which storage layer grows, distinguish alerting from enforcement, preserve exact bytes across repository stages, and explain why a backup must coordinate relational and blob state. Chapter 06 can therefore focus on Maven protocol semantics without re-teaching storage fundamentals.
Official references and version notes
- Nexus Repository Download and 2026 self-hosted release notes — current downloadable/GA baseline.
- System Requirements — Java 21, H2/PostgreSQL guidance, file handles, disk threshold, and filesystem support.
- Database Options — embedded H2 versus external PostgreSQL.
- Directories — application and persistent data directory responsibilities.
- Storage Guide and Storage Planning — blob-store layouts, sizing, and performance implications.
- Blob Stores — blob count, used size, path, state, soft quotas, and lifecycle constraints.
- Blob Store API and REST API Reference — supported inspection/configuration endpoints.
- Change Repository Blob Store — supported Pro-only repository relocation task.
- Self-Hosted Feature Matrix — edition boundaries for storage and database capabilities.
- AWS S3 Blob Store — object-storage deployment guidance.
- Raw Repositories — hosted Raw repositories and HTTP PUT publication.
Version-sensitive statements were rechecked against Sonatype primary documentation on 2026-08-26. The current Download, versions-status, and 2026 release-notes pages list 3.94.1 as the newest GA/downloadable self-hosted line. Mandatory labs therefore pin Nexus Repository Community Edition 3.94.1-06 on loopback with Java 21 and embedded H2 only as a disposable learning database. Current system requirements recommend external PostgreSQL for supported production-scale deployments and require at least 4 GB of free disk at all times. Learners should re-check the live pages before executing the lab because Nexus support matrices evolve.
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.