Infrastructure beginner ⏱ 45 minutes

Docker Basics for Homelabs: Your First Steps into Containerization

Learn Docker fundamentals for your homelab. From installation to Docker Compose, with AI-assisted automation tips.

By homelabbing.io • 2025-12-16
#docker#containers#beginner#infrastructure

Introduction

Here’s a stat that might surprise you: homelabbers are now routinely running 30+ services efficiently on hardware with just 4GB of RAM. Some enthusiasts are managing 100+ containers on a 3-node Proxmox cluster. How? Docker.

This isn’t just an incremental improvement over traditional virtual machine setups - it’s a complete paradigm shift. Where you once needed to carefully allocate resources to a handful of VMs, you can now deploy dozens of lightweight containers in minutes, each running its own service without the overhead of a full operating system.

Think about the last time you set up a new service in your homelab. How long did it take? How many configuration files did you edit? How many times did you check the documentation? With Docker, that same deployment becomes a single command: docker compose up -d. Your entire stack - database, application, reverse proxy, and all - springs to life in seconds.

We’re living in a pivotal moment for homelabbers. In 2025, containerization is converging with AI-driven automation, creating opportunities that seemed impossible just a few years ago. Non-technical users can now deploy complex, enterprise-grade infrastructure with the help of AI agents that handle the complexity behind the scenes.

By the end of this guide, you’ll:

  • Understand what Docker is and why it’s essential for modern homelabs
  • Have Docker installed and running on your platform of choice
  • Deploy your first containerized services using Docker Compose
  • Know how to secure, troubleshoot, and optimize your containers
  • Discover how AI can help you manage your Docker homelab

Tired of spending hours setting up and maintaining individual services? Docker changes everything. Let’s dive in.


Prerequisites

Before we begin, let’s make sure you have what you need to follow along successfully.

Hardware Requirements

Minimum Specifications:

  • CPU: 2 cores (4+ recommended for running multiple services)
  • RAM: 4GB minimum (8GB+ for running 10+ containers comfortably)
  • Storage: 20GB+ free space, preferably on SSD or NVMe for better performance
  • Network: 1Gbps Ethernet connection recommended

Common Homelab Platforms:

  • Desktop or laptop running Linux
  • Repurposed server hardware (Dell PowerEdge, HP ProLiant, old Mac Minis)
  • Raspberry Pi 4 or 5 (suitable for lightweight deployments)
  • Proxmox VE cluster (the gold standard for homelab virtualization)

Software Prerequisites

Supported Operating Systems:

  • Ubuntu Server (most documentation and community support)
  • Debian (stable, reliable alternative)
  • Rocky Linux (RHEL-based option)
  • Alpine Linux (minimal footprint for advanced users)
  • Proxmox VE (running Docker inside a VM or LXC container)

Important Note for Proxmox Users:

The recommended approach is running Docker inside a dedicated VM or LXC container, NOT directly on the Proxmox host. Installing Docker on the Proxmox host itself can cause:

  • Network conflicts with Proxmox’s virtual networking
  • Complications with system updates
  • More complex backup and recovery procedures
  • Potential instability

If you’re using Proxmox, you’ll create either a VM or LXC container first, then install Docker inside that environment.

Knowledge Assumptions

You should be comfortable with:

  • Linux command line basics (navigating directories, editing files, running commands)
  • Basic networking concepts (IP addresses, ports, DNS)
  • YAML syntax (optional but helpful for Docker Compose files)

Don’t worry if you’re not an expert - we’ll explain everything as we go. If you can SSH into a server and run a few commands, you’re ready to start.


Docker Fundamentals

What is Docker?

Docker is a containerization platform that packages applications with all their dependencies - code, libraries, system tools, and configurations - into isolated, portable units called containers.

Here’s the key difference from virtual machines: instead of virtualizing entire operating systems (which requires significant RAM and CPU), containers share the host system’s kernel. This makes them incredibly lightweight and fast to start.

The Architecture Comparison:

Traditional Virtual Machines:
┌─────────────────────────────────────────┐
│         Hypervisor Host                 │
├─────────────────────────────────────────┤
│  VM 1        │  VM 2        │  VM 3     │
│  Guest OS    │  Guest OS    │  Guest OS │
│  (1GB RAM)   │  (1GB RAM)   │  (1GB RAM)│
│  App         │  Database    │  Proxy    │
└─────────────────────────────────────────┘
   3GB RAM just for operating systems!

Docker Containers:
┌─────────────────────────────────────────┐
│         Docker Host                     │
├─────────────────────────────────────────┤
│  Container 1 │  Container 2 │  Cont 3   │
│  (50MB)      │  (100MB)     │  (20MB)   │
│  App         │  Database    │  Proxy    │
├─────────────────────────────────────────┤
│       Shared Docker Engine & Kernel     │
├─────────────────────────────────────────┤
│       Ubuntu/Debian Base OS             │
└─────────────────────────────────────────┘
   170MB total for all three services!

Core Container Benefits:

  1. Lightweight: Containers share the host OS kernel, so they use a fraction of the resources that VMs require. A typical container might use 50-200MB of RAM, while a VM needs at least 512MB-1GB just for the guest OS.

  2. Portable: A container runs identically whether deployed on your laptop, homelab server, or cloud platform. “It works on my machine” is no longer an excuse.

  3. Isolated: Containers are sandboxed from each other and the host system, providing security boundaries without the overhead of full virtualization.

  4. Fast: Containers start in seconds (sometimes milliseconds), compared to minutes for traditional VMs.

Why Docker is Essential for Homelabs

The homelab community has wholeheartedly embraced Docker, and for good reason:

1. Simplification

Installing and managing 30+ services becomes trivial compared to traditional approaches. Instead of spending hours manually configuring each service, you can deploy entire stacks with a single command: docker compose up -d.

Consider this: deploying a media server stack (Jellyfin + database + reverse proxy + SSL certificates) traditionally might take 2-3 hours of configuration. With Docker Compose, it takes less than 5 minutes.

2. Resource Efficiency

Real-world example: A homelab enthusiast documented running 100+ containers on a modest 3-node Proxmox cluster. That same hardware couldn’t handle even 20 VMs comfortably. Docker’s shared kernel architecture means you can run dramatically more services on the same hardware.

3. Rapid Experimentation

Want to test a new note-taking app? With Docker, you can have it running in under a minute:

docker run -d -p 8080:80 --name notes trilium

Don’t like it? Remove it completely with:

docker rm -f notes

No leftover configuration files, no system modifications, no cleanup headaches.

4. Backup & Recovery

Your entire infrastructure can be backed up as simple text files (Docker Compose YAML files) plus data volumes. Recovery from disaster is as simple as:

# Restore your compose files
cd /opt/docker/homelab
docker compose up -d

Minutes instead of days to rebuild your entire homelab.

5. Standardization

