Certificate Issuance Guide
📝 Documentation in Progress
This page is currently under development. For now, see the Introduction for basic certificate issuance workflow.
Overview
cert-ctrl supports issuing certificates from multiple Certificate Authorities (CAs):
- Let's Encrypt - Free, automated, production-ready
- ZeroSSL - Free alternative with commercial options
- Self-signed certificates for development
Prerequisites
Before issuing certificates, ensure you have:
- ✅ Domain ownership - You control the domain's DNS
- ✅ DNS provider configured - API credentials for automated validation
- ✅ ACME account - Registered with your chosen CA
Supported DNS Providers
cert-ctrl uses DNS-01 challenges for domain validation, supporting:
- Cloudflare - Global CDN and DNS
- Aliyun (Alibaba Cloud) - Popular in Asia-Pacific
- (More providers coming soon)
For technical details on DNS-01 validation, see DNS-01 Challenge Explained.
Quick Start
1. Configure DNS Provider
# Example: Cloudflare
curl -X POST https://cjj365.cc/apiv1/users/1/dns-providers \
-H "Content-Type: application/json" \
-H "Cookie: cjj365=$SESSION" \
-d '{
"provider": "cloudflare",
"api_token": "your_cloudflare_token",
"zone_id": "your_zone_id"
}'
2. Create ACME Account
# Register with Let's Encrypt
curl -X POST https://cjj365.cc/apiv1/users/1/acme-accounts \
-H "Content-Type: application/json" \
-H "Cookie: cjj365=$SESSION" \
-d '{
"ca_provider": "letsencrypt",
"email": "admin@example.com",
"terms_accepted": true
}'
3. Issue Certificate
curl -X POST https://cjj365.cc/apiv1/users/1/certificates \
-H "Content-Type: application/json" \
-H "Cookie: cjj365=$SESSION" \
-d '{
"domain": "example.com",
"sans": ["www.example.com", "api.example.com"],
"acme_account_id": 1,
"dns_provider_id": 1
}'
Certificate Lifecycle
┌─────────────┐
│ Request │
│ Certificate │
└──────┬──────┘
│
▼
┌─────────────┐ DNS-01 ┌──────────────┐
│ Create │ ──────────────► │ DNS Provider │
│ Order │ │ (Cloudflare)│
└──────┬──────┘ └──────────────┘
│
▼
┌─────────────┐
│ Validate │
│ Challenge │
└──────┬──────┘
│
▼
┌─────────────┐
│ Finalize │
│ Order │
└──────┬──────┘
│
▼
┌─────────────┐
│ Download │
│ Certificate │
└─────────────┘
Issuance Workflow
Step 1: Domain Validation
cert-ctrl automatically:
- Creates ACME order with CA
- Receives DNS-01 challenge token
- Creates TXT record via DNS provider API
- Waits for DNS propagation (typically 30-60 seconds)
- Notifies CA that challenge is ready
- CA validates domain ownership
Step 2: Certificate Generation
Once validated:
- Generate private key (RSA 2048 or ECDSA P-256)
- Create Certificate Signing Request (CSR)
- Submit CSR to CA
- CA issues certificate
Step 3: Storage and Encryption
Depending on your Private Key Policy:
- MASTER_ONLY: Encrypted with server master key
- HYBRID: Encrypted with both master and device keys
- DEVICE_REQUIRED: Encrypted only with device keys
Web UI Workflow
Via Dashboard
- Navigate to Certificates → Issue New Certificate
- Enter domain details:
- Primary domain:
example.com - Additional SANs:
www.example.com,api.example.com
- Primary domain:
- Select ACME account (Let's Encrypt or ZeroSSL)
- Select DNS provider (Cloudflare or Aliyun)
- Click Issue Certificate
- Monitor progress in real-time
- Certificate appears in list once issued
Advanced Options
Certificate Settings
{
"domain": "example.com",
"sans": ["www.example.com"],
"key_type": "ecdsa", // or "rsa"
"key_size": 256, // ECDSA: 256/384, RSA: 2048/4096
"auto_renew": true,
"renew_days_before": 30
}
Wildcard Certificates
{
"domain": "*.example.com",
"sans": ["example.com"], // Include base domain
"dns_provider_id": 1 // DNS-01 required for wildcards
}
Auto-Renewal
cert-ctrl automatically renews certificates:
- Renewal Window: 30 days before expiry (configurable)
- Retry Logic: Exponential backoff on failures
- Notification: Email alerts on renewal success/failure
- Agent Deployment: Renewed certificates auto-deploy to agents
Manual Renewal
curl -X POST https://cjj365.cc/apiv1/users/1/certificates/1001/renew \
-H "Cookie: cjj365=$SESSION"
Troubleshooting
Common Issues
DNS validation failed:
- Verify DNS provider credentials
- Check TXT record propagation:
dig _acme-challenge.example.com TXT - Allow 60-120 seconds for DNS propagation
Rate limit exceeded:
- Let's Encrypt: 50 certificates per domain per week
- Use staging environment for testing
- Consider ZeroSSL as alternative
Invalid CSR:
- Check domain name format
- Verify SANs are subdomains of primary domain
- Ensure key size is supported by CA
Debug Mode
Enable verbose logging:
{
"acme": {
"log_level": "debug",
"save_requests": true
}
}
Best Practices
- Test with Staging: Use Let's Encrypt staging for development
- Monitor Expiry: Set alerts for certificates expiring soon
- Backup Private Keys: Use MASTER_ONLY policy for critical certs
- Rotate Regularly: Even with auto-renewal, test rotation process
- Use Wildcards: Reduce certificate count for many subdomains
Security Considerations
Private Key Storage
- Keys encrypted at rest (AES-256-GCM)
- Master key stored securely (HSM recommended for production)
- Device keys never leave devices
- Audit logs track all key access
CA Selection
| Feature | Let's Encrypt | ZeroSSL |
|---|---|---|
| Cost | Free | Free + Paid |
| Rate Limits | 50/week/domain | Higher limits |
| Validation | ACME standard | ACME + alternatives |
| Support | Community | Commercial available |
| Wildcard | ✅ Yes | ✅ Yes |
Next Steps
- Private Key Policy - Security models
- DNS-01 Challenge - Technical details