Home > Blog > it_devops

Docker Compose สำหรับ Home Lab 2026 คู่มือตั้งค่าครบจบ

docker compose homelab 2026
2026-03-22 | it_devops | 2000 words

หลายคนที่เริ่มทำ Home Lab มักเจอปัญหาเดิม คือรัน Docker container ด้วย command ยาวๆ แล้วลืมว่าพิมพ์อะไรไป พอ container พังหรือต้อง restart server ก็ต้องมานั่งไล่ดูว่า flag อะไรที่ใส่ไป Docker Compose แก้ปัญหานี้ได้ตรงๆ ด้วยการเอา configuration ทุกอย่างไปเขียนในไฟล์เดียว

บทความนี้จะพาทำ Home Lab ด้วย Docker Compose ตั้งแต่พื้นฐานจนถึง stack ที่ใช้งานได้จริง รวมถึง service ยอดนิยมอย่าง Portainer, Nginx Proxy Manager, Pi-hole, Nextcloud และ Grafana+Prometheus

Docker Compose คืออะไร และทำไมต้องใช้

Docker Compose เป็นเครื่องมือที่ช่วยจัดการ multi-container Docker application ด้วยไฟล์ YAML ไฟล์เดียว แทนที่จะต้องรัน docker run หลายๆ ครั้งพร้อม option เยอะๆ ก็เขียนทุกอย่างลงใน docker-compose.yml แล้วรันแค่ docker compose up -d

ข้อดีหลักๆ ที่ทำให้ใช้ Docker Compose ใน Home Lab

ปัจจุบัน Docker Compose v2 เป็น plugin ในตัว Docker แล้ว ไม่ต้องติดตั้งแยก และใช้คำสั่ง docker compose แทน docker-compose (ไม่มี hyphen)

โครงสร้าง docker-compose.yml

ก่อนจะลงมือทำ Home Lab ต้องเข้าใจโครงสร้างพื้นฐานของไฟล์ก่อน

services:
  ชื่อ-service:
    image: image-name:tag
    container_name: ชื่อ-container
    restart: unless-stopped
    ports:
      - "host-port:container-port"
    volumes:
      - /path/on/host:/path/in/container
    environment:
      - VARIABLE_NAME=value
    networks:
      - ชื่อ-network
    depends_on:
      - service-อื่น

networks:
  ชื่อ-network:
    driver: bridge

volumes:
  ชื่อ-volume:
    driver: local

Key concepts ที่ต้องรู้:

Environment Variables และ .env File

อย่าเขียน password หรือ secret ตรงๆ ใน docker-compose.yml สร้าง .env file แยกแล้วอ้างอิงแทน

# .env file
POSTGRES_PASSWORD=your-super-secret-password
DOMAIN=yourdomain.com
TZ=Asia/Bangkok
PUID=1000
PGID=1000
# docker-compose.yml
services:
  postgres:
    image: postgres:16
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - TZ=${TZ}

เพิ่ม .env เข้า .gitignore เสมอ แต่เก็บ .env.example ไว้ใน repo เพื่อให้คนอื่นรู้ว่าต้องกำหนด variable อะไรบ้าง

Service หลักสำหรับ Home Lab

1. Portainer — จัดการ Docker ผ่าน Web UI

Portainer เป็น GUI สำหรับจัดการ Docker ที่ใช้งานง่ายที่สุด เหมาะสำหรับคนที่ไม่อยากพิมพ์ command ตลอดเวลา

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

volumes:
  portainer_data:

หลังรันแล้วเข้าไปที่ http://server-ip:9000 สร้าง admin account แล้วก็จัดการ container ผ่าน web ได้เลย

2. Nginx Proxy Manager — Reverse Proxy พร้อม SSL

แทนที่จะเปิด port ตรงๆ ให้ทุก service ใช้ Nginx Proxy Manager (NPM) เป็น reverse proxy แล้วจัดการ SSL certificate ได้ง่ายๆ ผ่าน GUI