Containers ensure consistency across environments. Your development, testing, and production deployments all use exactly the same containerized application, eliminating the “works in development, breaks in production” problem.

Container Architecture: A Deeper Look

Understanding how containers work under the hood helps you make better decisions when designing your homelab.

Key Components:

  • Images: The blueprint for containers. Think of an image as a frozen snapshot of an application and all its dependencies. Images are stored in registries like Docker Hub.

  • Containers: Running instances of images. You can create multiple containers from the same image, each with its own isolated environment.

  • Docker Engine: The runtime that manages containers, handles networking, storage, and isolation.

  • Docker Hub: A public registry where thousands of pre-built images are available. Need PostgreSQL? docker pull postgres:15. Need Nginx? docker pull nginx:latest.

When you run a container, Docker:

  1. Downloads the image (if not already cached)
  2. Creates an isolated filesystem from that image
  3. Sets up networking (virtual network interfaces, port mappings)
  4. Allocates resources (CPU, memory limits if specified)
  5. Starts the application inside the container

All of this happens in seconds, completely automatically.


Installation & Setup

Now let’s get Docker installed on your homelab. We’ll cover the three most common scenarios.

Step 1: Choose Your Platform

Option A: Docker in a Proxmox VM (Recommended)

This is the gold standard for Proxmox users:

  • Pros: Better isolation, snapshots/backups are easy, no conflicts with Proxmox, simpler disaster recovery
  • Cons: Slightly more resource overhead than LXC
  • When to choose: If you have 8GB+ RAM available and want maximum reliability

Setup Overview:

  1. Create an Ubuntu Server 22.04 or 24.04 VM in Proxmox
  2. Allocate at least 2 CPU cores, 4GB RAM, 20GB storage
  3. Install Docker inside the VM (we’ll show you how below)

Option B: Docker in a Proxmox LXC Container (Resource-Efficient)

For homelabs with limited resources:

  • Pros: Lower overhead than VMs, faster startup, less RAM usage
  • Cons: Requires kernel module configuration, slightly more complex
  • When to choose: If you’re running on hardware with 4-8GB RAM and need efficiency

Setup Overview:

  1. Create an Ubuntu LXC container in Proxmox
  2. Enable required kernel modules on the Proxmox host
  3. Install Docker inside the LXC container

Option C: Standalone Linux Server

Running Docker on dedicated hardware or a cloud VM:

  • Pros: Maximum performance, no hypervisor overhead, simplest to understand
  • Cons: No virtualization features (snapshots require different tools)
  • When to choose: If you have dedicated hardware or are using a cloud VPS

Setup Overview:

  1. Install Ubuntu Server, Debian, or your Linux distribution of choice
  2. Install Docker directly on the OS

Step 2: Install Docker

We’ll focus on the most common scenario: Ubuntu/Debian-based systems. The process is nearly identical for all three options above.

Method 1: Quick Installation Script (Fastest)

This is the easiest way to get started:

# Download Docker's official installation script
curl -fsSL https://get.docker.com -o get-docker.sh

# Run the installation script
sudo sh get-docker.sh

# Clean up
rm get-docker.sh

This script automatically detects your distribution and installs the latest Docker version. It’s quick and convenient, but offers less control over the installation process.

This method gives you more control and is better for production homelabs:

# Update package index
sudo apt update

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg

# Create directory for Docker's GPG key
sudo install -m 0755 -d /etc/apt/keyrings

# Download and install Docker's GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |   sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Set proper permissions
sudo chmod a+r /etc/apt/keyrings/docker.gpg

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

# Update package index again
sudo apt update

# Install Docker and related packages
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

What we just installed:

  • docker-ce: Docker Community Edition (the main Docker engine)
  • docker-ce-cli: Command-line interface for Docker
  • containerd.io: Container runtime
  • docker-buildx-plugin: Modern build system for Docker images
  • docker-compose-plugin: Docker Compose for multi-container applications

Verify Installation

Confirm Docker is working:

# Check Docker version
docker --version
# Expected output: Docker version 24.0.x, build xxxxx

# Run the test container
docker run hello-world

If you see “Hello from Docker!” congratulations - Docker is installed and working!

Step 3: Post-Installation Configuration

By default, Docker commands require sudo. For convenience, add your user to the docker group:

# Add your user to the docker group
sudo usermod -aG docker $USER

# Activate the group changes
newgrp docker

# Test without sudo
docker ps

Security Note: Users in the docker group have root-equivalent access to the system (they can mount any host directory in a container). Only add trusted users to this group.

Verify Docker Compose

Modern Docker installations include Docker Compose as a plugin:

# Check Docker Compose version
docker compose version
# Expected output: Docker Compose version v2.x.x

Note the command format: docker compose (not docker-compose with a hyphen, which is the older standalone version).

Create a Proper Directory Structure

Organization is key to maintaining a homelab. Create a dedicated directory structure:

# Create main Docker directory
sudo mkdir -p /opt/docker

# Create subdirectories for organization
sudo mkdir -p /opt/docker/{apps,backups,data,configs}

# Set ownership to your user
sudo chown -R $USER:$USER /opt/docker

# Navigate to your Docker workspace
cd /opt/docker

Directory purposes:

  • /opt/docker/apps/ - Individual application compose files
  • /opt/docker/backups/ - Volume backups and snapshots
  • /opt/docker/data/ - Persistent data volumes
  • /opt/docker/configs/ - Configuration files and templates

Docker Basics & First Deployment

Now that Docker is installed, let’s understand how to use it.

Understanding Images vs. Containers

Images are templates - blueprints for creating containers. Think of an image as a frozen snapshot containing:

  • The application code
  • All dependencies and libraries
  • Configuration files
  • Filesystem structure

Containers are running instances created from images. One image can spawn multiple containers, each isolated from the others.

Example:

# Pull an image from Docker Hub
docker pull nginx:latest

# Create and run a container from that image
docker run -d --name web-server -p 80:80 nginx:latest

# Create a second container from the same image
docker run -d --name web-server-2 -p 8080:80 nginx:latest

Now you have two independent web servers running from the same image.

Your First Container: The docker run Command

Let’s deploy a simple web server to understand the basics:

docker run -d   --name nginx-demo   -p 80:80   --restart unless-stopped   nginx:latest

Breaking down the command:

  • docker run - Create and start a container
  • -d - Detached mode (runs in background)
  • --name nginx-demo - Give the container a friendly name
  • -p 80:80 - Port mapping: host_port:container_port
  • --restart unless-stopped - Auto-restart policy
  • nginx:latest - Image name and tag

Verify it’s running:

# List running containers
docker ps

# Test the web server
curl http://localhost
# You should see the Nginx welcome page HTML

Useful container management commands:

# View container logs
docker logs nginx-demo

# Follow logs in real-time (like tail -f)
docker logs -f nginx-demo

# Stop the container
docker stop nginx-demo

# Start it again
docker start nginx-demo

# Remove the container (must be stopped first)
docker rm nginx-demo

