Categories

Explainers

Hands-on labs

Hands-on lab

Upgrade Jellyfin from 10.11 to 12 in Docker with a Backup and Rollback

Upgrading Jellyfin from 10.11.11 to 12.0 in Docker requires copying the /config volume first, because 12.0 rewrites the database. In this lab you take the copy with a helper container, migrate, read version 12.0.0 from the API and confirm that going back only works by restoring that copy.

Hands-on lab

How to upgrade Gitea 1.27 to 28 with Docker without losing webhooks

To upgrade Gitea 1.27 to 28 with Docker, stop the container, back up the /data volume, delete the legacy egress keys from app.ini and change GITEA_TAG to 28.0.0. In this lab 28 starts with 13 migrations and 0 errors, and the repository and webhook created on 1.27.3 keep working.

Hands-on lab

How to Run OpenBao in Docker with Raft Storage

OpenBao is the MPL 2.0 secrets manager that keeps Vault's API. In this lab you run it in Docker with the 2.6.2 image and Raft storage, initialise it with 5 keys, unseal it with 3, store and read a secret in KV v2 and take a Raft snapshot as a backup.

Hands-on lab

llama.cpp server in Docker with an OpenAI-compatible API

llama-server, the llama.cpp server, serves a GGUF model with the same API as OpenAI. In this lab you run it in Docker with the server-v0.5.0 image, it downloads Qwen3.5 0.8B from Hugging Face into a volume, requires an API key and answers /v1/chat/completions on CPU only.

Hands-on lab

How to Fix the MinIO pull access denied Error in Docker

The MinIO pull access denied error appears because minio/minio no longer exists on Docker Hub. In this lab you confirm the 404 in its API, run cgr.dev/chainguard/minio with Docker Compose, fix the file access denied error with chown 65532 and create a bucket and an object with the Chainguard mc client.

Hands-on lab

Migrate MinIO to Garage step by step with rclone

To migrate MinIO to Garage, run Garage v2.4.1 next to MinIO in the same Compose project, create a key and the target bucket, copy with rclone sync and verify with rclone check --download. In this lab, 300 objects arrive with 0 differences and the imported MinIO key keeps reading them from Garage.

Hands-on lab

What DNS Is and How It Works (hands-on, with dig)

DNS (the Domain Name System) is the Internet's address book: it translates names like jacar.es into IP addresses. A recursive resolver walks the hierarchy —root, top-level domain and authoritative server— and caches the answer. In this lab you see it live with dig and run your own DNSSEC-validating resolver.

Hands-on lab

How to build an agentic VM with herdr and several AI CLIs

An agentic VM brings together on one machine the runtime that keeps several coding agents alive, a context all of them read and a remote way in. This lab builds it on Ubuntu with herdr, installs Claude Code, Codex, OpenCode and OpenClaw, and gives them one shared MCP memory.

Hands-on lab

How to Run a Private, Self-Hosted Docker Registry

A private Docker registry stores and serves your own container images without depending on Docker Hub. In this lab you run registry:3 with TLS, signed by your own CA that the client trusts, and htpasswd authentication: an anonymous push fails and, after docker login, you push and pull back an alpine image over HTTPS.

Hands-on lab

Multi-Stage Docker Builds: Smaller, More Secure Images

A multi-stage Docker build chains several FROM stages inside one Dockerfile: one compiles with the full toolchain, and the final, minimal stage (Alpine, scratch or distroless) copies only the resulting binary with COPY --from=build. The production image ends up far smaller, with a much smaller attack surface.

Hands-on lab

Docker Healthchecks and Restart Policies

A HEALTHCHECK tells Docker how to check whether a container is truly working, not just still running; docker inspect and docker ps surface that state as healthy or unhealthy. Restart policies decide what happens when the process fails: no, on-failure, always, or unless-stopped, and Compose can wait for a service to turn healthy before starting the next one.

Hands-on lab

Managing Secrets in Docker (without baking them into the image)

Docker secrets management means never leaving tokens or passwords in a Dockerfile's ARG, ENV, or COPY, because they get baked into the image forever. This lab demonstrates the real leak with docker history and fixes it with a BuildKit --secret, a read-only file mount, a scoped env-file, and Compose's native secrets.

Hands-on lab

Traefik Reverse Proxy with Docker

Traefik with Docker is a reverse proxy that reads the Docker socket and turns each container's labels into automatic routing rules. In this lab you bring it up alongside two backends and use curl to prove each hostname reaches the right container, without editing a single routes file.

Hands-on lab

Pihole in Docker (DNS Sinkhole)

Pi-hole is a DNS resolver that acts as a sinkhole: it filters every query on your network before it reaches the internet and blocks ad and tracking domains from its lists, answering 0.0.0.0 instead of forwarding them. In this lab you run it in Docker and prove it live with dig.

Hands-on lab

Docker Volume Backup and Restore

A Docker volume stores data outside the container, in a location Docker itself manages. To back it up, a throwaway alpine container mounts the volume and a host folder, then packs the data into a .tar.gz with tar. Restoring reverses the process: extract that file into a fresh volume and confirm the data comes back intact.

Hands-on lab

How to Build a Multi-Container App with Docker Compose

Docker Compose describes a multi-container application in a single YAML file: which services to run, how they talk to each other over the network, and which data persists in named volumes. In this lab you define an Nginx web service and a Redis cache, connect them by service name, and confirm it all works with curl.

Hands-on lab

How Data Persists in Docker with Volumes and Bind Mounts

A container is ephemeral, but its data doesn't have to be. A Docker volume lives outside the container, managed by Docker itself, while a bind mount uses a host path directly. In this lab we create a named volume, write data from one container, remove that container entirely, and read the same data back from a brand-new one.

Hands-on lab

Docker Networking (Bridge and Custom)

Docker attaches every container to a default bridge network, but that network only works by IP: it resolves no names. Create a user-defined network with docker network create and Docker turns on an internal DNS server, so containers reach each other by name and stay isolated from every other network.