Introduction: Why Docker?

When running a home server, you'll want to install many different programs: media servers, file synchronization, ad blocking, password managers, and more. But installing programs directly leads to various problems - dependency conflicts, settings getting lost during updates, and having to reconfigure everything when migrating to a new server.

Docker solves all these problems elegantly. Programs run in isolated environments called containers, so they don't affect each other, and you can deploy complex services with just a few lines of configuration. In this guide, we'll cover everything from Docker basics to deploying useful services.

1. What is Docker?

1.1 Understanding Containers

A container is a package that bundles an application with everything it needs to run (libraries, configuration files, etc.). It looks similar to a virtual machine but is much lighter and faster.

  • Virtual Machine (VM): Includes an entire operating system, making it heavy and slow to boot.
  • Container: Shares the host OS kernel, making it lightweight and starting almost instantly.

Think of it this way: a virtual machine is like moving an entire house, while a container is like packing only the furniture you need into a shipping container.

1.2 Key Docker Concepts

  • Image: A template for creating containers. Contains the program and all required environment.
  • Container: A running instance of an image. The actual running program.
  • Registry: A storage and distribution service for images. Docker Hub is the most popular.
  • Volume: Persistent storage space for container data.

1.3 Benefits of Docker

  • Isolation: Each container runs in an independent environment and doesn't affect others.
  • Portability: An image created once runs identically anywhere.
  • Reproducibility: With just a configuration file, you can recreate the same environment anytime.
  • Efficiency: Uses far fewer resources than virtual machines.
  • Ecosystem: Countless images are publicly available on Docker Hub for immediate use.

2. Installing Docker

2.1 Installation on Ubuntu/Debian

Install the latest version of Docker using the official repository:

# Remove existing packages
sudo apt remove docker docker-engine docker.io containerd runc

# Install required packages
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release

# Add Docker GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

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

# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Start service and enable on boot
sudo systemctl start docker
sudo systemctl enable docker

2.2 Add Current User to Docker Group

To avoid typing sudo every time, add your user to the docker group:

sudo usermod -aG docker $USER
# Log out and back in to apply changes

2.3 Verify Installation

# Check Docker version
docker --version

# Check Docker Compose version
docker compose version

# Run test container
docker run hello-world

3. Basic Docker Commands

3.1 Image Commands

# Download an image
docker pull nginx

# List local images
docker images

# Remove an image
docker rmi nginx

# Clean up unused images
docker image prune

3.2 Running Containers (docker run)

docker run is the most commonly used command. Let's explore the key options:

# Basic run
docker run nginx

# Run in background (-d)
docker run -d nginx

# Specify container name (--name)
docker run -d --name my-nginx nginx

# Port mapping (-p host:container)
docker run -d -p 8080:80 nginx

# Volume mount (-v host:container)
docker run -d -v /my/content:/usr/share/nginx/html nginx

# Set environment variable (-e)
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql

# Set restart policy (--restart)
docker run -d --restart unless-stopped nginx

# Combining multiple options
docker run -d \
  --name webserver \
  -p 80:80 \
  -v /var/www:/usr/share/nginx/html:ro \
  --restart unless-stopped \
  nginx

3.3 Container Management (docker ps)

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# Stop a container
docker stop my-nginx

# Start a container
docker start my-nginx

# Restart a container
docker restart my-nginx

# Remove a container
docker rm my-nginx

# Force remove a running container
docker rm -f my-nginx

# Remove all stopped containers
docker container prune

3.4 Viewing Logs (docker logs)

# View logs
docker logs my-nginx

# Follow logs in real-time (-f: follow)
docker logs -f my-nginx

# Show last 100 lines
docker logs --tail 100 my-nginx

# Include timestamps
docker logs -t my-nginx

3.5 Accessing Container Interior (docker exec)

# Execute command inside container
docker exec my-nginx ls /etc/nginx

# Access container shell (-it: interactive terminal)
docker exec -it my-nginx /bin/bash

# If shell is not bash (Alpine, etc.)
docker exec -it my-nginx /bin/sh

4. Using Docker Compose

4.1 What is Docker Compose?

Docker Compose is a tool for defining and managing multiple containers. Define your service configuration in a YAML file, and start or stop all services with a single command.

4.2 Basic docker-compose.yml Structure

version: "3.8"

services:
  web:
    image: nginx:latest
    container_name: my-web
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: my-db
    environment:
      - MYSQL_ROOT_PASSWORD=secretpassword
      - MYSQL_DATABASE=myapp
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  db_data:

4.3 Docker Compose Commands

# Start services (background)
docker compose up -d

# Stop and remove containers
docker compose down

# Stop services (keep containers)
docker compose stop

# Restart services
docker compose restart

# View logs
docker compose logs -f

# Restart specific service
docker compose restart web

# Update images and redeploy
docker compose pull
docker compose up -d

4.4 Practical Example: WordPress + MariaDB

version: "3.8"

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    ports:
      - "8080:80"
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress_password
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: wordpress-db
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress_password
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  wordpress_data:
  db_data:

5. Web GUI Management with Portainer

5.1 Introduction to Portainer

Portainer is a tool that lets you manage Docker from a web browser. You can start/stop containers, view logs, manage images, and more through a GUI. It's especially useful for those not comfortable with the terminal.

5.2 Installing Portainer