Better Approach: Docker Compose

While docker run works for single containers, Docker Compose is far better for managing multiple services and complex configurations.

Create a file called docker-compose.yml:

cd /opt/docker/apps
mkdir nginx-demo
cd nginx-demo
nano docker-compose.yml

Add this content:

version: '3.8'

services:
  # Our web server service
  nginx:
    image: nginx:latest
    container_name: nginx-demo
    ports:
      - "80:80"  # Maps host port 80 to container port 80
    volumes:
      # Mount a local directory into the container
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped
    networks:
      - web-network

# Define networks
networks:
  web-network:
    driver: bridge

Create a simple HTML file:

mkdir html
echo "<h1>Hello from Docker Compose!</h1>" > html/index.html

Deploy the stack:

# Start services in detached mode
docker compose up -d

# View status
docker compose ps

# View logs
docker compose logs -f

# Stop and remove everything
docker compose down

Why Docker Compose is better:

  • All configuration in one readable YAML file
  • Easy to version control (add to git)
  • Simple to share with others
  • Manages multiple services and their relationships
  • Easier to update and maintain

Deploy Portainer: Your Docker Control Center

Portainer provides a web-based UI for managing Docker. It’s perfect for visual learners and makes complex operations simple.

Quick installation:

# Create a volume for Portainer data
docker volume create portainer_data

# Deploy Portainer
docker run -d   --name=portainer   --restart=always   -p 8000:8000   -p 9443:9443   -v /var/run/docker.sock:/var/run/docker.sock   -v portainer_data:/data   portainer/portainer-ce:latest

Access Portainer:

Open your browser to https://your-server-ip:9443

On first access:

  1. Create an admin account (choose a strong password!)
  2. Select “Docker” as your environment
  3. Click “Connect”

What you can do in Portainer:

  • View all containers, images, volumes, and networks
  • Deploy new containers from templates
  • View real-time resource usage
  • Access container logs without the command line
  • Manage Docker Compose stacks through the UI
  • Monitor container health

Pro tip: Portainer is often the first service homelabbers deploy because it makes everything else easier to manage.


Docker Compose Mastery

Docker Compose is where the real power of containerization shines. Let’s dive deep into creating production-ready compose files.

Docker Compose Fundamentals

Docker Compose orchestrates multi-container applications using a single YAML configuration file. Instead of running multiple docker run commands and manually managing container relationships, Compose handles everything:

  • Service definitions
  • Networking between containers
  • Volume management
  • Environment variables
  • Startup order and dependencies

Key benefits for homelabs:

  1. Single Source of Truth: Your entire infrastructure defined in YAML files
  2. Version Control: Track changes to your infrastructure in git
  3. Reproducible Deployments: Share your stack with others or restore from backups
  4. Environment Variables: Separate secrets from configuration
  5. Dependency Management: Services start in the correct order automatically

A Real-World Homelab Stack

Let’s build a complete application stack with:

  • PostgreSQL database
  • A web application
  • Nginx reverse proxy

Create /opt/docker/apps/webapp-stack/docker-compose.yml:

version: '3.8'

# Define all services
services:
  # PostgreSQL database
  database:
    image: postgres:15-alpine  # Alpine for smaller size
    container_name: webapp-db
    environment:
      # Pull sensitive data from .env file
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: webapp
    volumes:
      # Persist database data
      - db_data:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - backend  # Only accessible by backend services
    healthcheck:
      # Check if database is ready
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Web application (example - replace with your actual app)
  app:
    image: node:18-alpine
    container_name: webapp-app
    working_dir: /app
    command: npm start
    depends_on:
      database:
        condition: service_healthy  # Wait for DB to be ready
    environment:
      # Connection string uses service name as hostname
      DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@database:5432/webapp
      NODE_ENV: production
    volumes:
      - ./app:/app  # Mount your application code
    ports:
      - "${APP_PORT:-3000}:3000"  # Default to 3000 if not set
    restart: unless-stopped
    networks:
      - backend
      - frontend
    # Resource limits prevent runaway processes
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

  # Nginx reverse proxy
  proxy:
    image: nginx:alpine
    container_name: webapp-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # Custom nginx configuration
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      # SSL certificates
      - ./nginx/certs:/etc/nginx/certs:ro
      # Static files
      - ./nginx/html:/usr/share/nginx/html:ro
    restart: unless-stopped
    networks:
      - frontend
    depends_on:
      - app

# Define volumes for persistent data
volumes:
  db_data:
    driver: local
    # Optional: specify mount point
    # driver_opts:
    #   type: none
    #   o: bind
    #   device: /opt/docker/data/webapp-db

# Define networks for service isolation
networks:
  # Backend network: database and app only
  backend:
    driver: bridge
    internal: true  # No external access

  # Frontend network: app and proxy
  frontend:
    driver: bridge

Create the .env file (never commit this to git!):

nano .env

Add your environment variables:

# Database credentials
DB_USER=webapp_user
DB_PASSWORD=super_secure_password_here

# Application settings
APP_PORT=3000
NODE_ENV=production

Deploy the stack:

docker compose up -d

What just happened:

  1. Docker Compose read the YAML file
  2. Created two networks (backend and frontend)
  3. Created a volume for database persistence
  4. Started the database service first
  5. Waited for the database health check to pass
  6. Started the app service (which can now connect to the database)
  7. Started the proxy service

All automatically, in the correct order, with proper isolation.

Docker Compose Best Practices

1. Use .env Files for Secrets

Never hardcode sensitive data in compose files:

# BAD - secrets in plain text
environment:
  DB_PASSWORD: my_secret_password

# GOOD - reference environment variables
environment:
  DB_PASSWORD: ${DB_PASSWORD}

Add .env to your .gitignore:

echo ".env" >> .gitignore
echo ".env.local" >> .gitignore

2. Set Resource Limits

Prevent containers from consuming all available resources:

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2'      # Maximum 2 CPU cores
          memory: 1G     # Maximum 1GB RAM
        reservations:
          cpus: '0.5'    # Reserve 0.5 cores
          memory: 256M   # Reserve 256MB

3. Use Health Checks

Ensure services are actually ready before depending services start:

services:
  database:
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

4. Organize Complex Stacks with Includes

For large homelabs, split services across multiple files:

# docker-compose.yml (main file)
include:
  - ./apps/media/docker-compose.yml
  - ./apps/monitoring/docker-compose.yml
  - ./apps/automation/docker-compose.yml

This keeps each service category organized and easier to maintain.

5. Use Named Volumes for Important Data

Named volumes are managed by Docker and easier to backup:

# GOOD - named volume
volumes:
  db_data:/var/lib/postgresql/data

volumes:
  db_data:
    driver: local

# LESS IDEAL - bind mount (harder to backup)
volumes:
  - /host/path/data:/var/lib/postgresql/data

Essential Homelab Services

Now that you understand Docker Compose, let’s explore the most popular containers for homelabs.

