Chapter 05Lesson 02165–210 min

Blob Stores, Storage Layout, Database Choices, Capacity Planning, and Data Separation: Guided Hands-On Workflow and Core Operations

Inspect blob stores and database mode, create disposable file blob stores and hosted repositories, measure deterministic growth, and move exact accepted bytes without touching Nexus internals.

Community labFile blob storesRaw hostedStorage evidenceExact-byte transfer

Learning objectives

  • Capture before-state for blob stores, repositories, database mode, and free disk.
  • Create two disposable file blob stores and deliberately map Raw hosted repositories to them.
  • Generate deterministic payloads and compare expected bytes with Nexus used-size/blob-count evidence.
  • Transfer the exact Nexus-served bytes into another hosted repository while preserving SHA-256 identity.
  • Distinguish the free Community workflow from the Pro-only Change Repository Blob Store task and clean up safely.

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.

Lab scope: use only the disposable loopback instance. The names academy-ch05-fast, academy-ch05-capacity, academy-ch05-hot, and academy-ch05-archive are reserved for this lesson. Never point these steps at a production data directory or valuable repository.

1. Preflight: prove the instance is writable and has headroom

Storage work begins with evidence. Save the service writable state, existing blob stores, repositories, and free disk. If the lab host is close to the 4 GB emergency threshold, stop instead of using the lesson to “see what happens.”

# POSIX/Bash. Use only against the disposable loopback instance.
LAB="$HOME/nexus-ch05-lab"
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"

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.

From Settings → Support → System Information, record the database mode. The Chapter 02 disposable baseline is H2. This inspection is intentionally product-level; do not read or modify database internals.

2. Create two file blob stores through Nexus

Navigate to Settings → Repository → Blob Stores → Create Blob Store → File. Create these two stores with no soft quota yet:

Blob store File path Reason
academy-ch05-fast academy-ch05-fast (relative lab path) Hot/source content for measured writes.
academy-ch05-capacity academy-ch05-capacity (relative lab path) Separate destination so repository placement is observable.

A relative file path is Nexus-managed under the configured data/blob area. The process account must have access. Do not pre-create internal blob files or fix a permission problem by switching Nexus to root.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/blobstores"   | tee "$LAB/evidence/05-blobstores-created.json"

for b in academy-ch05-fast academy-ch05-capacity; do
  curl --fail-with-body --silent --show-error --netrc-file "$NETRC"     "$NX_URL/service/rest/v1/blobstores/file/$b"     | tee "$LAB/evidence/06-$b-config.json"
done

The returned path/configuration is the supported source of truth for this exercise. There is no need to open blob-store property files.

3. Map repositories to blob stores

Create two raw (hosted) repositories through Settings → Repository → Repositories:

Repository Blob store Write policy Purpose
academy-ch05-hot academy-ch05-fast Allow Source of synthetic growth.
academy-ch05-archive academy-ch05-capacity Allow once Destination that models stricter release/archive placement.

The mapping itself is database/configuration state. It does not copy content. The blob store grows when repository assets are written.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/repositorySettings"   > "$LAB/evidence/07-repository-settings-after.json"

python3 - <<'PY'
import json, pathlib
p = pathlib.Path.home()/"nexus-ch05-lab/evidence/07-repository-settings-after.json"
for r in json.loads(p.read_text()):
    if r.get("name") in {"academy-ch05-hot", "academy-ch05-archive"}:
        print(json.dumps(r, indent=2, sort_keys=True))
PY

4. Generate deterministic measurable content

Create harmless files whose size and SHA-256 are known before publication. No package hooks or public upstreams are involved.

python3 - <<'PY'
from pathlib import Path
import hashlib
root = Path.home()/"nexus-ch05-lab/payload"
root.mkdir(parents=True, exist_ok=True)
for mib, byte in [(1,b"A"), (2,b"B"), (4,b"C")]:
    p = root/f"payload-{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"