services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "81:81"    # Admin UI
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    environment:
      - TZ=${TZ}

volumes:
  npm_data:
  npm_letsencrypt:

Port 81 คือ Admin UI เข้าครั้งแรกใช้ admin@example.com / changeme แล้วเปลี่ยนทันที NPM จะ request SSL certificate จาก Let's Encrypt ให้อัตโนมัติ

3. Pi-hole — Block Ads ทั้งบ้าน

Pi-hole ทำหน้าที่เป็น DNS server ที่ block domain ของ ad network ทำให้ทุก device ในบ้านที่ใช้ DNS นี้ไม่เห็นโฆษณา

services:
  pihole:
    image: pihole/pihole:latest
    container_name: pihole
    restart: unless-stopped
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "8080:80/tcp"
    environment:
      - TZ=${TZ}
      - WEBPASSWORD=${PIHOLE_PASSWORD}
    volumes:
      - pihole_etc:/etc/pihole
      - pihole_dnsmasq:/etc/dnsmasq.d
    cap_add:
      - NET_ADMIN

volumes:
  pihole_etc:
  pihole_dnsmasq:

สิ่งสำคัญ: ต้อง disable systemd-resolved บน Ubuntu ก่อนเพราะชน port 53

sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

4. Nextcloud — Private Cloud Storage

Nextcloud เป็น self-hosted alternative สำหรับ Google Drive / iCloud ใช้ PostgreSQL เป็น database และ Redis สำหรับ caching

services:
  nextcloud-db:
    image: postgres:16
    container_name: nextcloud-db
    restart: unless-stopped
    volumes:
      - nextcloud_db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD=${NEXTCLOUD_DB_PASSWORD}

  nextcloud-redis:
    image: redis:alpine
    container_name: nextcloud-redis
    restart: unless-stopped

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    ports:
      - "8081:80"
    volumes:
      - nextcloud_data:/var/www/html
    environment:
      - POSTGRES_HOST=nextcloud-db
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
      - REDIS_HOST=nextcloud-redis
      - NEXTCLOUD_TRUSTED_DOMAINS=cloud.${DOMAIN}
      - TZ=${TZ}
    depends_on:
      - nextcloud-db
      - nextcloud-redis
    networks:
      - nextcloud_net
      - default

networks:
  nextcloud_net:

volumes:
  nextcloud_db:
  nextcloud_data:

5. Grafana + Prometheus — Monitoring Stack

ดู metrics ของ server และ service ต่างๆ แบบ real-time ด้วย Grafana dashboard และ Prometheus เป็น data source

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
    depends_on:
      - prometheus

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'

volumes:
  prometheus_data:
  grafana_data:

สร้าง prometheus.yml ด้วย:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

การจัดการ Network

Docker Compose สร้าง network ให้อัตโนมัติชื่อ projectname_default ทุก service ใน compose file เดียวกันคุยกันได้ผ่านชื่อ service แต่ถ้าต้องการให้ service คนละ stack คุยกัน ต้องสร้าง external network

# สร้าง network สำหรับ proxy
docker network create proxy

# ใน compose file ของ NPM
networks:
  proxy:
    external: true

# ใน compose file ของ service อื่น
networks:
  proxy:
    external: true

วิธีนี้ทำให้ NPM เข้าถึง service อื่นๆ ได้โดยไม่ต้อง expose port ออกมา

คำสั่งที่ใช้บ่อย

# Start ทุก service
docker compose up -d

# Stop ทุก service
docker compose down

# ดู logs
docker compose logs -f
docker compose logs -f service-name

# Restart service เดียว
docker compose restart service-name

# Pull image ใหม่และ recreate
docker compose pull && docker compose up -d

# ดูสถานะ service
docker compose ps

# เข้าไปใน container
docker compose exec service-name bash

Tips การจัดการ Stack หลายอัน