# Create volume
docker volume create portainer_data

# Run Portainer
docker run -d \
  -p 9443:9443 \
  --name portainer \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

5.3 Initial Portainer Setup

  1. Access https://ServerIP:9443 in your web browser
  2. Create admin account (password must be 12+ characters)
  3. Select "Get Started" or "Local" environment
  4. Manage containers, images, volumes, etc. from the dashboard

5.4 Key Portainer Features

  • Container Management: Start, stop, restart, delete, view logs
  • Stacks: Manage docker-compose files via web interface
  • Image Management: Download, delete, build images
  • Volume Management: Create, delete, backup volumes
  • Network Management: Configure Docker networks
  • Templates: Quick deployment with predefined app templates

6. Useful Docker Applications

6.1 Pi-hole: Network-wide Ad Blocking

Pi-hole blocks ads at the DNS level. Once configured, ads are blocked on all devices connected to your network.

version: "3.8"

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      TZ: 'America/New_York'
      WEBPASSWORD: 'your_password_here'
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped

After installation, change your router's DNS server to the Pi-hole server IP to apply network-wide.

6.2 Nginx Proxy Manager: Reverse Proxy

Nginx Proxy Manager connects domains to multiple services and automatically manages SSL certificates.

version: "3.8"

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    restart: unless-stopped

Default login: Email admin@example.com, Password changeme

6.3 Homepage: Home Server Dashboard

Homepage is a dashboard that lets you see all your home server services at a glance. It features a clean design and various service widgets.

version: "3.8"

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    ports:
      - 3000:3000
    volumes:
      - ./config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

6.4 Uptime Kuma: Service Monitoring

Uptime Kuma monitors the status of websites, services, and ports, and sends notifications when issues arise.

version: "3.8"

services:
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    ports:
      - "3001:3001"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

Receive notifications via Telegram, Discord, email, and more when downtime occurs.

6.5 Vaultwarden: Password Manager

Vaultwarden is a Bitwarden-compatible password manager. It's much lighter than the official Bitwarden server and optimized for self-hosting.

version: "3.8"

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    ports:
      - "8000:80"
    environment:
      - SIGNUPS_ALLOWED=true
      - ADMIN_TOKEN=your_random_admin_token
    volumes:
      - ./data:/data
    restart: unless-stopped

Running without HTTPS is a security risk, so always apply SSL through a reverse proxy.

7. Data Backup and Volume Management

7.1 Types of Volumes

  • Named Volume: Managed by Docker. Created with docker volume create
  • Bind Mount: Mounts a specific path on the host to the container

Generally, Bind Mounts are easier to manage for configuration files and data that needs backup.

7.2 Volume Management Commands

# List volumes
docker volume ls

# Volume details
docker volume inspect volume_name

# Delete volume
docker volume rm volume_name

# Clean up unused volumes
docker volume prune

7.3 Data Backup Strategies

Method 1: Direct Backup of Bind Mount Directories

# Stop service before backup
docker compose stop
tar -czvf backup_$(date +%Y%m%d).tar.gz ./data
docker compose start

Method 2: Backup from Running Container

# MySQL/MariaDB backup
docker exec my-db mysqldump -u root -p'password' --all-databases > backup.sql

# PostgreSQL backup
docker exec my-postgres pg_dumpall -U postgres > backup.sql

Method 3: Named Volume Backup

# Backup volume contents with temporary container
docker run --rm \
  -v volume_name:/source:ro \
  -v $(pwd):/backup \
  alpine tar -czvf /backup/volume_backup.tar.gz -C /source .

7.4 Automated Backup Script

#!/bin/bash
# backup.sh

BACKUP_DIR="/backup/docker"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup each service data
for dir in /opt/docker/*/; do
    service=$(basename $dir)
    tar -czvf "$BACKUP_DIR/${service}_${DATE}.tar.gz" -C $dir .
done

# Delete backups older than 30 days
find $BACKUP_DIR -type f -mtime +30 -delete

echo "Backup completed: $DATE"

Register in crontab for automatic execution:

# Backup at 3 AM daily
0 3 * * * /opt/scripts/backup.sh >> /var/log/docker-backup.log 2>&1

8. Docker Troubleshooting

8.1 Common Issues

Port Already in Use

# Find process using the port
sudo lsof -i :80
# Or change to a different port in docker-compose.yml

Permission Issues with Volume Access

# Check host directory permissions
ls -la ./data
# Change permissions
sudo chown -R 1000:1000 ./data

Container Keeps Restarting

# Check logs
docker logs container_name
# Change restart policy
docker update --restart no container_name

8.2 Disk Space Cleanup

# Check Docker disk usage
docker system df

# Clean up everything unused (caution!)
docker system prune -a

# Clean up excluding volumes
docker system prune

Conclusion

In this guide, we covered Docker from basic concepts to practical usage. Learning Docker makes home server management much easier. You can deploy new services with a single docker-compose file without worrying about dependencies, and if something goes wrong, just delete the container and start fresh.

The commands might feel unfamiliar at first, but using GUI tools like Portainer makes the learning curve much smoother. Start by installing the services introduced in this guide one by one to get comfortable with Docker.

In the next part, we'll learn about strengthening home server security - firewall configuration, VPN setup, intrusion detection, and essential knowledge for safe home server operation.