Module 6 · Labs
These five labs assemble everything the curriculum has built into a running, public, self-hosted platform. The capstone (Lab 5) is the moment the loop closes: your portfolio, hosting your writeups, live on your own hardware, reachable through your own tunnel. Commit your Compose files and configs (secrets stripped) as you go — that repository is itself part of the deliverable.
Lab 1 · First stack
Section titled “Lab 1 · First stack”Goal: deploy a service with Docker Compose and prove your data survives the container. Exercises Lesson 6.1.
- Install Docker on your server (or a VM on your Module 4 Proxmox host).
- Write a
compose.yamlfor any simple service that stores data (e.g. a small wiki, a note app, or even nginx serving a mounted directory). Give it a named volume for its data. docker compose up -d; confirm it runs (docker compose ps,docker compose logs -f).- Write some data into the service (a note, a page).
- The proof:
docker compose down(removes the container), thendocker compose up -d(recreates it). Confirm your data is still there — because it was in the volume, not the container. - Bonus: change something in the Compose file, re-up, and observe declarative behavior.
Verify
Section titled “Verify”- The service is defined entirely in a committed
compose.yaml. - Its data lives in a volume and survived a container destroy/recreate.
- You can read the logs and status with
docker composecommands.
Commit
Section titled “Commit”Start a homelab/ (or compose/) directory in your repo with this stack’s compose.yaml and a
.env.example. Never commit the real .env.
Lab 2 · Front door
Section titled “Lab 2 · Front door”Goal: put a reverse proxy in front of multiple services, each on its own hostname with valid TLS. Exercises Lessons 6.2 and 6.3.
- Add Caddy (recommended) as a container in your Compose stack, on the same Docker network as your services.
- Run three services (e.g. your Lab 1 app, a dashboard, and one more), each on its own internal port.
- Write a Caddyfile routing three hostnames to the three services
(
app.yourdomain.com,home.yourdomain.com, …). Point those names at your setup via DNS (Lesson 1.3). - Confirm each hostname reaches the right service and shows a valid TLS certificate (the
padlock; verify with
curl -vI https://...).
Verify
Section titled “Verify”- Three services sit behind one reverse proxy, routed by hostname.
- Each has a valid, browser-trusted certificate.
- Only the proxy is exposed; the backends aren’t individually reachable from outside.
Commit
Section titled “Commit”Add the Caddyfile and updated Compose to homelab/. Document which hostname maps to what.
Lab 3 · DNS-01
Section titled “Lab 3 · DNS-01”Goal: obtain a wildcard certificate via the DNS-01 challenge — TLS with no inbound ports. Exercises Lesson 6.3.
- Get a DNS-provider API token (e.g. Cloudflare), scoped as narrowly as possible (DNS edit only). It’s a secret — keep it out of git.
- Configure your proxy (Caddy with the DNS provider plugin, or certbot with the DNS plugin) to
use DNS-01 and request a wildcard certificate (
*.yourdomain.com). - Confirm issuance succeeds without any inbound port 80/443 reachable from the internet.
- Verify the wildcard cert covers multiple subdomains (
a.yourdomain.com,b.yourdomain.com) withopenssl s_client/curl -vI. - Write up why DNS-01 is the elegant choice for a no-open-ports homelab (tie it to Module 5 and DNS from Lesson 1.3).
Verify
Section titled “Verify”- A wildcard certificate was issued via DNS-01, with no inbound ports open.
- Multiple subdomains are covered by the one certificate.
- You can explain the DNS-01 flow and why it suits your architecture.
Commit
Section titled “Commit”homelab/tls.md documenting the DNS-01 setup (sanitized — no API token) and the reasoning.
Lab 4 · Self-host your git
Section titled “Lab 4 · Self-host your git”Goal: stand up your own git server and migrate your work onto it. Exercises Lesson 6.4.
- Add Forgejo (or Gitea) to your Compose stack, with a volume for its data, behind the proxy
at
git.yourdomain.comwith TLS. - Create your account; add your SSH key (Lesson 0.2) so you push over SSH.
- Migrate your curriculum repo to it. Push a commit to your own git server and confirm it lands.
- (Recommended) Keep a GitHub mirror as an offsite copy (3-2-1) and for the public showcase.
- Ensure the Forgejo volume is included in your backups (Lesson 4.3).
Verify
Section titled “Verify”- A self-hosted git server runs behind your proxy with valid TLS.
- You pushed a commit to it over SSH.
- Its data volume is backed up.
Commit
Section titled “Commit”Naturally — commit this to the git server you just built. Add its Compose service to homelab/.
Lab 5 · Publish the portfolio
Section titled “Lab 5 · Publish the portfolio”This is the module’s deliverable and the curriculum’s turning point. Get your documentation site live, publicly, on your own hardware — closing the loop. Exercises everything.
- Deploy your blog/docs site (a static site — Hugo/Astro — or Ghost) as a service in your stack, behind the proxy with TLS.
- Publish it to the public internet via Cloudflare Tunnel (Lesson 5.3)
at a real domain — zero open inbound ports (verify with an external
nmap, as in Lab 5.4). - Publish your writeups. Put every artifact you’ve produced so far on the site:
- the packet-capture walkthrough (Module 1)
- the server build log + hardening checklist (Module 2)
- the network diagram + segmentation rationale (Module 3)
- the verified restore demo (Module 4)
- the remote-access ADR (Module 5)
- your original first blog post (Module 0)
- Confirm the whole loop: the site is built from code in your self-hosted git, served by your proxy with TLS, through your tunnel, on your hardened server, and it documents that same infrastructure.
- Submit to the showcase via a pull request.
Verify
Section titled “Verify”- Your site is live at a real domain, on your own hardware, with valid TLS and zero open ports.
- It hosts your writeups from every module so far.
- The site is built from a repo on your self-hosted git server.
- You submitted your URL to the showcase.
Commit & publish
Section titled “Commit & publish”git add homelab/git commit -m "Add self-hosted site + git server; publish portfolio"git push # to your own git server nowThen open the showcase PR. When it merges, your self-hosted site is publicly listed — the final exercise in the exact git/writing/PR workflow this curriculum taught.
Module 6 checkpoint
Section titled “Module 6 checkpoint”- I deploy services declaratively with Compose files kept in git (Lab 1)
- All my services sit behind one reverse proxy with valid TLS (Lab 2)
- I can obtain and auto-renew certificates, including via DNS-01 (Lab 3)
- My blog is live at a real domain on my own hardware (Lab 5)
- My code lives on a git server I host myself (Lab 4)
- Every service is backed up and reachable through my overlay network (all labs)
Deliverable
Section titled “Deliverable”Your live, self-hosted portfolio site and git server (Lab 5): publicly reachable, TLS-valid, built from code on your own git server, hosting all your writeups — the closed loop, submitted to the showcase. This is the single most important artifact in the curriculum: it is your portfolio, and it works because you made every layer beneath it work.
Next module: Module 7 · Automation & CI/CD → — where you automate all of this so you never build it by hand again.