Container Management & Monitoring

Portainer (Free/Business)

  • Purpose: Web-based Docker management interface
  • Why useful: Perfect for visual learners, makes complex operations simple
  • Resource usage: ~50MB RAM
  • Difficulty: Beginner-friendly
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:

Dozzle (Free)

  • Purpose: Real-time container log viewer
  • Why useful: See logs from all containers in one web UI
  • Resource usage: ~10MB RAM
  • Difficulty: Beginner-friendly

Watchtower (Free)

  • Purpose: Automatic container updates
  • Why useful: Keeps your containers up to date automatically
  • Resource usage: ~30MB RAM
  • Difficulty: Intermediate
services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_CLEANUP=true  # Remove old images
      - WATCHTOWER_SCHEDULE=0 0 4 * * *  # 4 AM daily

Reverse Proxy & Security

Nginx Proxy Manager (Free)

  • Purpose: Easy reverse proxy with SSL certificates
  • Why essential: Secure external access to your services
  • Resource usage: ~100MB RAM
  • Difficulty: Beginner-friendly
services:
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"    # HTTP
      - "443:443"  # HTTPS
      - "81:81"    # Admin interface
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt

volumes:
  npm_data:
  npm_letsencrypt:

Pi-hole (Free)

  • Purpose: Network-wide ad blocking and DNS
  • Why useful: Block ads and tracking for all devices on your network
  • Resource usage: ~50MB RAM
  • Difficulty: Intermediate

Media Services

Jellyfin (Free)

  • Purpose: Media server for movies, TV shows, and music
  • Why useful: Open-source alternative to Plex, no subscription fees
  • Resource usage: 200-500MB RAM (more with hardware transcoding)
  • Difficulty: Intermediate

Immich (Free)

  • Purpose: Self-hosted photo management (Google Photos alternative)
  • Why useful: Keep your photos private with AI-powered organization
  • Resource usage: ~500MB RAM
  • Difficulty: Advanced

Nextcloud (Free)

  • Purpose: Self-hosted file sync and collaboration
  • Why useful: Replace Dropbox/Google Drive with your own cloud
  • Resource usage: ~200MB RAM
  • Difficulty: Intermediate

Home Automation

Home Assistant (Free)

  • Purpose: Central hub for smart home devices
  • Why essential: Control all your IoT devices from one interface
  • Resource usage: ~300MB RAM
  • Difficulty: Intermediate
services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    network_mode: host  # Needed for device discovery
    volumes:
      - homeassistant_config:/config
    environment:
      - TZ=America/New_York

volumes:
  homeassistant_config:

Databases

PostgreSQL (Free)

services:
  postgres:
    image: postgres:15-alpine
    container_name: postgres
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

Redis (Free) - In-memory data store for caching MongoDB (Free) - NoSQL document database

Development Tools

Gitea (Free) - Self-hosted Git service Jenkins (Free) - CI/CD automation server VS Code Server (Free) - Browser-based code editor


Storage and Networking

Understanding Docker’s storage and networking is crucial for a stable homelab.

Docker Storage Deep Dive

Volume Types Explained

1. Named Volumes (Recommended for Databases)

services:
  database:
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:
    driver: local

Characteristics:

  • Managed by Docker in /var/lib/docker/volumes/
  • Persist across container restarts and removals
  • Easy to backup with docker volume commands
  • Best for database files and critical data

Backup a named volume:

docker run --rm   -v db_data:/source:ro   -v $(pwd):/backup   alpine tar czf /backup/db_data_backup.tar.gz -C /source .

2. Bind Mounts (Good for Configuration Files)

services:
  nginx:
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d:ro
      - ./nginx/html:/usr/share/nginx/html

Characteristics:

  • Direct mapping of host directories to container paths
  • Changes on host immediately reflected in container
  • Useful for configuration files you want to edit easily
  • Can have permission issues (user ID mismatches)

3. Tmpfs Mounts (Temporary Data)

services:
  app:
    tmpfs:
      - /tmp
      - /app/cache

Characteristics:

  • Stored in RAM, not on disk
  • Lost when container stops
  • Very fast for temporary data
  • Useful for caches and session data

Storage Best Practices

1. Always use volumes for persistent data

# GOOD
volumes:
  - postgres_data:/var/lib/postgresql/data

# BAD - data lost when container is removed!
# No volume defined

2. Regular backups

# Backup all volumes weekly
0 2 * * 0 /opt/docker/scripts/backup-volumes.sh

3. Monitor disk space

# Clean up unused resources
docker system prune -a

# Show disk usage
docker system df

Docker Networking Essentials

Network Modes

Bridge Network (Default - Recommended)

This creates an isolated network for your containers with internal DNS:

services:
  app:
    networks:
      - app-network

  database:
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Key features:

  • Containers communicate via service names (DNS)
  • app can reach database at hostname database
  • Isolated from other Docker networks
  • Can control which services communicate

Host Network (Use Sparingly)

services:
  app:
    network_mode: host

Container uses host’s network directly. Use only when:

  • You need device discovery (like Home Assistant)
  • Maximum performance is critical
  • You understand the security implications

Custom Bridge Networks

Create multiple networks for security isolation:

services:
  # Frontend tier
  web:
    networks:
      - frontend

  # Application tier
  app:
    networks:
      - frontend
      - backend

  # Database tier
  database:
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No internet access

This creates a 3-tier architecture where:

  • Web can only reach app
  • App can reach both web and database
  • Database can only be reached by app (not web directly)

Port Mapping

services:
  app:
    ports:
      # Format: "HOST:CONTAINER"
      - "8080:3000"              # Public on all interfaces
      - "127.0.0.1:9000:9000"    # Localhost only (more secure)
      - "192.168.1.10:5432:5432" # Specific IP only

Security tip: Bind to 127.0.0.1 for services that should only be accessed via reverse proxy:

services:
  internal-app:
    ports:
      - "127.0.0.1:8080:8080"  # Only accessible from host

  proxy:
    ports:
      - "80:80"     # Public access
      - "443:443"

Network Troubleshooting Commands

# List networks
docker network ls

# Inspect a network (see connected containers)
docker network inspect app-network

# Check which ports a container is exposing
docker port container_name

# Connect a running container to a network
docker network connect network_name container_name

# Disconnect from a network
docker network disconnect network_name container_name

AI-Assisted Homelab Management

Here’s where homelabbing.io distinguishes itself from traditional Docker guides. We’re not just teaching you to manage containers - we’re showing you how AI can help you manage them smarter.

What is AI-Assisted Homelab Management?

Imagine having an expert system administrator watching your homelab 24/7, one that:

  • Knows when services are struggling before they crash
  • Automatically optimizes resource allocation based on your usage patterns
  • Detects security vulnerabilities and suggests fixes
  • Deploys complex stacks from simple descriptions
  • Troubleshoots problems in seconds that might take you hours