เมื่อ service เยอะขึ้น ควรแยก compose file ตาม category

~/docker/
├── infrastructure/
│   ├── docker-compose.yml    # NPM, Portainer
│   └── .env
├── media/
│   ├── docker-compose.yml    # Jellyfin, Radarr, etc.
│   └── .env
├── monitoring/
│   ├── docker-compose.yml    # Grafana, Prometheus
│   ├── prometheus.yml
│   └── .env
└── services/
    ├── docker-compose.yml    # Nextcloud, Pi-hole
    └── .env

สร้าง script สำหรับ update ทุก stack พร้อมกัน

#!/bin/bash
STACKS=("infrastructure" "media" "monitoring" "services")

for stack in "${STACKS[@]}"; do
  echo "Updating $stack..."
  cd ~/docker/$stack
  docker compose pull
  docker compose up -d
done

echo "All stacks updated!"

สำหรับ Home Lab ขั้นสูง ลองดูบทความ การ Setup Proxmox Cluster เพื่อรัน Docker บน VM หลายๆ เครื่องได้ และ Cloudflare Tunnel สำหรับ expose service ออก internet อย่างปลอดภัยโดยไม่ต้อง port forward

การ Backup Volumes

ข้อมูลสำคัญอยู่ใน Docker volumes ต้อง backup สม่ำเสมอ

# Backup volume เป็น tar
docker run --rm \
  -v volume-name:/data \
  -v /backup:/backup \
  alpine tar czf /backup/volume-name-$(date +%Y%m%d).tar.gz -C /data .

# Restore จาก backup
docker run --rm \
  -v volume-name:/data \
  -v /backup:/backup \
  alpine tar xzf /backup/volume-name-20260101.tar.gz -C /data

หรือจะใช้ แนวทางการรักษาความปลอดภัย server ร่วมด้วยเพื่อให้ Home Lab มีความปลอดภัยมากขึ้น


คำถามที่พบบ่อย (FAQ)

Docker Compose v2 ต่างจาก v1 อย่างไร?

Docker Compose v2 เป็น Go binary ที่ build ใหม่ทั้งหมด เร็วกว่า v1 ที่เป็น Python script และรวมเป็น plugin ของ Docker แล้ว ใช้คำสั่ง docker compose แทน docker-compose v1 ถูก deprecate แล้วตั้งแต่ปี 2023

ควรใช้ named volumes หรือ bind mounts?

Named volumes (volume-name:/path) เหมาะสำหรับ database และข้อมูลที่ Docker จัดการเอง Bind mounts (/host/path:/container/path) เหมาะสำหรับ config files ที่ต้องการแก้ไขง่ายจาก host

ทำไม container restart ตัวเองตลอด?

ตรวจสอบ logs ด้วย docker compose logs service-name สาเหตุทั่วไปคือ config ผิด, environment variable ขาด, หรือ port ชนกัน

จะ update image ทุก container พร้อมกันได้ไหม?

ได้ด้วยคำสั่ง docker compose pull && docker compose up -d Docker จะ pull image ใหม่และ recreate เฉพาะ container ที่ image เปลี่ยน

Home Lab ต้องใช้ RAM เท่าไหร่?

stack พื้นฐาน (Portainer + NPM + Pi-hole) ใช้ประมาณ 512MB เพิ่ม Nextcloud อีกประมาณ 1GB และ monitoring stack อีก 512MB รวมๆ สำหรับทุก service ในบทความนี้ควรมี RAM อย่างน้อย 4GB

จะเก็บ docker-compose.yml ใน Git ได้ไหม?

ได้ และควรทำ แต่อย่าลืมเพิ่ม .env เข้า .gitignore เก็บแค่ .env.example ไว้เป็น template


Back to Blog | iCafe Forex | SiamLanCard | Siam2R

ปฏิทินข่าว Forex | Smart Money Concept

วิเคราะห์ทองคำ | กลยุทธ์เทรดทอง