Introduction
GitLab Pages supports automatic Let's Encrypt certificate provisioning for custom domains. When certificate renewal fails -- due to DNS changes, rate limiting, or validation challenges -- the domain's HTTPS certificate expires, causing browser security warnings and broken page access for visitors.
Symptoms
- GitLab Pages custom domain shows
SSL certificate expiredin browser - GitLab Pages settings show
Certificate renewal failed - Visitors see
NET::ERR_CERT_DATE_INVALIDor similar browser warnings - Let's Encrypt rate limit reached, preventing immediate renewal
- Error message:
Failed to renew Let's Encrypt certificate: challenge failed
Common Causes
- DNS A/CNAME record changed, breaking domain validation for ACME challenge
- Let's Encrypt rate limit exceeded (5 certificates per domain per 7 days)
- Custom domain not properly configured in GitLab Pages settings
- GitLab Pages daemon not running or misconfigured for certificate management
- Firewall blocking Let's Encrypt validation requests to the GitLab Pages server
Step-by-Step Fix
- 1.Check the certificate status in GitLab Pages settings: Verify the renewal state.
- 2.
` - 3.# GitLab UI: Project > Pages > Your custom domain
- 4.# Check certificate status and expiration date
- 5.# Look for error messages about the renewal failure
- 6.
` - 7.Verify DNS records point to the correct Pages server: Ensure domain validation works.
- 8.```bash
- 9.# Check A record
- 10.dig A mydomain.example.com +short
- 11.# Check CNAME (if using CNAME)
- 12.dig CNAME mydomain.example.com +short
- 13.# Should point to GitLab Pages IP or <username>.gitlab.io
- 14.
` - 15.Trigger manual certificate renewal: Force a new Let's Encrypt request.
- 16.```bash
- 17.# Via GitLab API
- 18.curl --request PUT --header "PRIVATE-TOKEN: $TOKEN" \
- 19."https://gitlab.example.com/api/v4/projects/$PROJECT_ID/pages/domains/mydomain.example.com" \
- 20.--form "certificate=" --form "key="
- 21.# This triggers automatic Let's Encrypt renewal
- 22.
` - 23.Check Let's Encrypt rate limit status: Verify you are not rate-limited.
- 24.```bash
- 25.# Check via Let's Encrypt API
- 26.curl -s https://letsencrypt.org/documents/rate-limits/
- 27.# If rate-limited, wait for the cooldown period (typically 1 hour)
- 28.
` - 29.Verify the new certificate is active: Confirm HTTPS is working.
- 30.```bash
- 31.echo | openssl s_client -connect mydomain.example.com:443 -servername mydomain.example.com 2>/dev/null | openssl x509 -noout -dates
- 32.
`
Prevention
- Monitor certificate expiration dates and alert 14 days before expiry
- Ensure DNS records are stable and point to the correct GitLab Pages server
- Use GitLab-managed certificates rather than manual uploads when possible
- Document DNS requirements for GitLab Pages custom domains in the project README
- Test certificate renewal in a staging project before applying to production domains
- Keep Let's Encrypt rate limits in mind when making DNS changes that trigger re-validation