This isn’t science fiction - it’s the convergence of containerization and AI that’s happening right now in 2025.

While traditional Docker documentation shows you how to run containers, we’re showing you how to let AI agents help you run them better.

Use Case 1: AI-Powered Container Deployment

Traditional Approach:

  1. Research which photo management software to use
  2. Read documentation for Immich, PhotoPrism, or alternatives
  3. Find a docker-compose.yml example
  4. Modify it for your environment
  5. Configure reverse proxy
  6. Set up SSL certificates
  7. Test and troubleshoot
  8. Total time: 2-4 hours

AI-Assisted Approach:

You: “I want to organize my 50,000 photos with facial recognition, accessible securely from anywhere”

AI Agent:

  1. Analyzes your requirements
  2. Recommends Immich (best for your needs)
  3. Checks your available resources (6GB RAM available)
  4. Generates optimized docker-compose.yml
  5. Configures Nginx Proxy Manager integration
  6. Sets up Let’s Encrypt SSL certificates
  7. Deploys everything with health checks
  8. Provides access URL: https://photos.yourhomelab.com
  9. Total time: 3-5 minutes

The Magic Behind the Scenes:

User Request
    ↓
AI Analysis (resource availability, feature requirements)
    ↓
Service Selection (Immich vs alternatives)
    ↓
Compose File Generation (optimized for your hardware)
    ↓
Automated Deployment (docker compose up -d)
    ↓
Configuration (reverse proxy, SSL, DNS)
    ↓
Health Monitoring (ensure everything started correctly)
    ↓
User Notification: "Your photo library is ready at https://..."

Benefits:

  • Non-technical users deploy complex stacks effortlessly
  • Eliminates configuration mistakes
  • Best practices automatically applied
  • Dramatically reduced deployment time

Use Case 2: Intelligent Resource Optimization

Your homelab is running 20+ containers. Some are idle most of the time, others are resource-hungry during peak hours. Managing this manually is tedious and error-prone.

How AI Helps:

The AI agent continuously monitors all containers:

# What the AI sees:
Container: jellyfin
  Current limits: 2 CPUs, 4GB RAM
  Actual usage: 0.3 CPUs, 800MB RAM (evening: 1.2 CPUs, 2.5GB RAM)

Container: immich
  Current limits: 1 CPU, 2GB RAM
  Actual usage: 0.8 CPUs, 1.9GB RAM (frequently hitting limit)

Container: postgres
  Current limits: None
  Actual usage: 0.1 CPUs, 350MB RAM (very stable)

AI recommendations:

SUGGESTION 1: Reduce Jellyfin limits
  Current: cpus: '2', memory: 4G
  Recommended: cpus: '1.5', memory: 3G
  Reason: Peak usage never exceeds 1.2 CPUs and 2.5GB
  Impact: Free up 0.5 CPU cores and 1GB RAM
  Confidence: High (90%)

SUGGESTION 2: Increase Immich limits
  Current: cpus: '1', memory: 2G
  Recommended: cpus: '1.5', memory: 3G
  Reason: Frequently hitting memory limit, causing OOM warnings
  Impact: Prevent crashes, improve performance
  Confidence: Very High (95%)

SUGGESTION 3: Add limits to PostgreSQL
  Current: None
  Recommended: cpus: '0.5', memory: 512M
  Reason: Usage very stable, limits prevent runaway behavior
  Impact: Protect against potential issues
  Confidence: Medium (75%)

The Learning Loop:

Monitor → Analyze → Recommend → (User Approves) → Implement → Validate → Learn
    ↑                                                                      ↓
    ←──────────────────────────────────────────────────────────────────────

Over time, the AI learns your homelab’s patterns:

  • Monday mornings: Photo uploads spike (weekend photos)
  • Friday evenings: Media server usage increases
  • Weekday afternoons: Everything quiet

It adjusts resources predictively before issues occur.

Use Case 3: Proactive Security Monitoring

The Old Way:

  • Wait for security researchers to discover vulnerabilities
  • Manually check if your containers are affected
  • Read changelogs to understand impact
  • Update containers hoping nothing breaks
  • Pray you didn’t miss anything

The AI-Assisted Way:

AI agent performs continuous security auditing:

SECURITY ALERT - Medium Severity
Container: nginx-proxy-manager
Issue: Running as root user
Risk: Container compromise = system compromise
CVE: N/A (configuration issue)
Fix: Add 'user: 101:101' to compose file

Automated remediation available: Yes
Apply fix? [Yes/No/Review]
SECURITY ALERT - High Severity
Container: jellyfin
Issue: CVE-2024-XXXX in ffmpeg library
Risk: Remote code execution via crafted video file
Affected versions: &lt; 10.8.13
Current version: 10.8.10

Recommended action:
  1. Update to jellyfin:10.8.13
  2. Restart container
  3. Verify health checks pass

Automated update available: Yes
Update now? [Yes/Schedule/Review]
SECURITY ALERT - Critical
Container: photoprism
Issue: Unusual network traffic detected
Pattern: 10,000+ requests to external IP 185.220.xxx.xxx
Classification: Potential data exfiltration
Confidence: 87%

Actions taken:
  ✓ Container network isolated
  ✓ Logs collected for analysis
  ✓ Admin notification sent

Review required: Yes
Detailed analysis: [View Report]

What makes AI monitoring special:

  • Learns what’s “normal” for your specific homelab
  • Detects anomalies that signature-based tools miss
  • Provides context and actionable recommendations
  • Can auto-remediate low-risk issues
  • Reduces security knowledge barrier

Use Case 4: Self-Healing Infrastructure

3 AM: Your Immich container crashes. In a traditional setup, you won’t know until morning. With AI-assisted management:

[03:14:22] Container 'immich' stopped unexpectedly
[03:14:23] Analyzing logs...
[03:14:25] Root cause identified: Out of Memory (OOM)
[03:14:26] Checking historical usage patterns...
[03:14:28] Analysis: Container memory limit too low for recent usage
[03:14:30] Recommended fix: Increase memory limit from 2GB to 3GB
[03:14:32] Applying fix... ✓
[03:14:35] Restarting container... ✓
[03:14:42] Health check passed ✓
[03:14:43] Service restored. Total downtime: 21 seconds
[03:14:44] Incident report generated
[03:14:45] User notification: "Immich auto-recovered from OOM, limits adjusted"

The self-healing workflow:

Failure Detection
    ↓
Log Analysis (identify error patterns)
    ↓
Root Cause Identification
    ↓
Historical Pattern Analysis (is this a recurring issue?)
    ↓
Solution Selection (based on known fixes)
    ↓
Safety Check (will this fix cause other issues?)
    ↓
Automated Remediation
    ↓
Validation (did it work?)
    ↓
Documentation (log for future learning)
    ↓
User Notification (what happened and what was fixed)

Use Case 5: Natural Language Container Management

Instead of remembering Docker commands, just describe what you want:

You: “Show me which containers are using the most CPU right now”

AI Agent:

Top CPU Consumers (Last 5 minutes):
1. Immich (2.1 CPUs) - Processing 450 photos
2. Jellyfin (0.8 CPUs) - Active transcoding: 1 stream
3. Home Assistant (0.3 CPUs) - Normal operation
4. All others &lt; 0.1 CPUs

Would you like to see detailed metrics for any service?

You: “Why did my media server stop working last night?”

AI Agent:

Analyzing jellyfin container history...

Incident Timeline:
23:47:12 - High memory usage detected (3.8GB / 4GB limit)
23:51:34 - Out of memory warning
23:52:18 - Container killed by system OOM killer
23:52:22 - Auto-restart triggered by restart policy
23:52:45 - Container healthy again

Root Cause: Hardware transcoding 3 simultaneous 4K streams
Exceeded memory limits

Actions already taken:
✓ Memory limit increased to 6GB
✓ Concurrent transcoding limited to 2 streams in config

Current status: Healthy, no issues since adjustment

You: “Set up a nightly backup of all my databases at 2 AM”

AI Agent:

Creating backup solution...

Services identified for backup:
- PostgreSQL (webapp-db)
- MongoDB (immich-db)
- MySQL (homeassistant-db)

Backup strategy:
- Schedule: Daily at 02:00 AM
- Retention: 7 daily, 4 weekly, 3 monthly
- Method: Volume snapshots + database dumps
- Compression: gzip
- Verification: Automatic restore test weekly

Compose file created: /opt/docker/apps/backup/docker-compose.yml
Starting backup service... ✓

First backup scheduled for: Tonight at 02:00 AM
Backup destination: /opt/docker/backups/databases/

Would you like email notifications for backup status?

Making This Real: Implementation Pathways

You might be thinking: “This sounds amazing, but how do I actually get this?”

Option 1: Use Existing AI Tools

  • Claude, ChatGPT, or other AI assistants can help with compose file generation
  • Tools like GitHub Copilot can suggest Docker configurations
  • Open-source projects like Fabric can automate some tasks

Option 2: Build Custom Automations

  • Use AI APIs to create monitoring scripts
  • Implement chatbot interfaces for your homelab
  • Develop smart alerting systems

Option 3: Wait for Integrated Solutions

  • Projects like Komodo, Portainer, and others are adding AI features
  • The future of homelab management is AI-first

The key insight: You don’t need to wait for perfect AI integration. Start small:

  1. Use AI to generate compose files
  2. Implement basic monitoring
  3. Automate responses to common issues
  4. Gradually build more intelligence

Security Best Practices

In 2025, the idea that “my homelab isn’t interesting to hackers” is dangerously outdated. Automated scanning bots don’t care about the size of your lab - they care about vulnerable, exploitable systems.

The Modern Threat Landscape

Real threats facing homelabs today:

  1. Automated Scanning: AI-powered bots continuously scan for vulnerable Docker installations, misconfigured containers, and exposed services

  2. Cryptocurrency Mining: Compromised containers become part of mining botnets, consuming your resources and electricity

  3. Data Harvesting: Personal photos, documents, and credentials stored in your homelab are valuable

  4. Ransomware: 24/7 running homelabs are prime targets for ransomware-as-a-service operations

The good news: Docker provides excellent security capabilities when configured correctly.

Fundamental Security Principles

1. Keep Everything Updated

# Update the host system
sudo apt update && sudo apt upgrade -y

# Update Docker itself
sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io

# Update all running containers (use with caution!)
docker compose pull
docker compose up -d

Why this matters: Container escape vulnerabilities (like the “Leaky Vessels” CVE series) are discovered regularly. Staying updated is your first line of defense.

2. Never Run Containers as Root

Bad (default for many images):

services:
  app:
    image: myapp:latest
    # Runs as root inside container (UID 0)

Good:

services:
  app:
    image: myapp:latest
    user: "1000:1000"  # Run as non-root user

Even better (in your Dockerfile):

FROM alpine:3.18

# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Copy files with correct ownership
COPY --chown=appuser:appgroup . /app

# Switch to non-root user
USER appuser

CMD ["/app/start.sh"]

Why this matters: If an attacker compromises a container running as root, they have root-level capabilities. A non-root container limits the blast radius.

3. Use Read-Only Filesystems

services:
  app:
    image: nginx:alpine
    read_only: true  # Container filesystem is read-only
    tmpfs:
      - /tmp        # Allow temporary files in memory
      - /var/run

Why this matters: Attackers can’t modify the container filesystem to install malware or create backdoors.

4. Drop Unnecessary Capabilities

Linux capabilities give containers specific permissions. Drop everything, then add back only what’s needed:

services:
  app:
    image: myapp:latest
    cap_drop:
      - ALL  # Drop all capabilities
    cap_add:
      - NET_BIND_SERVICE  # Only add what's absolutely necessary

Why this matters: Even if an attacker escapes the container, their capabilities are severely limited.

Container Configuration Security

Environment Variable Security

Never do this:

# BAD - secrets in compose file
services:
  app:
    environment:
      DB_PASSWORD: super_secret_password123
      API_KEY: sk_live_abc123xyz

Do this instead:

# GOOD - secrets in .env file
services:
  app:
    env_file:
      - .env
    environment:
      DB_PASSWORD: ${DB_PASSWORD}
      API_KEY: ${API_KEY}

And add .env to .gitignore:

echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo "secrets/" >> .gitignore

Resource Limits (Prevent DoS)

services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'      # Maximum CPU usage
          memory: 512M     # Maximum RAM
          pids: 100        # Maximum processes
        reservations:
          cpus: '0.25'
          memory: 128M

Why this matters: Prevents a compromised container from consuming all resources and taking down your entire homelab.

Image Security

Scan Images for Vulnerabilities

# Using Docker Scout (built into Docker Desktop)
docker scout cves nginx:latest

# Using Trivy (open source)
trivy image nginx:latest

# Using Grype (Anchore)
grype nginx:latest

Use Specific Image Tags

# BAD - unpredictable updates
services:
  app:
    image: nginx:latest

# GOOD - specific, reproducible version
services:
  app:
    image: nginx:1.25.3-alpine

Why specific tags matter:

  • :latest can change at any time, breaking your stack
  • Specific tags are reproducible and testable
  • You control when to update (after testing)

Automated Updates with Watchtower (Carefully)

services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_INCLUDE_STOPPED=false
      - WATCHTOWER_SCHEDULE=0 0 4 * * *  # 4 AM daily
      # Only update specific containers
      - WATCHTOWER_LABEL_ENABLE=true

  app:
    image: myapp:latest
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Network Security

Network Segmentation

Create security boundaries between services:

services:
  # Public-facing service
  web:
    networks:
      - frontend

  # Application tier
  app:
    networks:
      - frontend  # Can talk to web
      - backend   # Can talk to database

  # Database tier
  database:
    networks:
      - backend   # Only accessible by app

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No internet access

