← All Posts
DevOps6 Aug 2026·14 min read

Docker for Homelabs: Install, Configure, and a Complete Command Cheatsheet

Srinivasa Rao Maganti — Lead Cloud & DevOps Trainer at CloudTechTrainings

Srinivasa Rao Maganti

Cloud Architect & Lead Trainer, CloudTechTrainings

#Docker#Homelab#Docker Compose#DevOps#Self-Hosting

Most homelabs end up running the same way: a Pi-hole for DNS, maybe Home Assistant, a media server, Nextcloud, a handful of small tools you found on a weekend — and every single one of them wants a different Python version, a different Node version, or a package that conflicts with something else already on the box. Docker exists to make that problem disappear. Each service runs in its own isolated container with its own dependencies, and your host OS only ever needs Docker itself installed. This is the install, the homelab-specific configuration most tutorials skip, and a complete command cheatsheet for everyday use.

Info: What This Covers

Docker Engine + Compose on Ubuntu/Debian, the two settings every homelab should change before running anything long-term (log rotation and storage location), a working Compose example, and a full command reference.

Installing Docker on Ubuntu / Debian

Skip the Ubuntu repo's docker.io package — it lags months behind. Install straight from Docker's own apt repository instead, which is what gets you the current Engine plus the Compose v2 plugin.

bash
# Remove any old or conflicting packages first
sudo apt-get remove docker docker-engine docker.io containerd runc

# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to apt sources
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Install Engine, CLI, containerd, and the Compose v2 plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Verify
sudo docker run hello-world

On Debian, swap ubuntu for debian in both URLs above — the rest of the command is identical.

Run Docker Without sudo

bash
sudo usermod -aG docker $USER
# Log out and back in (or reboot) — group membership doesn't apply to your
# current shell session until you do. Then confirm:
docker run hello-world

Warning: What That Group Actually Grants

Membership in the docker group is root-equivalent — anyone in it can mount the host filesystem into a container and read or write anything root can. Fine for your own single-user homelab box; don't add shared or low-trust accounts to it.

Start Docker on Boot

bash
sudo systemctl enable docker.service
sudo systemctl enable containerd.service

Configuring Docker for a Homelab

The default settings are built for a laptop running Docker for an afternoon, not a box running twenty containers for two years. Two changes matter before you put anything real on it.

1. Cap Container Logs

By default, Docker's json-file log driver has no size limit. A chatty container — Home Assistant with debug logging on, or a media server transcoding daily — will quietly fill your disk over a few months. Nothing crashes loudly; you just wake up to a full root partition.

