← All break/fix scenarios in Proxmox VE
Certificate auto-renewal fails and the GUI shows an expired cert warning
Reported symptoms
- ●Browser shows "Your connection is not private" with NET::ERR_CERT_DATE_INVALID
- ●The certificate was working yesterday
- ●pvecm updatecerts --renew (or the GUI renew button) fails
- ●journalctl shows ACME challenge failures
Evidence
- · openssl x509 -in /etc/pve/local/pveproxy-ssl.pem -noout -dates
- · journalctl -u pveproxy -e | grep -i acme
- · curl -v https://acme-v02.api.letsencrypt.org/directory
- · pvesh get /cluster/acme/directories
Diagnosis and resolutionclick to reveal
Root cause
The ACME renewal failed for one of several reasons: - Port 80 is not reachable from the internet (HTTP-01 challenge) - DNS-01 challenge credentials are wrong - The ACME account key is missing or expired - Rate limit hit (too many renewals in a short period) - Let's Encrypt CA changed their root certificate
Remediation
1. Check the current cert expiry: `openssl x509 -in /etc/pve/local/pveproxy-ssl.pem -noout -dates` 2. Check ACME config: `pvesh get /cluster/acme/account` 3. Force a renew attempt with verbose output: `pveproxy ACME renew` Or via the GUI: Datacenter → ACME → Accounts → Force renew 4. Check the specific failure: - HTTP-01: ensure port 80 is forwarded to the PVE host - DNS-01: re-enter the API token for your DNS provider - Rate limit: wait or use the staging directory temporarily 5. If the cert is now expired, generate a self-signed cert as interim: `pvecm updatecerts --selfsigned` Then plan the ACME re-setup. 6. If you need immediate external access, use a different host name or accept the warning temporarily.
Verification
- The cert is valid for >30 days (auto-renewal healthy) - Browser shows no certificate warning - `openssl x509 ... -dates` shows future expiry - All API calls over HTTPS succeed
Prevention
- Monitor cert expiry with an alert (cert_expiry < 30 days) - Use DNS-01 challenge for hosts behind firewalls - Document the renewal procedure - Test the renewal quarterly with --dry-run if available