ติดตั้ง Docker Registry ส่วนตัวบน VPS

ติดตั้ง Docker Registry ส่วนตัวบน VPS

มิถุนายน 2026 · อ่าน 7 นาที

Docker Hub มีข้อจำกัดด้าน rate limit และ privacy โดยเฉพาะ image ที่เป็น internal project ที่ไม่อยากให้คนอื่นเห็น การตั้ง Docker Registry ส่วนตัวบน VPS ช่วยให้ push/pull image ได้เร็วขึ้นเพราะอยู่บน network เดียวกัน และควบคุม access ได้เต็มที่ผ่าน authentication และ TLS

ติดตั้ง Docker Registry ด้วย Docker Compose

วิธีที่ง่ายที่สุดคือรัน Registry ผ่าน Docker Compose แล้วใส่ reverse proxy ด้วย Nginx:

sudo apt update && sudo apt install docker.io docker-compose -y
sudo systemctl enable --now docker

mkdir -p ~/registry/auth ~/registry/data
cd ~/registry
cat > docker-compose.yml <<'EOF'
version: '3'
services:
  registry:
    image: registry:2
    container_name: docker-registry
    restart: unless-stopped
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./auth:/auth
      - ./data:/data
    ports:
      - "5000:5000"
EOF

สร้าง User Authentication

# ติดตั้ง htpasswd
sudo apt install apache2-utils -y

# สร้าง user (เปลี่ยน myuser เป็นชื่อที่ต้องการ)
htpasswd -Bc ~/registry/auth/htpasswd myuser
# จะถามรหัสผ่าน

# เพิ่ม user เพิ่มเติม
htpasswd -B ~/registry/auth/htpasswd anotheruser

ตั้ง Nginx Reverse Proxy + TLS

sudo nano /etc/nginx/sites-available/registry
server {
    listen 443 ssl;
    server_name registry.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/registry.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.yourdomain.com/privkey.pem;

    client_max_body_size 0;  # สำคัญ: ไม่จำกัด size สำหรับ image
    chunked_transfer_encoding on;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 900;
    }
}
server {
    listen 80;
    server_name registry.yourdomain.com;
    return 301 https://$host$request_uri;
}
sudo ln -s /etc/nginx/sites-available/registry /etc/nginx/sites-enabled/
sudo certbot --nginx -d registry.yourdomain.com
sudo nginx -t && sudo systemctl reload nginx
cd ~/registry && docker-compose up -d

Push และ Pull Image จาก Registry ส่วนตัว

# Login จากเครื่อง client
docker login registry.yourdomain.com
# ใส่ username และ password ที่สร้างด้วย htpasswd

# Tag image ก่อน push
docker tag myapp:latest registry.yourdomain.com/myapp:latest

# Push ขึ้น Registry
docker push registry.yourdomain.com/myapp:latest

# Pull กลับมาใช้
docker pull registry.yourdomain.com/myapp:latest

ดู Images ที่อยู่ใน Registry

# ดูรายการ repositories ทั้งหมด
curl -u myuser:password https://registry.yourdomain.com/v2/_catalog

# ดู tags ของ image
curl -u myuser:password https://registry.yourdomain.com/v2/myapp/tags/list

# ดูขนาดพื้นที่ใช้งาน
du -sh ~/registry/data/
Tip: ใส่ client_max_body_size 0 ใน Nginx config เสมอ ถ้าไม่ตั้ง Nginx จะ reject image ที่ใหญ่กว่า 1MB ซึ่งคือ image แทบทุกตัว

ตรวจสอบว่า Docker Registry ทำงานถูกต้อง

# ตรวจ container status
docker ps | grep registry

# ทดสอบ API โดยตรง
curl -u myuser:password https://registry.yourdomain.com/v2/

# Push test image จาก Docker Hub ก่อน tag แล้ว push ขึ้น private registry
docker pull hello-world
docker tag hello-world registry.yourdomain.com/hello-world:test
docker push registry.yourdomain.com/hello-world:test

# Pull กลับมาตรวจ
docker rmi registry.yourdomain.com/hello-world:test
docker pull registry.yourdomain.com/hello-world:test
Tip: curl ไปที่ /v2/ และได้ {} กลับมาพร้อม HTTP 200 หมายความว่า Registry ทำงานถูกต้องและ authentication ผ่าน

แก้ปัญหาที่พบบ่อย

Error: "http: server gave HTTP response to HTTPS client"

Docker client พยายาม connect ผ่าน HTTPS แต่ Registry รันบน HTTP plain ต้องตั้ง insecure-registries หรือใช้ TLS:

sudo nano /etc/docker/daemon.json
{
  "insecure-registries": ["registry.yourdomain.com:5000"]
}
sudo systemctl restart docker

Error: "413 Request Entity Too Large"

Nginx ปฏิเสธ image เพราะ body size limit ต้องเพิ่ม config:

sudo nano /etc/nginx/sites-available/registry
# เพิ่มใน server block:
client_max_body_size 0;

sudo nginx -t && sudo systemctl reload nginx

Error: "unauthorized: authentication required"

htpasswd ไม่ถูกต้อง หรือ mount path ผิด ตรวจสอบ:

# ตรวจไฟล์ htpasswd
cat ~/registry/auth/htpasswd

# ทดสอบ login
docker logout registry.yourdomain.com
docker login registry.yourdomain.com

# ดู container logs
docker logs docker-registry

Disk เต็มจาก images เก่า

ต้อง garbage collect ลบ layer ที่ไม่ถูกอ้างอิงแล้ว:

docker exec docker-registry registry garbage-collect /etc/docker/registry/config.yml
# ดูขนาดก่อน-หลัง
du -sh ~/registry/data/

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

Registry ส่วนตัวกับ Docker Hub ต่างกันอย่างไร?

Docker Hub เป็น public registry ที่มี rate limit (100 pull/6h สำหรับ anonymous) Registry ส่วนตัวไม่มีข้อจำกัด push/pull ควบคุม access ได้เอง และ image ไม่ถูก expose สู่ public เหมาะสำหรับ CI/CD pipeline ภายในองค์กร

ใช้ Registry กับ Kubernetes ได้ไหม?

ได้ ต้องสร้าง imagePullSecret ใน Kubernetes ก่อน แล้วระบุใน Pod spec หรือ ServiceAccount เพื่อให้ Kubernetes pull image จาก private registry ได้ โดยใช้ kubectl create secret docker-registry

มีทางเลือกอื่นนอกจาก Registry official image ไหม?

มี เช่น Harbor (enterprise, มี UI + vulnerability scanning), Gitea Package Registry, และ Nexus Repository Manager แต่สำหรับการใช้งานส่วนตัวบน VPS เดียว Registry official image เบาและเสถียรที่สุด