json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Save that as /etc/docker/daemon.json (create the file if it doesn't exist), then restart Docker. This caps every container's logs at 3 files of 10MB each — old data ages out automatically instead of accumulating forever. It only applies to containers created after the change, so existing ones need a recreate (docker compose up -d -force-recreate) to pick it up.

2. Move Docker’s Storage Off the Boot Drive

Most homelab boxes boot from a small SSD and keep bulk storage on a separate drive or NAS mount. Docker defaults to /var/lib/docker on whatever disk that is — worth relocating before your image and volume data eats the drive your OS needs to boot.

bash
sudo systemctl stop docker

# Copy existing data to the new location (skip if this is a fresh install)
sudo mkdir -p /mnt/storage/docker
sudo rsync -aP /var/lib/docker/ /mnt/storage/docker/

Add data-root to the same daemon.json from step one:

json
{
  "data-root": "/mnt/storage/docker",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
bash
sudo mv /var/lib/docker /var/lib/docker.old
sudo systemctl start docker

# Confirm it's using the new path
docker info | grep "Docker Root Dir"

# Once you've verified everything still runs correctly:
sudo rm -rf /var/lib/docker.old

Docker Compose: Your First Homelab Stack

Almost nobody runs docker run by hand for long — a docker-compose.yml file that describes the whole service (image, ports, volumes, restart policy) in one place is the homelab standard. Here's Portainer, a web UI for managing containers, as a first real stack:

yaml
# docker-compose.yml
services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: unless-stopped
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

volumes:
  portainer_data:
bash
docker compose up -d      # create and start, detached
docker compose logs -f    # follow the logs
docker compose down       # stop and remove (volumes are kept)

Note: docker compose, Not docker-compose

Older tutorials use the standalone docker-compose (hyphen) Python tool, which is deprecated. The docker-compose-plugin installed above gives you docker compose (space) as a Docker subcommand instead — same YAML file, different invocation. If a guide's commands fail with "command not found," this is usually why.

The Cheatsheet

Container Lifecycle

CommandWhat It Does
docker run -d --name web -p 8080:80 nginxStart a new container in the background, named and port-mapped
docker psList running containers
docker ps -aList all containers, including stopped ones
docker stop <name>Gracefully stop a running container
docker start <name>Start a stopped container
docker restart <name>Restart a container
docker rm <name>Remove a stopped container
docker rm -f <name>Force-remove a running container

Images

CommandWhat It Does
docker pull <image>:<tag>Download an image without running it
docker imagesList locally stored images
docker rmi <image>Remove an image
docker build -t myapp:latest .Build an image from a Dockerfile in the current directory
docker tag myapp:latest myapp:v2Add another tag to an existing image
docker history <image>Show the layers that make up an image

Volumes & Networks

CommandWhat It Does
docker volume create mydataCreate a named volume for persistent storage
docker volume lsList volumes
docker volume inspect mydataShow where a volume actually lives on disk
docker network create mynetCreate a custom bridge network
docker network lsList networks
docker run --network mynet ...Attach a container to a specific network

Docker Compose

CommandWhat It Does
docker compose up -dCreate and start every service in docker-compose.yml, detached
docker compose downStop and remove containers and networks (volumes are kept)
docker compose down -vSame, and also delete named volumes — destructive
docker compose logs -f <service>Follow logs for one service
docker compose restart <service>Restart a single service without touching the rest of the stack
docker compose pullPull newer images for every service
docker compose psList containers managed by this compose file

Cleanup & Disk Space

CommandWhat It Does
docker system dfShow disk space used by images, containers, and volumes
docker system pruneRemove stopped containers, unused networks, and dangling images
docker system prune -a --volumesAlso remove unused images and volumes — reclaims the most space, most destructive
docker image pruneRemove only dangling (untagged) images
docker container pruneRemove all stopped containers

Inspecting & Debugging

CommandWhat It Does
docker logs -f <name>Follow a container's stdout/stderr
docker exec -it <name> shOpen a shell inside a running container
docker inspect <name>Full JSON dump of a container's config and state
docker statsLive CPU, memory, and network usage per container
docker top <name>Show the processes running inside a container

Common Homelab Gotchas

  • restart: unless-stopped missing from a compose file — the #1 reason a service doesn't come back after a power cut or reboot. Without it, Docker's default restart policy is none.
  • Permission denied on /var/run/docker.sock right after usermod -aG docker — the group change needs a fresh login session; newgrp docker works in the current shell but not for services started another way.
  • Bind mounts vs. named volumes — a bind mount (- /opt/appdata/pihole:/etc/pihole) puts data in a plain folder you can back up directly; a named volume (- pihole_data:/etc/pihole) is Docker-managed and lives under /var/lib/docker/volumes, which is easy to forget about until a backup script misses it.
  • Port conflicts on the host — two containers can't both bind host port 80. Map each to a unique host port (8080:80, 8081:80) or put a reverse proxy (Traefik, Caddy, Nginx Proxy Manager) in front once you're running more than a couple of web services.

Warning: If Your Router Port-Forwards to This Box

Don't publish a container's ports straight to 0.0.0.0 on a box reachable from the internet without a reverse proxy and TLS in front of it. -p 8080:80 is fine on your LAN; forwarded through your router with no proxy, it's an unauthenticated service exposed to the entire internet.

Everything above gets a single Docker host running reliably. The natural next question, once you're comfortable with it, is what changes when you need more than one host — that's what container orchestration (Kubernetes, or the lighter-weight Docker Swarm) actually solves.

For how that comparison actually plays out, see Kubernetes vs Docker Swarm. Our live Kubernetes and DevOps batches both start from exactly this — a single Docker host — before building up to production-grade, multi-node deployments.

Go Further

Ready to Start Your Cloud Journey?

Live batches Mon–Sat — Azure 9–10 AM IST (started 3 august 2026 — join in progress) · AWS 10:30–11:45 AM IST (starts 31 august 2026). Hands-on labs, exam prep, and community support.

Join Free Demo →WhatsApp Us

Keep Reading

DevOps

Terraform Policy as Code: Inside HashiCorp's New tfpolicy Framework

HashiCorp just introduced tfpolicy — a native, HCL-based policy-as-code framework built directly into Terraform. Here is what changed, how it compares to Sentinel and OPA, and how to start enforcing governance in the same language you already write infrastructure in.

2 Aug 2026·12 min read
Read →
DevOps

DevOps Training in Hyderabad — Live Online Course

Looking for DevOps training in Hyderabad? This guide covers what a DevOps engineering course covers, which tools you'll learn, target certifications (TF-003, AZ-400, CKA), and how to choose the right program.

25 Jun 2026·8 min read
Read →