Chapter 17Lesson 05250–330 min

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.

CheckpointTLS proofPublicationFirewall modelCleanup

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:

  1. 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.
  2. 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.
  3. 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?

Why must the wrong-host TLS test fail?

What is the expected relationship between client access to 443 and backend 8081?

Does HTTP 403 from the edge prove the publisher lacks Nexus privileges?

Which files are forbidden from the evidence packet?

Official references and version notes

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.