Docker basics for homelabbers
Almost every build on this site runs inside Docker. If you’ve never touched it, this page gets you to the point where the instructions in the articles make sense. You don’t need to understand everything about Docker to use it well. I certainly didn’t when I started.
What Docker actually is
A container is a program packaged together with everything it needs to run: the right version of Python, its libraries, its config defaults. You run that package on your machine, and it behaves the same way it did on mine. That’s the whole trick, and it’s why I can hand you a build and say “this will work” with a straight face.
A container is not a virtual machine. A VM pretends to be a whole computer, with its own operating system. A container shares your machine’s operating system and only brings its own app and libraries, so it starts in a second and uses very little memory. On a small mini PC that difference matters.
Three words you’ll see constantly:
- Image: the package, downloaded once. Think of it as the installer.
- Container: a running copy of an image. You can delete it and make a new one from the same image any time.
- Volume (or bind mount): a folder on your real disk that the container can see. This is where anything you want to keep lives, because the container’s own files are thrown away when you recreate it.
That last point catches everybody once. If an app saves its settings inside the container and you recreate the container, the settings are gone. Every build here maps a folder on your disk into the container for exactly that reason.
Installing Docker
On Ubuntu or Debian, Docker’s own convenience script is the quickest route:
curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.shsudo usermod -aG docker $USERLog out and back in after the last line. It adds you to the docker group so you don’t need sudo in front of every command. Check it worked:
docker run --rm hello-worldIf you see “Hello from Docker!”, you’re set.
Docker Compose: the part you’ll actually use
Typing long docker run commands gets old fast, and you’ll forget the exact flags you used three months ago. Docker Compose fixes that: you describe the container in a small text file called docker-compose.yml, keep it in a folder, and Compose does the rest.
Here’s a tiny but real example, a web server that shows a folder of files:
services: web: image: nginx:1.27 restart: unless-stopped ports: - "8080:80" volumes: - ./site:/usr/share/nginx/html:roReading it line by line:
imageis what to download.restart: unless-stoppedbrings it back after a crash or a reboot, unless you stopped it yourself. Every build here uses this.ports: "8080:80"means port 8080 on your machine goes to port 80 inside the container. Left side is yours, right side is the container’s.volumesmaps thesitefolder next to the compose file into the container. The:romakes it read-only inside.
The five commands you’ll type most
Run these from the folder that holds docker-compose.yml:
docker compose up -d # create/start everything in the backgrounddocker compose ps # is it running?docker compose logs -f # watch its output (Ctrl+C to stop watching)docker compose pull # download newer imagesdocker compose down # stop and remove the containers (volumes stay)After a pull, run up -d again to recreate the containers on the new image.
Settings in a .env file
Most kits keep their settings in a file named .env next to the compose file: one NAME=value per line. Compose reads it automatically. It’s where you’ll put things like your server’s address and API keys. Two habits worth having from day one:
- Never share your
.envfile or paste it into a forum post. It usually holds passwords and keys. - Keep a copy of it somewhere safe. It’s the one file you’d have to recreate by hand.
Where I tripped up early
- “It says healthy, but it’s broken.” Docker’s “healthy” label only means the container’s own health check passed, and some health checks are lazy. If a service seems down, test the thing itself: open the web page, or check the port.
- Port already in use. If
up -dfails with “address already in use”, something else on the machine owns that port. Change the left-hand number inports. - Forgot the volume. Recreate a container that has no volume and its settings are gone. Check the
volumessection before you rely on anything.
Next up: SSH and keys, which is how you’ll get onto the box that runs all this.