Bind Sensitive Services to Localhost

services:
  database:
    ports:
      # BAD - exposed to network
      # - "5432:5432"

      # GOOD - only accessible from host
      - "127.0.0.1:5432:5432"

Defense-in-Depth Strategy

Layer 1: Network Perimeter

  • Firewall: Only expose necessary ports
  • VPN: Use Tailscale or WireGuard for remote access
  • Reverse Proxy: Never expose services directly

Layer 2: Container Isolation

  • Network segmentation
  • Resource limits
  • Read-only filesystems
  • Capability dropping

Layer 3: Application Security

  • Strong authentication
  • Regular updates
  • Vulnerability scanning
  • Secrets management

Layer 4: Monitoring & Response

  • Log aggregation
  • Anomaly detection
  • Automated alerting
  • Incident response plan

Ten-Minute Daily Security Review:

# Quick security check script
#!/bin/bash

echo "=== Security Health Check ==="

# Check for containers running as root
echo "Containers running as root:"
docker ps --format '[[.Names]]' | while read container; do
  user=$(docker inspect --format='[[.Config.User]]' $container)
  if [ -z "$user" ]; then
    echo "  - $container (running as root!)"
  fi
done

# Check for exposed ports
echo "Publicly exposed ports:"
docker ps --format '[[.Names]]\t[[.Ports]]' | grep '0.0.0.0'

# Check for outdated images
echo "Outdated images:"
docker images --format '[[.Repository]]:[[.Tag]]' | while read image; do
  docker pull $image --quiet > /dev/null 2>&1
done

# Check disk space
echo "Disk usage:"
docker system df

echo "=== Review complete ==="

Run this daily, address any issues, and your homelab will be significantly more secure than 95% of home setups.


Troubleshooting Common Issues

Even with perfect configuration, you’ll encounter issues. Here’s how to diagnose and fix the most common problems.

Issue 1: Port Conflicts

Symptoms:

Error response from daemon: driver failed programming external
connectivity on endpoint app: Bind for 0.0.0.0:80 failed:
port is already allocated

Diagnosis:

# Find what's using port 80
sudo lsof -i :80
# or
sudo netstat -tulpn | grep :80

Solution 1: Change the host port

services:
  app:
    ports:
      - "8080:80"  # Use 8080 instead of 80

Solution 2: Use a reverse proxy

services:
  nginx-proxy:
    ports:
      - "80:80"
      - "443:443"

  app1:
    # No ports exposed - accessed via proxy
    expose:
      - "3000"

  app2:
    expose:
      - "8080"

Issue 2: Persistent Data Loss

Symptoms:

  • Database resets after container restart
  • Configuration changes disappear
  • Uploaded files vanish

Root cause: No volume defined

Solution:

# BAD - no volume
services:
  database:
    image: postgres:15

# GOOD - named volume
services:
  database:
    image: postgres:15
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Backup your volumes:

# Backup a volume
docker run --rm   -v postgres_data:/data:ro   -v $(pwd):/backup   alpine tar czf /backup/postgres_backup_$(date +%Y%m%d).tar.gz -C /data .

# Restore a volume
docker run --rm   -v postgres_data:/data   -v $(pwd):/backup   alpine tar xzf /backup/postgres_backup_20251216.tar.gz -C /data

Issue 3: Container Can’t Connect to Database

Symptoms:

Error: getaddrinfo ENOTFOUND database
Connection refused to database:5432

Diagnosis:

# Check if containers are on the same network
docker network inspect app-network

# Try to ping from one container to another
docker exec app ping database

Solution:

services:
  app:
    networks:
      - app-network
    environment:
      # Use service name as hostname
      DB_HOST: database  # Not "localhost", not IP address

  database:
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Issue 4: Container Keeps Restarting

Diagnosis:

# Check container status
docker ps -a

# View recent logs
docker logs --tail 100 container_name

# Follow logs in real-time
docker logs -f container_name

Common causes and solutions:

Cause 1: Dependency not ready

# SOLUTION: Use health checks
services:
  app:
    depends_on:
      database:
        condition: service_healthy

  database:
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

Cause 2: Out of memory

# Check logs for OOM (Out Of Memory)
docker logs container_name | grep -i "killed"

# Solution: Increase memory limit
services:
  app:
    deploy:
      resources:
        limits:
          memory: 1G  # Increased from 512M

Cause 3: Missing environment variables

# Check logs for environment variable errors
docker logs container_name | grep -i "environment|env|variable"

# Solution: Add required variables

Issue 5: Slow Performance

Diagnosis:

# Monitor resource usage in real-time
docker stats

# Check disk I/O
docker system df
docker system df -v  # Verbose output

Common solutions:

1. Resource limits too low

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2'      # Increased from 1
          memory: 2G     # Increased from 1G

2. Volume driver issues

# If using bind mounts, consider named volumes
volumes:
  # SLOW on some systems
  - ./large_data:/data

# Try named volume instead
volumes:
  - app_data:/data

volumes:
  app_data:

3. Network bottlenecks

# Check network throughput between containers
docker exec app ping -c 10 database

Debugging Commands Reference

# CONTAINER INSPECTION
docker ps                              # List running containers
docker ps -a                           # List all containers
docker inspect container_name          # Detailed container info
docker logs container_name             # View logs
docker logs -f container_name          # Follow logs (tail -f)
docker logs --since 1h container_name  # Logs from last hour
docker stats                           # Real-time resource usage
docker top container_name              # Processes inside container

# INTERACTIVE DEBUGGING
docker exec -it container_name sh      # Shell into container (Alpine)
docker exec -it container_name bash    # Shell into container (Ubuntu/Debian)
docker exec container_name cat /etc/hosts  # Run single command

# NETWORK DEBUGGING
docker network ls                      # List networks
docker network inspect network_name    # Network details
docker port container_name             # Port mappings

# VOLUME DEBUGGING
docker volume ls                       # List volumes
docker volume inspect volume_name      # Volume details

# CLEANUP
docker system prune                    # Remove unused resources
docker system prune -a                 # Remove all unused images too
docker volume prune                    # Remove unused volumes
docker image prune -a                  # Remove unused images

# HEALTH CHECKS
docker inspect --format='[[.State.Health.Status]]' container_name
docker inspect --format='[[json .State.Health]]' container_name | jq

Getting Help

When asking for help (on Reddit, Discord, forums):

Provide this information:

# Your environment
docker --version
docker compose version
uname -a

# Container status
docker ps -a

# Recent logs
docker logs --tail 50 container_name

# Your compose file (remove sensitive data!)
cat docker-compose.yml

# Resource usage
docker stats --no-stream

The more information you provide, the faster you’ll get helpful responses.


Next Steps

Congratulations! You now have a solid foundation in Docker for homelabs. Here’s your path forward based on your goals.

For Beginners: Build Your First Stack