wc -c "$LAB"/payload/*.bin | tee "$LAB/evidence/09-local-bytes.txt"

5. Measure blob stores before and after publication

Save the pre-write blob-store view, then publish all three files only to the hosted academy-ch05-hot repository. Raw hosted repositories support direct HTTP PUT.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/blobstores"   | tee "$LAB/evidence/10-blobstores-pre-upload.json"

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-hot/growth/$name"
done

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/blobstores"   | tee "$LAB/evidence/11-blobstores-post-upload.json"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/assets?repository=academy-ch05-hot"   | tee "$LAB/evidence/12-hot-assets.json"

Do not expect Used Size to increase by exactly 7 MiB. Blob stores include per-blob properties/metadata and filesystem allocation overhead. The important causal observation is that the store assigned to academy-ch05-hot changes while the untouched destination store does not acquire those assets.

6. Community-compatible relocation: move accepted bytes, not internals

The current Admin - Change repository blob store task is Pro-only. Community learners should not simulate it by copying obfuscated blob files. Instead, model a safe content transition at the repository interface: download the exact accepted object from the source repository, verify its SHA-256, and publish the same bytes to the intentionally mapped destination repository.

SRC="$NX_URL/repository/academy-ch05-hot/growth/payload-4MiB.bin"
DST="$NX_URL/repository/academy-ch05-archive/release/payload-4MiB.bin"

curl --fail-with-body --silent --show-error   "$SRC" -o "$LAB/move/retrieved-4MiB.bin"

sha256sum "$LAB/payload/payload-4MiB.bin" "$LAB/move/retrieved-4MiB.bin"   | tee "$LAB/evidence/13-before-transfer-sha256.txt"
cmp "$LAB/payload/payload-4MiB.bin" "$LAB/move/retrieved-4MiB.bin"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   --upload-file "$LAB/move/retrieved-4MiB.bin" "$DST"

curl --fail-with-body --silent --show-error   "$DST" -o "$LAB/move/archive-4MiB.bin"

sha256sum "$LAB/move/retrieved-4MiB.bin" "$LAB/move/archive-4MiB.bin"   | tee "$LAB/evidence/14-after-transfer-sha256.txt"
cmp "$LAB/move/retrieved-4MiB.bin" "$LAB/move/archive-4MiB.bin"

This is not the same operation as changing a repository’s backing blob store. It is a free-path teaching model for exact-byte content movement. A Pro operator performing a real repository backing-store change must use the documented task and its version/database prerequisites.

7. Observe storage and quota signals

Capture final blob counts/used size and the destination quota-status endpoint. With no quota configured, the endpoint should not report a violation. Lesson 4 deliberately introduces a soft-quota warning without exhausting disk.

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/blobstores"   | tee "$LAB/evidence/15-blobstores-final.json"

curl --fail-with-body --silent --show-error --netrc-file "$NETRC"   "$NX_URL/service/rest/v1/blobstores/academy-ch05-capacity/quota-status"   | tee "$LAB/evidence/16-destination-quota.json"

df -h "$HOME" | tee "$LAB/evidence/17-disk-after.txt"

8. Challenge: choose the control before changing state

Your hot store is projected to fill in six weeks, but the repository itself is healthy. Which control belongs to which edition?

  • If you only need a Community learning path, create new storage/repository placement and move exact accepted content through supported repository endpoints.
  • If production requires changing the backing blob store of an existing repository, evaluate the documented Pro-only Change Repository Blob Store task and its prerequisites.
  • If the actual problem is merely early warning, use capacity monitoring/soft quota—not content movement—as the first control.

9. Pause or clean up

If you are continuing directly to Lesson 4, keep these four disposable objects because that lesson can use them. Otherwise delete the repositories first through Settings → Repository → Repositories, then delete the now-unused blob stores through Settings → Repository → Blob Stores. Nexus will not allow deletion of a blob store still in use. Never remove its files manually.

# Always remove the temporary credential file when you finish this session.
rm -f "$NETRC"
unset NETRC

Knowledge check

Why did only academy-ch05-fast grow after the first three uploads?

Why is the exact 7 MiB payload total not expected to equal the blob store Used Size delta?

Can Community Edition use the Change Repository Blob Store task?

What evidence proves the transferred release object preserved identity?

Should a nearly full store be fixed by deleting files under its blob path?

10. Summary

You mapped repositories to independent stores, measured causal growth, and moved exact accepted bytes without touching internal storage. The next lesson turns those observations into production architecture tradeoffs.

Next lesson

Storage design choices

Choose layouts, database, object storage, and headroom with explicit operational consequences.

Official references and version notes

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.