Sửa lỗi 'x509: certificate has expired or is not yet valid' Khi Pull từ Docker Registry

intermediate🐳 Docker2026-05-15| Docker 20.x+, Linux/macOS/Windows, self-hosted Docker Registry hoặc corporate registry có TLS

Error Message

Get "https://registry.example.com/v2/": x509: certificate has expired or is not yet valid: current time 2025-01-01T00:00:00Z is after 2024-12-31T23:59:59Z
#docker#ssl#certificate#x509#registry#expired

TL;DR

Ba cách sửa nhanh tùy theo nguyên nhân:

  • Cert của registry đã hết hạn → gia hạn lại (Let's Encrypt hoặc CA của bạn)
  • Đồng hồ hệ thống bị sai → đồng bộ với NTP (timedatectl set-ntp true)
  • Môi trường dev/test và bạn không cần quan tâm → thêm registry vào insecure-registries trong cấu hình Docker daemon

Lỗi Đầy Đủ

Get "https://registry.example.com/v2/": x509: certificate has expired or is not yet valid: current time 2025-01-01T00:00:00Z is after 2024-12-31T23:59:59Z

Bạn sẽ gặp lỗi này khi chạy docker pull, docker push, hoặc docker login — bất kỳ thao tác nào mở kết nối TLS đến một registry. Thông tin thời gian trong thông báo lỗi là manh mối đầu tiên. Chạy date trên máy của bạn và so sánh với những gì Docker thấy. Kiểm tra 30 giây này thường cho bạn biết tất cả.

Nguyên Nhân

Mọi chứng chỉ TLS đều có khoảng thời gian hiệu lực được định nghĩa bởi hai trường: notBeforenotAfter. TLS stack Go của Docker sẽ từ chối kết nối ngay khi vượt qua một trong hai ranh giới này:

  • notAfter của cert đã là quá khứ — cert của registry thực sự đã hết hạn
  • Đồng hồ cục bộ của bạn chạy trước notAfter — cert hợp lệ trông như đã hết hạn do lệch giờ
  • Đồng hồ cục bộ của bạn chậm hơn notBefore — cert trông như chưa có hiệu lực

Lệch giờ đồng hồ tinh vi hơn bạn nghĩ. Một VM bị tạm dừng vài giờ, một container host không có NTP, hoặc laptop bị trôi 5 phút — bất kỳ trường hợp nào trong số này đều có thể gây ra chính xác lỗi tương tự như cert thực sự hết hạn.

Bước 1 — Kiểm Tra Thời Hạn Của Chứng Chỉ

Đừng đoán mò. Lấy cert trực tiếp và đọc ngày của nó:

# Kiểm tra cert của registry trực tiếp
openssl s_client -connect registry.example.com:443 -servername registry.example.com 2>/dev/null \
  | openssl x509 -noout -dates

# Ví dụ đầu ra:
# notBefore=Dec  1 00:00:00 2024 GMT
# notAfter=Dec 31 23:59:59 2024 GMT

Nếu notAfter trước ngày hôm nay, cert đã hết hạn — chuyển đến Cách A. Nếu các ngày trông hoàn toàn bình thường, đồng hồ hệ thống của bạn đang nói dối Docker.

Bước 2 — Kiểm Tra Độ Lệch Đồng Hồ Hệ Thống

# Kiểm tra giờ hiện tại và trạng thái đồng bộ NTP
timedatectl status

# Hoặc đơn giản:
date -u

Lệch hơn một hoặc hai phút? Hãy sửa lại:

# Bật đồng bộ NTP (Linux dùng systemd)
timedatectl set-ntp true

# Ép đồng bộ ngay lập tức
sudo chronyc makestep
# hoặc
sudo ntpdate -u pool.ntp.org

VM bị tạm dừng thường là thủ phạm chính ở đây — đồng hồ đóng băng khi host ngủ, rồi thức dậy có thể bị tụt hàng giờ. Sau khi đồng bộ, thử lại docker pull. Nếu lỗi đồng hồ là nguyên nhân? Sẽ hoạt động ngay lập tức.

Cách A — Gia Hạn Chứng Chỉ Registry

Bạn quản lý registry và cert đã hết hạn. Đã đến lúc thay thế.

Let's Encrypt (Certbot)

# Gia hạn tất cả cert
sudo certbot renew

# Buộc gia hạn dù chưa gần hết hạn
sudo certbot renew --force-renewal --cert-name registry.example.com

Sau đó khởi động lại dịch vụ registry của bạn:

# Nếu đang chạy dưới dạng Docker container
docker restart registry

# Hoặc dùng systemd
sudo systemctl restart docker-registry

Cert tự ký (tạo cert mới)

openssl req -newkey rsa:4096 -nodes -sha256 \
  -keyout /certs/domain.key \
  -x509 -days 365 \
  -out /certs/domain.crt \
  -subj "/CN=registry.example.com" \
  -addext "subjectAltName=DNS:registry.example.com"

Khởi động lại container registry với đường dẫn cert mới được mount vào. Mọi máy Docker client cũng cần tin tưởng cert mới — xem Cách B.

Cách B — Tin Tưởng Cert Tự Ký Hoặc CA Nội Bộ

Registry của doanh nghiệp và CA nội bộ không có trong kho tin tưởng mặc định của Docker. Cách sửa là đặt cert vào thư mục theo từng registry của Docker:

# Tạo thư mục cho registry này
sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000

# Sao chép CA cert (hoặc cert tự ký)
sudo cp ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt

Không cần khởi động lại daemon — Docker đọc thư mục này mỗi khi kết nối.

Muốn tin tưởng toàn hệ thống để curl, openssl, và mọi thứ khác cũng chấp nhận cert?

# Ubuntu/Debian
sudo cp ca.crt /usr/local/share/ca-certificates/registry-ca.crt
sudo update-ca-certificates

# RHEL/CentOS/Fedora
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/registry-ca.crt
sudo update-ca-trust

Cách C — Registry Không An Toàn (Chỉ Dùng Dev/Test)

Đang mắc kẹt trong pipeline CI hoặc vòng lặp dev cục bộ và chỉ cần nó hoạt động ngay bây giờ? Đánh dấu registry là không an toàn. Không được dùng trong môi trường production.

Chỉnh sửa /etc/docker/daemon.json:

{
  "insecure-registries": ["registry.example.com:5000"]
}

Khởi động lại daemon:

sudo systemctl restart docker

Docker sẽ kết nối qua HTTP hoặc bỏ qua xác minh TLS cho registry đó. Cài đặt nhanh, thực sự nguy hiểm trong production — bạn đã được cảnh báo.

Xác Nhận Đã Sửa Xong

# Thử lại lệnh pull
docker pull registry.example.com/myimage:latest

# Xác nhận cert sẽ không hết hạn trong ít nhất 24 giờ tới
openssl s_client -connect registry.example.com:443 -servername registry.example.com 2>/dev/null \
  | openssl x509 -noout -checkend 86400
# Hiển thị: "Certificate will not expire" nếu còn hiệu lực

# Gọi trực tiếp API v2 của registry
curl -v https://registry.example.com/v2/

Phòng Tránh Lỗi Này Tái Diễn

  • Tự động hóa việc gia hạn cert: certbot renew qua cron hoặc systemd timer, chạy trước 30 ngày khi cert hết hạn — không phải đến ngày nó chết mới làm
  • Giám sát ngày hết hạn với ssl-cert-check hoặc Prometheus ssl_expiry exporter; cảnh báo cho mình khi còn 14 ngày
  • Luôn chạy NTP trên mọi Docker host, đặc biệt là VM — timedatectl show | grep NTPSynchronized là cách kiểm tra nhanh
  • Cert tự ký với chu kỳ 365 ngày hết hạn nhanh hơn bạn nhớ; hãy tự động hóa việc xoay vòng cert hoặc chuyển sang Let's Encrypt

Tham Chiếu Nhanh

# Kiểm tra hạn cert
openssl s_client -connect HOST:PORT 2>/dev/null | openssl x509 -noout -dates

# Đồng bộ đồng hồ
timedatectl set-ntp true && sudo chronyc makestep

# Tin tưởng CA cert (chỉ Docker)
sudo mkdir -p /etc/docker/certs.d/HOST:PORT
sudo cp ca.crt /etc/docker/certs.d/HOST:PORT/ca.crt

# Fallback registry không an toàn (chỉ dev)
# /etc/docker/daemon.json → { "insecure-registries": ["HOST:PORT"] }
sudo systemctl restart docker

Related Error Notes