Week 1-2: Foundation

  1. ✓ You just completed: Docker Basics
  2. Deploy Portainer for visual management
  3. Deploy Nginx Proxy Manager for reverse proxy
  4. Set up your first .env file workflow

Week 3-4: First Real Services

  1. Add a media service (Jellyfin or Plex)
  2. Add a file sync service (Nextcloud)
  3. Configure SSL certificates via Nginx Proxy Manager
  4. Set up your first backup routine

Month 2: Expansion

  1. Add monitoring (Uptime Kuma or similar)
  2. Add a dashboard (Homepage, Homarr, or Dashy)
  3. Implement automated updates with Watchtower
  4. Document your stack in a README

For Intermediate Users: Level Up

Advanced Docker Compose:

  • Multi-file compose setups with include
  • Building custom images
  • CI/CD pipelines for homelab deployments
  • Docker secrets for production-grade security

Orchestration:

  • Docker Swarm for multi-node deployments
  • Kubernetes (K3s) for learning enterprise tools
  • High availability setups

Automation:

  • GitOps workflows (infrastructure as code)
  • Automated testing of compose files
  • Integration with Home Assistant
  • Custom monitoring and alerting

For Advanced Users: Push the Boundaries

AI-Assisted Infrastructure:

  • Implement natural language interfaces for container management
  • Build self-healing automations
  • Create predictive resource allocation systems
  • Contribute to open-source homelab projects

Enterprise Patterns:

  • Service mesh architectures
  • Distributed tracing and observability
  • Advanced networking (VLANs, multiple subnets)
  • Disaster recovery and business continuity

Essential Next Reads:

  • “Nginx Proxy Manager: Complete Setup Guide” - Secure external access to your services
  • “Docker Security Hardening Deep Dive” - Advanced security configurations
  • “Essential Docker Containers for Every Homelab” - Curated service recommendations
  • “Backing Up Your Docker Homelab” - Comprehensive backup strategies

Platform-Specific:

  • “Proxmox + Docker: The Complete Guide” - Deep dive into running Docker on Proxmox
  • “Raspberry Pi Docker Homelab” - ARM-specific considerations and optimizations

Advanced Topics:

  • “AI-Assisted Homelab Management: The Future of Home Infrastructure”
  • “From Docker to Kubernetes: When and Why to Make the Jump”
  • “GitOps for Homelabs: Infrastructure as Code Done Right”

Join the Community

Homelabbing is better together:

  • r/homelab - The largest homelab community on Reddit
  • r/selfhosted - Self-hosting specific discussions
  • Discord servers - Real-time help and conversations
  • homelabbing.io community - Our AI-forward homelab community

Share your setups, learn from others, and contribute back to help the next generation of homelabbers.


Conclusion

You’ve just learned the fundamentals of Docker for homelabs - from understanding what containers are, to installing Docker, deploying services, and implementing security best practices.

Key Takeaways:

  1. Docker transforms homelabs: What used to require hours now takes minutes. Complex deployments become simple docker compose up -d commands.

  2. Containers are not VMs: They’re lightweight, fast, and efficient. You can run dramatically more services on the same hardware.

  3. Docker Compose is essential: It turns complex multi-container deployments into readable, version-controlled YAML files.

  4. Security matters: Even homelabs need proper security. Run containers as non-root, use resource limits, scan for vulnerabilities, and segment networks.

  5. AI is the future: The convergence of containerization and AI assistance will make sophisticated homelab management accessible to everyone.

The Docker Mindset:

Think in terms of:

  • Services, not servers
  • Immutable infrastructure (replace, don’t repair)
  • Declarative configuration (describe what you want, not how to get it)
  • Automation first (if you’re doing it manually more than twice, automate it)

Your Homelab Journey:

Where you go from here depends on your interests:

  • Media enthusiasts: Build a complete media stack (Jellyfin, *arr services, download managers)
  • Smart home fans: Deploy Home Assistant and automation services
  • Developers: Set up CI/CD, private git, and development tools
  • Privacy advocates: Self-host everything (email, photos, cloud storage, passwords)
  • Tinkerers: Experiment with everything and break things (that’s how you learn!)

One Last Piece of Advice:

Start small, document as you go, and don’t be afraid to break things. Docker’s beauty is that when something breaks, you can destroy and recreate it in seconds. This makes experimentation safe and learning fast.

Your homelab is a playground for learning real-world infrastructure skills. The Docker knowledge you gain here transfers directly to professional DevOps, cloud engineering, and software development careers.

What sets homelabbing.io apart:

We’re not just teaching you Docker commands - we’re showing you how to build intelligent, AI-assisted infrastructure that manages itself. The future of homelabbing isn’t just containers; it’s containers with AI agents that optimize, secure, and maintain your environment automatically.

Now go forth and containerize all the things! Your journey from Docker basics to AI-powered homelab mastery starts now.


Quick Reference

Essential Docker Commands

# Container Management
docker ps                                    # List running containers
docker ps -a                                 # List all containers
docker run -d --name app image              # Run container detached
docker stop container_name                   # Stop container
docker start container_name                  # Start container
docker restart container_name                # Restart container
docker rm container_name                     # Remove container
docker rm -f container_name                  # Force remove running container

# Docker Compose
docker compose up -d                         # Start services
docker compose down                          # Stop and remove services
docker compose ps                            # List services
docker compose logs -f                       # Follow logs
docker compose pull                          # Update images
docker compose restart service_name          # Restart specific service

# Images
docker images                                # List images
docker pull image_name                       # Download image
docker rmi image_name                        # Remove image
docker image prune -a                        # Remove unused images

# Volumes
docker volume ls                             # List volumes
docker volume create volume_name             # Create volume
docker volume inspect volume_name            # Volume details
docker volume rm volume_name                 # Remove volume
docker volume prune                          # Remove unused volumes

# Networks
docker network ls                            # List networks
docker network inspect network_name          # Network details
docker network create network_name           # Create network
docker network connect network container     # Connect container to network

# Debugging
docker logs container_name                   # View logs
docker logs -f container_name                # Follow logs
docker exec -it container sh                 # Shell into container
docker inspect container_name                # Detailed info
docker stats                                 # Real-time resource usage

# Cleanup
docker system prune                          # Remove unused resources
docker system prune -a                       # Remove all unused images too
docker system df                             # Show disk usage

Compose File Template

version: '3.8'

services:
  app:
    image: app:latest
    container_name: my-app
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - ENV_VAR=${ENV_VAR}
    volumes:
      - app_data:/data
      - ./config:/config:ro
    networks:
      - app-network
    depends_on:
      db:
        condition: service_healthy
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:15-alpine
    container_name: my-db
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  app_data:
  db_data:

networks:
  app-network:
    driver: bridge

Last updated: December 16, 2025 Author: homelabbing.io Difficulty: Beginner Time to complete: 45 minutes

Happy homelabbing! 🚀