Fix lỗi "unable to get issuer certificate" khi cài SSL Let's Encrypt cho Zimbra
Ý kiến
0
Chưa có ý kiến nào. Hãy là người đầu tiên chia sẻ!
Chưa có ý kiến nào. Hãy là người đầu tiên chia sẻ!
Bạn vừa renew chứng chỉ Let's Encrypt cho Zimbra, chạy zmcertmgr verifycrt và nhận về một dòng cộc lốc:
unable to get issuer certificate
Khoan đổ lỗi cho acme.sh. Cert vẫn đúng, key vẫn khớp — vấn đề nằm ở chain.pem chưa đúng định dạng mà Zimbra Collaboration Suite yêu cầu, đặc biệt với các bản intermediate mới (R10/R11/R12/R13) của Let's Encrypt.
Bài này là note thực chiến mình hay phải dùng lại mỗi lần renew cert trên Zimbra production. Làm theo từng bước là chạy.
Khác với Nginx hay Apache — chỉ cần đẩy fullchain là xong — zmcertmgr của Zimbra khá khó tính. Nó yêu cầu tách hẳn 3 file:
cert.pem — chỉ server certificate (cert của domain bạn).
chain.pem — intermediate cộng với root CA phù hợp.
privkey.pem — private key của domain.
Lỗi unable to get issuer certificate nghĩa là khi OpenSSL của Zimbra duyệt ngược chain từ cert lên, nó không tìm thấy root CA đáng tin cậy để kết thúc chuỗi. Nói cách khác: chain của bạn đứt một mắt xích.
Trong vài trường hợp, file ca.cer mà acme.sh issue ra chỉ chứa intermediate — chưa có ISRG Root. Đó là lý do bạn cần append thêm bằng tay.
Tạo thư mục làm việc riêng cho cert (đừng đụng vào /opt/zimbra/ssl/zimbra/commercial cho đến bước deploy):
mkdir -p /opt/zimbra/ssl/letsencrypt
Copy server certificate từ acme.sh:
cp /root/.acme.sh/wigroup.vn/wigroup.vn.cer \
/opt/zimbra/ssl/letsencrypt/cert.pem
Copy private key:
cp /root/.acme.sh/wigroup.vn/wigroup.vn.key \
/opt/zimbra/ssl/letsencrypt/privkey.pem
Lưu ý: Thay
wigroup.vnbằng domain của bạn. Nếu acme.sh issue bằng ECC (mặc định gần đây), thư mục sẽ có hậu tố_ecc, ví dụ/root/.acme.sh/wigroup.vn_ecc/.
Đây là bước hay sai. Let's Encrypt hiện đang luân phiên ký bằng intermediate R10/R11/R12/R13, các intermediate này được cross-sign bởi ISRG Root X1. Zimbra muốn nhìn thấy cả intermediate và root trong cùng một file.
Bắt đầu bằng intermediate từ acme.sh:
cat /root/.acme.sh/wigroup.vn/ca.cer \
> /opt/zimbra/ssl/letsencrypt/chain.pem
Tải ISRG Root X1 trực tiếp từ Let's Encrypt:
curl -o /tmp/isrgrootx1.pem \
https://letsencrypt.org/certs/isrgrootx1.pem
Append root vào chain.pem:
cat /tmp/isrgrootx1.pem \
>> /opt/zimbra/ssl/letsencrypt/chain.pem
Sau bước này, chain.pem sẽ có 2 block -----BEGIN CERTIFICATE----- nối tiếp nhau: intermediate ở trên, ISRG Root X1 ở dưới. Đó chính xác là thứ zmcertmgr muốn.
Zimbra đọc private key từ thư mục commercial, nên cần đồng bộ key sang đó:
cp /root/.acme.sh/wigroup.vn/wigroup.vn.key \
/opt/zimbra/ssl/zimbra/commercial/commercial.key
Toàn bộ file cert/key phải thuộc user zimbra. Đây là lỗi mình từng bị: cert đúng, chain đúng, nhưng deploy fail chỉ vì file đang là root:root.
chown -R zimbra:zimbra /opt/zimbra/ssl/letsencrypt
chown zimbra:zimbra /opt/zimbra/ssl/zimbra/commercial/commercial.key
chmod 640 /opt/zimbra/ssl/letsencrypt/*
chmod 640 /opt/zimbra/ssl/zimbra/commercial/commercial.key
Trước khi deploy thật, luôn chạy verify để biết chain có hợp lệ không:
su - zimbra -c "
/opt/zimbra/bin/zmcertmgr verifycrt comm \
/opt/zimbra/ssl/letsencrypt/privkey.pem \
/opt/zimbra/ssl/letsencrypt/cert.pem \
/opt/zimbra/ssl/letsencrypt/chain.pem
"
Nếu mọi thứ đúng, output sẽ là:
** Verifying cert.pem against privkey.pem
Certificate (cert.pem) and private key (privkey.pem) match.
** Verifying cert.pem against chain.pem
Valid certificate chain
Còn lặp lại unable to get issuer certificate nghĩa là root chưa được append đúng — quay lại bước 3 và kiểm tra chain.pem có thực sự chứa 2 block CERTIFICATE không.
Khi verify đã pass, mới deploy:
su - zimbra -c "
/opt/zimbra/bin/zmcertmgr deploycrt comm \
/opt/zimbra/ssl/letsencrypt/cert.pem \
/opt/zimbra/ssl/letsencrypt/chain.pem
"
Cuối cùng, restart để Zimbra load cert mới cho tất cả service (mailbox, proxy, MTA, LDAP…):
su - zimbra -c "zmcontrol restart"
Quá trình restart mất khoảng 1–3 phút tuỳ cấu hình. Trong lúc chờ, có thể mở tab khác và test bằng:
openssl s_client -connect mail.wigroup.vn:443 -servername mail.wigroup.vn -showcerts < /dev/null
Đây là câu hỏi mình hay gặp nhất khi mentor cho team: cùng một script, lần renew tuần trước OK, tuần này lại fail.
Nguyên nhân: Let's Encrypt luân phiên ký cert bằng các intermediate khác nhau, hiện tại là R10, R11, R12, R13. Mỗi đợt renew, bạn không biết trước cert mới sẽ được ký bằng intermediate nào. Trong khi đó:
Zimbra 8.x — đặc biệt là các bản trước 8.8.15 P40+ — có store CA cũ.
OpenSSL cũ trên các bản OS đã EOL (CentOS 6, Ubuntu 16.04/18.04, Debian 9) không hiểu chain mới của LE.
Cross-sign expired: ISRG Root X1 cross-signed bởi DST Root CA X3 đã hết hạn từ tháng 9/2024 — server cũ vẫn cố verify qua mắt xích đó sẽ fail.
Append ISRG Root X1 trực tiếp vào chain.pem như bước 3 giúp cắt đứt sự phụ thuộc vào CA store của hệ điều hành — bạn cung cấp luôn root cho Zimbra, không cần OS biết về nó.
Với Zimbra 9.x / 10.x trên OS không quá cũ, có thể bỏ qua chuyện append root và dùng thẳng fullchain.cer mà acme.sh tạo sẵn:
su - zimbra -c "
/opt/zimbra/bin/zmcertmgr deploycrt comm \
/root/.acme.sh/wigroup.vn/fullchain.cer \
/root/.acme.sh/wigroup.vn/ca.cer
"
Nhưng — và đây là cái bẫy — không phải bản Zimbra nào cũng accept. Nhiều bản cũ vẫn báo lỗi chain bất kể fullchain có đúng hay không. Khi đó, quay về cách append ISRG Root ở trên là an toàn nhất.
Trước khi chọn cách deploy, kiểm tra version:
su - zimbra -c "zmcontrol -v"
Quy tắc kinh nghiệm:
Zimbra 8.x: gần như chắc chắn phải append ISRG Root X1.
Zimbra 9.x: thường OK với fullchain, nhưng vẫn nên append cho chắc nếu OS cũ.
Zimbra 10.x: dùng thẳng fullchain được, chain mới đã được fix.
Vì bạn sẽ phải làm lại mỗi 60–90 ngày, tốt nhất là viết script và gắn vào renew-hook của acme.sh:
acme.sh --install-cert -d wigroup.vn \
--key-file /opt/zimbra/ssl/letsencrypt/privkey.pem \
--fullchain-file /opt/zimbra/ssl/letsencrypt/cert.pem \
--reloadcmd "/opt/zimbra/scripts/deploy-cert.sh"
Trong /opt/zimbra/scripts/deploy-cert.sh, gói lại các bước 3 → 8 ở trên. Lúc đó renew thành job nền hoàn toàn, không phải đụng tay nữa.
Lỗi unable to get issuer certificate trên Zimbra hầu như luôn là vấn đề chain thiếu root, không phải cert sai. Ba điều cần nhớ:
Tách cert / chain / key thành 3 file riêng — Zimbra không hiểu fullchain gộp.
Append ISRG Root X1 vào chain.pem với các bản Zimbra/OS cũ.
Verify trước, deploy sau — đừng bỏ qua zmcertmgr verifycrt để rồi phải rollback giữa đêm.
Làm đúng tuần tự thì cert Let's Encrypt sẽ chạy mượt trên Zimbra, kể cả các bản 8.x đã già.
Hướng dẫn đầy đủ ssh port forwarding (-L local, -R remote, -D SOCKS) và autossh để giữ tunnel luôn sống — bao gồm các tham số quan trọng (ServerAliveInterval, ExitOnForwardFailure, GatewayPorts), biến môi trường autossh, và systemd service. Mọi lệnh đã test trong Docker.
Pipeline production Next.js → Docker → K8s với cache image, manual approval. Tổng kết best practices và kỹ thuật debug (CI Lint, visualizer, CI_DEBUG_TRACE).
Khai báo environment để GitLab theo dõi deployments, có lịch sử và nút rollback. Review Apps — tính năng signature: mỗi MR tự deploy lên môi trường tạm.