Skip to main content

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:

  1. Domain ownership - You control the domain's DNS
  2. DNS provider configured - API credentials for automated validation
  3. 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:

  1. Creates ACME order with CA
  2. Receives DNS-01 challenge token
  3. Creates TXT record via DNS provider API
  4. Waits for DNS propagation (typically 30-60 seconds)
  5. Notifies CA that challenge is ready
  6. CA validates domain ownership

Step 2: Certificate Generation

Once validated:

  1. Generate private key (RSA 2048 or ECDSA P-256)
  2. Create Certificate Signing Request (CSR)
  3. Submit CSR to CA
  4. 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

  1. Navigate to CertificatesIssue New Certificate
  2. Enter domain details:
    • Primary domain: example.com
    • Additional SANs: www.example.com, api.example.com
  3. Select ACME account (Let's Encrypt or ZeroSSL)
  4. Select DNS provider (Cloudflare or Aliyun)
  5. Click Issue Certificate
  6. Monitor progress in real-time
  7. 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

  1. Test with Staging: Use Let's Encrypt staging for development
  2. Monitor Expiry: Set alerts for certificates expiring soon
  3. Backup Private Keys: Use MASTER_ONLY policy for critical certs
  4. Rotate Regularly: Even with auto-renewal, test rotation process
  5. 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

FeatureLet's EncryptZeroSSL
CostFreeFree + Paid
Rate Limits50/week/domainHigher limits
ValidationACME standardACME + alternatives
SupportCommunityCommercial available
Wildcard✅ Yes✅ Yes

Next Steps

Support