Checkpoint Lab — TLS, Reverse Proxies, Context Paths, HTTP Settings, Network Boundaries, and Secure Exposure
Publish one synthetic artifact through a locally secured reverse-proxy endpoint, prove certificate, hostname, headers, package identity, insecure-path rejection, and intended network zones, then clean up only lab state.
Learning objectives
- Predict state changes before a secure publication.
- Prove HTTPS certificate identity and reject an insecure HTTP path.
- Publish/download identical bytes through a local reverse proxy and verify SHA-256.
- Produce an evidence packet and network-zone/firewall runbook without secrets or private keys.
- Remove only the disposable repository, identity, proxy process, and local certificate fixture.
1. Checkpoint mission
You are preparing a repository endpoint for a team that must publish through HTTPS while the Nexus backend remains private. Your deliverable is not merely a successful upload. It is an evidence packet proving the certificate name, TLS chain, forwarded-edge request, repository write, byte identity, rejection of plain HTTP, and intended backend/firewall boundary.
Disposable-only checkpoint. Use a local self-hosted Community instance and synthetic names. Do not change corporate DNS, a production reverse proxy, employer certificates, production firewall rules, shared Nexus listeners, or valuable repositories. The local certificate private key and credential file are temporary secrets and must not enter the evidence packet.
Version baseline (26 August 2026). The official Sonatype download and archive pages list Nexus Repository 3.95.0, build 3.95.0-07, as the current self-hosted download. Nexus Repository 3.87+ uses Java 21 and official installers include a bundled Java 21 runtime. Record the version actually running in your lab before applying any example.
2. Exact assumptions and preflight
| Item | Checkpoint assumption | Record |
|---|---|---|
| Nexus | Self-hosted Community, official 3.95.0-07 reference baseline; record actual running version | status.json |
| Runtime | Bundled Java 21 on current official packages | System Information / startup evidence |
| Database | Small local H2 acceptable for this non-container disposable lab; PostgreSQL recommended production | Architecture note |
| Blob | Default local file blob store for one Raw repository | Repository configuration screenshot/note |
| Backend | 127.0.0.1:8081 only |
Listener evidence |
| Edge |
Python TLS fixture 127.0.0.1:8443; HTTP deny
127.0.0.1:8080
|
Proxy log |
| Hostname |
nexus.lab.test mapped per-request with
--resolve
|
Client command |
| Repository |
academy-ch17-checkpoint Raw hosted, Allow once
|
Repository state |
| Identity |
academy-ch17-cp-publisher, only required repo
privileges
|
Authorization note |
3. Write predictions before changing state
Record at least these predictions in
predictions.md before the first upload:
- A successful HTTPS PUT will create one Raw asset’s Nexus metadata plus blob bytes, but it will not change the TLS certificate or reverse-proxy configuration.
- A GET through HTTPS will return bytes identical to the producer file; an HTTP request to the lab edge will be rejected before Nexus repository authorization is evaluated.
- The backend listener will remain reachable locally but not be an intended client endpoint; in a production network, only the reverse-proxy tier would be permitted to reach it.
4. Set up the secured local edge
Reuse the Lesson 2 method, but use fresh checkpoint names. Capture
the original Nexus runtime properties, ensure
application-host=127.0.0.1, and restart only the
disposable instance. Generate a new two-day certificate with SAN
DNS:nexus.lab.test. Start the same TLS proxy fixture
and plain-HTTP deny listener.
export LAB="$HOME/nexus-ch17-checkpoint"
mkdir -p "$LAB/evidence" "$LAB/cert"
# After generating the checkpoint certificate and starting the fixture:
openssl x509 -in "$LAB/cert/nexus.lab.test.crt" -noout \
-subject -issuer -dates -fingerprint -sha256 -ext subjectAltName \
> "$LAB/evidence/certificate.txt"
curl --fail --cacert "$LAB/cert/nexus.lab.test.crt" \
--resolve nexus.lab.test:8443:127.0.0.1 \
https://nexus.lab.test:8443/service/rest/v1/status \
> "$LAB/evidence/status.json"
5. Create the disposable repository and publisher
Create Raw hosted repository
academy-ch17-checkpoint using the default blob store,
strict content validation, and Allow once. Create
academy-ch17-cp-publisher with only
browse/read/add/edit privileges for this repository. Do not grant
delete, wildcard repository access, security administration, or
nx-admin.
Before publication, Browse/Search should show no checkpoint asset.
Save that observation as repository-before.txt or a
screenshot outside the ZIP if desired.
6. Prepare a secret that never enters the evidence packet
export NX_USER='academy-ch17-cp-publisher'
read -r -s -p 'Checkpoint publisher password: ' NX_PASS; echo
export AUTH_FILE="$(mktemp)"
chmod 600 "$AUTH_FILE"
printf 'machine nexus.lab.test login %s password %s
' "$NX_USER" "$NX_PASS" > "$AUTH_FILE"
unset NX_PASS
# Never print or copy AUTH_FILE.
7. Validate TLS hostname and chain
openssl s_client -connect 127.0.0.1:8443 -servername nexus.lab.test \
-CAfile "$LAB/cert/nexus.lab.test.crt" </dev/null 2>&1 \
| grep -E 'subject=|issuer=|Verify return code' \
| tee "$LAB/evidence/tls-valid.txt"
# Negative proof: same socket, wrong hostname.
set +e
curl --cacert "$LAB/cert/nexus.lab.test.crt" \
--resolve wrong.lab.test:8443:127.0.0.1 \
https://wrong.lab.test:8443/service/rest/v1/status \
2>"$LAB/evidence/tls-wrong-host.txt"
printf 'wrong-host curl exit=%s
' "$?" >> "$LAB/evidence/tls-wrong-host.txt"
set -e
The negative test must fail because the requested hostname is absent
from the SAN. Do not add -k to make it pass.
8. Publish one synthetic package-shaped artifact through HTTPS
cat > "$LAB/academy-network-package-1.0.0.txt" <<'EOF'
name=academy-network-package
version=1.0.0
purpose=chapter-17-checkpoint
content=synthetic non-secret training artifact
EOF
sha256sum "$LAB/academy-network-package-1.0.0.txt" \
| tee "$LAB/evidence/producer.sha256"
export SECURE_URL='https://nexus.lab.test:8443/repository/academy-ch17-checkpoint/com/example/academy/network/1.0.0/academy-network-package-1.0.0.txt'
curl --fail --show-error --cacert "$LAB/cert/nexus.lab.test.crt" \
--resolve nexus.lab.test:8443:127.0.0.1 --netrc-file "$AUTH_FILE" \
--upload-file "$LAB/academy-network-package-1.0.0.txt" "$SECURE_URL"
curl --fail --show-error --cacert "$LAB/cert/nexus.lab.test.crt" \
--resolve nexus.lab.test:8443:127.0.0.1 --netrc-file "$AUTH_FILE" \
-o "$LAB/consumer.txt" "$SECURE_URL"
sha256sum "$LAB/consumer.txt" | tee "$LAB/evidence/consumer.sha256"
cmp "$LAB/academy-network-package-1.0.0.txt" "$LAB/consumer.txt"
9. Prove the insecure edge path is rejected
curl -sS -i \
http://127.0.0.1:8080/repository/academy-ch17-checkpoint/com/example/academy/network/1.0.0/academy-network-package-1.0.0.txt \
| tee "$LAB/evidence/http-rejected.txt"
grep -q '403' "$LAB/evidence/http-rejected.txt"
This rejection is performed by the edge fixture. It must not be interpreted as a Nexus authorization result. That distinction is part of the checkpoint.
10. Capture forwarded-edge and Nexus evidence
tail -n 40 "$LAB/evidence/proxy.log" > "$LAB/evidence/proxy-tail.txt"
tail -n 50 "$NEXUS_DATA/log/request.log" 2>/dev/null \
> "$LAB/evidence/nexus-request-tail.txt" || true
# Through the Nexus UI or read-only REST API, record:
# repository name, format/type, exact asset path, size, and checksum fields if exposed.
# Do not inspect or copy raw blob files.
Expected proxy evidence includes
forwarded_proto=https and external host
nexus.lab.test:8443. Expected Nexus evidence shows the
PUT/GET path and the created Raw asset through supported repository
state.
11. Document intended network zones and firewall rules
Create $LAB/evidence/network-boundary.md with a table
like this, adapted to your real production design without changing
any real firewall during this lab.
| Source zone | Destination | Port | Expected | Reason |
|---|---|---:|---|---|
| Developer/CI | Repository edge | 443 | ALLOW | Approved package traffic |
| Developer/CI | Nexus backend | 8081 | DENY | Prevent edge bypass |
| Reverse proxy | Nexus backend private IP | 8081 | ALLOW | Backend request path |
| Public internet | Admin-only edge/path | 443 | DENY | Administration is private |
| Admin VPN/bastion | Admin edge/path | 443 | ALLOW | Privileged operations |
| Nexus backend | Required upstream registries | policy-defined | ALLOW selectively | Proxy repositories only |
The lab proves the first-order model locally. A production acceptance test should run reachability checks from actual network zones under change-control.
12. Verification checklist and evidence packet
| Evidence | Pass condition |
|---|---|
certificate.txt |
SAN contains nexus.lab.test; certificate is
short-lived synthetic lab material.
|
tls-valid.txt |
TLS verification return code is successful. |
tls-wrong-host.txt |
Wrong hostname fails verification; no insecure bypass used. |
producer.sha256 + consumer.sha256
|
Hashes match exactly. |
http-rejected.txt |
Plain HTTP edge returns 403. |
proxy-tail.txt |
Shows HTTPS forwarded scheme and intended host/path. |
| Nexus Browse/API evidence |
Exact asset exists in academy-ch17-checkpoint.
|
| Listener evidence | Backend is loopback/private according to the lab architecture. |
network-boundary.md |
Documents allow/deny intent for client, edge, backend, and admin zones. |
Evidence hygiene. The evidence packet must not
contain AUTH_FILE, publisher password, TLS private
key, Authorization headers, production DNS names, or production
firewall configurations.
13. Cleanup and rollback
First delete the disposable repository through Nexus supported controls, then remove the disposable publisher. Stop the proxy process. Restore the original listener configuration if it was changed for this lab and restart the disposable instance. Finally remove the exact temporary credential and certificate files.
kill "$PROXY_PID" 2>/dev/null || true
rm -f "$AUTH_FILE"
rm -f "$LAB/cert/nexus.lab.test.key" "$LAB/cert/nexus.lab.test.crt"
# Restore saved nexus.properties if changed, then restart the disposable Nexus instance.
# Remove academy-ch17-checkpoint and academy-ch17-cp-publisher in Nexus UI/API.
14. What Chapter 17 adds to the operating model
You can now document not only which repository exists and who may use it, but how requests are permitted to reach it: canonical hostname, certificate owner, reverse-proxy route, forwarded-header contract, Nexus listener/context, package/admin audience, and firewall boundary. This makes network exposure testable and recoverable rather than an implicit collection of proxy snippets.
Chapter 18 moves from exposure to lifecycle: cleanup policies, retention criteria, preview, and physical storage reclamation. The same discipline continues—policy first, evidence second, least-destructive execution third.
15. Knowledge check
Why does the checkpoint hash producer and consumer bytes?
To prove the secure publication and retrieval preserved exact artifact bytes; the hash does not prove provenance or vulnerability safety.
Why must the wrong-host TLS test fail?
Because certificate hostname verification is part of the security property; accepting the wrong host would show verification was bypassed or misconfigured.
What is the expected relationship between client access to 443 and backend 8081?
Approved clients reach the edge; the backend is reachable only from the trusted proxy/private path, not directly from normal client zones.
Does HTTP 403 from the edge prove the publisher lacks Nexus privileges?
No. The edge rejects insecure transport before Nexus authorization is evaluated.
Which files are forbidden from the evidence packet?
Temporary credential files, passwords/tokens, Authorization headers, and TLS private keys.
Official references and version notes
- Sonatype: Run Behind a Reverse Proxy — production reverse-proxy and forwarded-header guidance.
- Sonatype: Configuring the Runtime Environment — listener and context-path configuration.
- Sonatype: Configuring SSL — inbound TLS options and certificate configuration.
- Sonatype: System Requirements — Java 21 and database/storage production guidance.
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.