CertMate – SSL Certificate Management System

原始链接: https://github.com/fabriziosalmi/certmate

CertMate simplifies SSL certificate management across modern distributed architectures. It offers zero-downtime automation with certificates automatically renewing 30 days before expiry, and supports multi-cloud environments with 19 DNS providers including Cloudflare, AWS, and Azure. It is enterprise-ready with Docker, Kubernetes, and a REST API. Key features include Let's Encrypt integration for free certificates, wildcard and multi-domain support, and real-time SSL status checking. Its security-first approach includes bearer token authentication, file permissions, and audit logging. Integration is simplified through one-URL certificate downloads. Installation options include Docker, Python virtual environments, and system packages. Extensive documentation and API examples (Python, Bash, Ansible, Terraform) are available. Security best practices, performance optimization, and monitoring integration are also emphasized. Contributions and commercial use are welcomed under the MIT License.

Here's a summary of the Hacker News thread about "CertMate – SSL Certificate Management System": The discussion centers on the tool's utility and naming. Some users question the use of "SSL" in the name, arguing that TLS is the current standard. Others defend the naming choice, highlighting that "SSL" has better mindshare and recognition. Concerns were raised about CertMate's usefulness for large enterprises, with suggestions that configuration management systems offer better control and automation. Another point of contention involves the Docker and Docker Compose version requirements, potentially forcing users to upgrade their environments even if existing apps function on older versions. Finally, a user inquired about support for custom DNS servers not listed in CertMate's options, prompting a suggestion to use RFC2136 for dynamic DNS updates, though its implementation is left to the user. Overall, the comments range from practical concerns about compatibility and features to semantic debates about terminology.
相关文章

原文

CertMate solves the complexity of SSL certificate management in modern distributed architectures. Whether you're running a single application or managing certificates across multiple datacenters, CertMate provides:

  • 🔄 Zero-Downtime Automation - Certificates renew automatically 30 days before expiry
  • 🌐 Multi-Cloud Support - Works with 19 DNS providers (Cloudflare, AWS, Azure, GCP, Hetzner, Porkbun, GoDaddy, and more)
  • 🚀 Enterprise-Ready - Docker, Kubernetes, REST API, and monitoring built-in
  • 📦 Simple Integration - One-URL certificate downloads for easy automation
  • 🔒 Security-First - Bearer token authentication, secure file permissions, audit logging

🔐 Certificate Management

  • Let's Encrypt Integration - Free, automated SSL certificates
  • Wildcard Support - Single certificate for *.example.com and example.com
  • Multi-Domain Certificates - SAN certificates for multiple domains
  • Automatic Renewal - Smart renewal 30 days before expiry
  • Certificate Validation - Real-time SSL certificate status checking

🌐 Multi-DNS Provider Support

  • Cloudflare - Global CDN with edge locations worldwide
  • AWS Route53 - Amazon's scalable DNS service
  • Azure DNS - Microsoft's cloud DNS solution
  • Google Cloud DNS - Google's high-performance DNS
  • PowerDNS - Open-source DNS server with REST API
  • REST API - Complete programmatic control with Swagger/OpenAPI docs
  • Web Dashboard - Modern, responsive UI built with Tailwind CSS
  • Docker Ready - Full containerization with Docker Compose
  • Kubernetes Compatible - Deploy in any Kubernetes cluster
  • High Availability - Stateless design for horizontal scaling
  • Monitoring Integration - Health checks and structured logging

Security & Compliance

  • Bearer Token Authentication - Secure API access control
  • File Permissions - Proper certificate file security (600/700)
  • Audit Logging - Complete certificate lifecycle tracking
  • Environment Variables - Secure credential management
  • Rate Limit Handling - Let's Encrypt rate limit awareness
  • One-URL Downloads - Simple certificate retrieval for automation
  • Multiple Output Formats - PEM, ZIP, individual files
  • SDK Examples - Python, Bash, Ansible, Terraform examples
  • Webhook Support - Certificate renewal notifications
  • Extensive Documentation - API docs, guides, and examples

🌐 Supported DNS Providers

CertMate supports 19 DNS providers through Let's Encrypt DNS-01 challenge via individual certbot plugins that provide reliable, well-tested DNS challenge support:

Provider Credentials Required Use Case Status
🔶 Cloudflare API Token Global CDN, Free tier available Stable
🟠 AWS Route53 Access Key, Secret Key AWS infrastructure, Enterprise Stable
🔵 Azure DNS Service Principal credentials Microsoft ecosystem Stable
🟢 Google Cloud DNS Service Account JSON Google Cloud Platform Stable
⚫ PowerDNS API URL, API Key Self-hosted, On-premises Stable
🔷 DigitalOcean API Token Cloud infrastructure Stable
🟣 Linode API Key Cloud hosting Stable
🟡 Gandi API Token Domain registrar Stable
🔴 OVH API Credentials European hosting Stable
🟢 Namecheap Username, API Key Domain registrar Stable
🟦 Vultr API Key Global cloud infrastructure Stable
🔺 DNS Made Easy API Key, Secret Key Enterprise DNS management Stable
🟣 NS1 API Key Intelligent DNS platform Stable
🔷 RFC2136 Nameserver, TSIG Key/Secret Standard DNS update protocol Stable
🟠 Hetzner API Token European cloud hosting Stable
🟡 Porkbun API Key, Secret Key Domain registrar with DNS Stable
🟢 GoDaddy API Key, Secret Popular domain registrar Stable
🔵 Hurricane Electric Username, Password Free DNS hosting Stable
🔶 Dynu API Token Dynamic DNS service Stable
  • Cloud Providers: AWS Route53, Azure DNS, Google Cloud DNS, DigitalOcean, Linode, Vultr, Hetzner
  • Enterprise DNS: Cloudflare, DNS Made Easy, NS1, PowerDNS
  • Domain Registrars: Gandi, OVH, Namecheap, Porkbun, GoDaddy
  • European Providers: OVH, Gandi, Hetzner
  • Free Services: Hurricane Electric, Dynu
  • Standard Protocols: RFC2136 (for BIND and compatible servers)

📚 Detailed Setup Instructions: See DNS_PROVIDERS.md for provider-specific configuration.
🔧 Step-by-Step Installation: See INSTALLATION.md for complete setup guide.

🚀 Quick Start with Docker

Get CertMate running in under 5 minutes with Docker Compose:

  • Docker 20.10+
  • Docker Compose 2.0+
  • Domain with DNS managed by supported provider
# Clone the repository
git clone https://github.com/fabriziosalmi/certmate.git
cd certmate

# Copy environment template
cp .env.example .env

Edit .env file with your credentials:

# 🔒 Required: API Security
API_BEARER_TOKEN=your_super_secure_api_token_here_change_this

# 🌐 DNS Provider Configuration (choose one or multiple)

# Option 1: Cloudflare (Recommended for beginners)
CLOUDFLARE_TOKEN=your_cloudflare_api_token_here

# Option 2: AWS Route53
# AWS_ACCESS_KEY_ID=your_aws_access_key
# AWS_SECRET_ACCESS_KEY=your_aws_secret_key
# AWS_DEFAULT_REGION=us-east-1

# Option 3: Azure DNS
# AZURE_SUBSCRIPTION_ID=your_azure_subscription_id
# AZURE_RESOURCE_GROUP=your_resource_group
# AZURE_TENANT_ID=your_tenant_id
# AZURE_CLIENT_ID=your_client_id
# AZURE_CLIENT_SECRET=your_client_secret

# Option 4: Google Cloud DNS
# GOOGLE_PROJECT_ID=your_gcp_project_id
# GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json

# Option 5: PowerDNS
# POWERDNS_API_URL=https://your-powerdns-server:8081
# POWERDNS_API_KEY=your_powerdns_api_key

# ⚙️ Optional: Application Settings
SECRET_KEY=your_flask_secret_key_here
FLASK_ENV=production
HOST=0.0.0.0
PORT=8000
# Start all services
docker-compose up -d

# Check status
docker-compose ps

# View logs
docker-compose logs -f certmate

5. Create Your First Certificate

Using the Web Interface:

  1. Navigate to http://localhost:8000
  2. Go to Settings and configure your DNS provider
  3. Add your domain (e.g. example.com)
  4. Click "Create Certificate"

Using the API:

curl -X POST "http://localhost:8000/api/certificates/create" \
  -H "Authorization: Bearer your_api_token_here" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com"}'

📋 Installation Methods

Choose the installation method that best fits your environment:

🐳 Docker (Recommended)

Perfect for production deployments with isolation and easy scaling. Supports multiple architectures: AMD64 (Intel/AMD), ARM64 (Apple Silicon, ARM servers), and ARM v7 (Raspberry Pi).

# Quick start with Docker Compose
git clone https://github.com/fabriziosalmi/certmate.git
cd certmate
cp .env.example .env
# Edit .env with your configuration
docker-compose up -d

Multi-Platform Support:

# Build for multiple architectures (ARM64 + AMD64)
./build-multiplatform.sh

# Build and push to Docker Hub for all platforms
./build-multiplatform.sh -r YOUR_DOCKERHUB_USERNAME -p

# Use pre-built multi-platform image
docker run --platform linux/arm64 -d --name certmate --env-file .env -p 8000:8000 USERNAME/certmate:latest

📚 Multi-Platform Guide: See DOCKER_MULTIPLATFORM.md for comprehensive multi-architecture setup instructions.

🐍 Python Virtual Environment

Ideal for development and testing environments.

# Create and activate virtual environment
python3 -m venv certmate-env
source certmate-env/bin/activate  # On Windows: certmate-env\Scripts\activate

# Install dependencies
git clone https://github.com/fabriziosalmi/certmate.git
cd certmate
pip install -r requirements.txt

# Set environment variables
export API_BEARER_TOKEN="your_token_here"
export CLOUDFLARE_TOKEN="your_cloudflare_token"

# Run the application
python app.py

For container orchestration and high availability deployments.

# Example Kubernetes deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: certmate
spec:
  replicas: 2
  selector:
    matchLabels:
      app: certmate
  template:
    metadata:
      labels:
        app: certmate
    spec:
      containers:
      - name: certmate
        image: certmate:latest
        ports:
        - containerPort: 8000
        env:
        - name: API_BEARER_TOKEN
          valueFrom:
            secretKeyRef:
              name: certmate-secrets
              key: api-token
        volumeMounts:
        - name: certificates
          mountPath: /app/certificates
      volumes:
      - name: certificates
        persistentVolumeClaim:
          claimName: certmate-certificates

📦 System Package Installation

For system-wide installation on Linux distributions.

# Install system dependencies (Ubuntu/Debian)
sudo apt update
sudo apt install python3 python3-pip python3-venv certbot openssl

# Clone and install
git clone https://github.com/fabriziosalmi/certmate.git
sudo mv certmate /opt/
cd /opt/certmate
sudo pip3 install -r requirements.txt

# Create systemd service (see Service Setup section below for detailed instructions)
sudo cp certmate.service /etc/systemd/system/
sudo systemctl enable certmate
sudo systemctl start certmate

📖 Detailed Instructions: See INSTALLATION.md for complete setup guides for each method.

For production deployments, CertMate should run as a system service. This section provides comprehensive instructions for setting up CertMate with systemd on Linux distributions.

  • Linux system with systemd
  • Python 3.9 or higher
  • Root/sudo access

1. Create Dedicated System User

Create a dedicated user for running CertMate:

# Create system user and group
sudo useradd --system --shell /bin/false --home-dir /opt/certmate --create-home certmate

# Set proper ownership
sudo chown -R certmate:certmate /opt/certmate

2. Prepare Application Directory

Set up the application in /opt/certmate:

# If not already done, clone the repository
git clone https://github.com/fabriziosalmi/certmate.git
sudo mv certmate /opt/
cd /opt/certmate

# Create Python virtual environment
sudo -u certmate python3 -m venv venv
sudo -u certmate ./venv/bin/pip install -r requirements.txt

# Create necessary directories
sudo -u certmate mkdir -p certificates data

3. Configure Environment Variables

Create environment file for the service:

# Create environment file
sudo tee /opt/certmate/.env > /dev/null <<EOF
# 🔒 SECURITY: Change this token!
API_BEARER_TOKEN=your_super_secure_api_token_here_change_this

# Optional: Set specific host/port
HOST=127.0.0.1
PORT=8000

# Optional: Enable debug mode (not recommended for production)
FLASK_DEBUG=false
EOF

# Set proper permissions
sudo chown certmate:certmate /opt/certmate/.env
sudo chmod 600 /opt/certmate/.env

4. Install systemd Service

Install and configure the systemd service:

# Copy service file
sudo cp /opt/certmate/certmate.service /etc/systemd/system/

# Reload systemd configuration
sudo systemctl daemon-reload

# Enable service to start on boot
sudo systemctl enable certmate

# Start the service
sudo systemctl start certmate

Check that the service is running correctly:

# Check service status
sudo systemctl status certmate

# View recent logs
sudo journalctl -u certmate --lines=50

# Follow logs in real-time
sudo journalctl -u certmate -f

6. Service Management Commands

Common commands for managing the CertMate service:

# Start service
sudo systemctl start certmate

# Stop service
sudo systemctl stop certmate

# Restart service
sudo systemctl restart certmate

# Reload service configuration
sudo systemctl reload certmate

# Check if service is enabled
sudo systemctl is-enabled certmate

# Check if service is active
sudo systemctl is-active certmate

# Disable service from starting on boot
sudo systemctl disable certmate

Ensure proper file permissions for security:

# Set ownership
sudo chown -R certmate:certmate /opt/certmate

# Set directory permissions
sudo chmod 755 /opt/certmate
sudo chmod 750 /opt/certmate/certificates /opt/certmate/data

# Set file permissions
sudo chmod 644 /opt/certmate/*.py /opt/certmate/*.md
sudo chmod 600 /opt/certmate/.env
sudo chmod 755 /opt/certmate/venv/bin/*
  • API Bearer Token: Always change the default API bearer token in /opt/certmate/.env
  • File Permissions: The service runs with restricted permissions and limited filesystem access
  • Network Access: The service binds to 0.0.0.0:8000 by default - consider using a reverse proxy for production
  • Environment File: The .env file contains sensitive data and should be readable only by the certmate user
  • Certificates: Generated certificates are stored in /opt/certmate/certificates with restricted access

🔍 Troubleshooting Service Setup

If the service fails to start:

  1. Check service status: sudo systemctl status certmate
  2. View logs: sudo journalctl -u certmate --lines=100
  3. Verify permissions: Ensure the certmate user can read all necessary files
  4. Test manually: sudo -u certmate /opt/certmate/venv/bin/python /opt/certmate/app.py
  5. Check dependencies: sudo -u certmate /opt/certmate/venv/bin/python validate_dependencies.py

For more detailed installation instructions, see INSTALLATION.md.

CertMate provides a comprehensive REST API for programmatic certificate management. All endpoints require Bearer token authentication.

Include the Authorization header in all API requests:

Authorization: Bearer your_api_token_here
# Health check
GET /health

# API documentation
GET /docs/          # Swagger UI
GET /redoc/         # ReDoc documentation
# Get current settings
GET /api/settings
Authorization: Bearer your_token_here

# Update settings
POST /api/settings
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "dns_provider": "cloudflare",
  "dns_providers": {
    "cloudflare": {
      "api_token": "your_cloudflare_token"
    }
  },
  "domains": [
    {
      "domain": "example.com",
      "dns_provider": "cloudflare"
    }
  ],
  "email": "[email protected]",
  "auto_renew": true
}
# List all certificates
GET /api/certificates
Authorization: Bearer your_token_here

# Create new certificate
POST /api/certificates/create
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "domain": "example.com",
  "dns_provider": "cloudflare"  # Optional, uses default from settings
}

# Renew certificate
POST /api/certificates/example.com/renew
Authorization: Bearer your_token_here

# Download certificate (ZIP format)
GET /api/certificates/example.com/download
Authorization: Bearer your_token_here

# Check certificate deployment status
GET /api/certificates/example.com/deployment-status
Authorization: Bearer your_token_here

🎯 Automation-Friendly Download URL

The most powerful feature for infrastructure automation:

# Download certificates via simple URL pattern
GET /{domain}/tls
Authorization: Bearer your_token_here

This endpoint returns a ZIP file containing all certificate files:

  • cert.pem - Server certificate
  • chain.pem - Intermediate certificate chain
  • fullchain.pem - Full certificate chain (cert + chain)
  • privkey.pem - Private key

💼 Integration Examples

curl -H "Authorization: Bearer your_token_here" \
     -o example.com-tls.zip \
     https://your-certmate-server.com/example.com/tls
import requests
import zipfile
from pathlib import Path

class CertMateClient:
    def __init__(self, base_url, token):
        self.base_url = base_url.rstrip('/')
        self.headers = {"Authorization": f"Bearer {token}"}
    
    def download_certificate(self, domain, extract_to=None):
        """Download and optionally extract certificate for domain"""
        url = f"{self.base_url}/{domain}/tls"
        
        response = requests.get(url, headers=self.headers)
        response.raise_for_status()
        
        zip_path = f"{domain}-tls.zip"
        with open(zip_path, 'wb') as f:
            f.write(response.content)
        
        if extract_to:
            Path(extract_to).mkdir(parents=True, exist_ok=True)
            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
                zip_ref.extractall(extract_to)
        
        return zip_path
    
    def list_certificates(self):
        """List all managed certificates"""
        response = requests.get(f"{self.base_url}/api/certificates", 
                              headers=self.headers)
        response.raise_for_status()
        return response.json()
    
    def create_certificate(self, domain, dns_provider=None):
        """Create new certificate for domain"""
        data = {"domain": domain}
        if dns_provider:
            data["dns_provider"] = dns_provider
            
        response = requests.post(f"{self.base_url}/api/certificates/create",
                               json=data, headers=self.headers)
        response.raise_for_status()
        return response.json()
    
    def renew_certificate(self, domain):
        """Renew existing certificate"""
        response = requests.post(f"{self.base_url}/api/certificates/{domain}/renew",
                               headers=self.headers)
        response.raise_for_status()
        return response.json()

# Usage example
client = CertMateClient("https://certmate.company.com", "your_token_here")

# Download certificate
client.download_certificate("api.company.com", extract_to="/etc/ssl/certs/api/")

# List all certificates
certs = client.list_certificates()
for cert in certs:
    print(f"Domain: {cert['domain']}, Expires: {cert['expiry_date']}")

Infrastructure as Code Examples

Terraform Provider Example:

# Configure the CertMate provider
terraform {
  required_providers {
    certmate = {
      source = "local/certmate"
      version = "~> 1.0"
    }
  }
}

provider "certmate" {
  endpoint = "https://certmate.company.com"
  token    = var.certmate_token
}

# Create certificates for multiple domains
resource "certmate_certificate" "api" {
  domain       = "api.company.com"
  dns_provider = "cloudflare"
}

resource "certmate_certificate" "web" {
  domain       = "web.company.com" 
  dns_provider = "route53"
}

# Download certificates to local files
data "certmate_certificate_download" "api" {
  domain = certmate_certificate.api.domain
}

# Use in nginx configuration
resource "kubernetes_secret" "api_tls" {
  metadata {
    name      = "api-tls"
    namespace = "default"
  }
  
  type = "kubernetes.io/tls"
  
  data = {
    "tls.crt" = data.certmate_certificate_download.api.fullchain_pem
    "tls.key" = data.certmate_certificate_download.api.private_key_pem
  }
}

Bash Automation Script:

#!/bin/bash
set -euo pipefail

# Configuration
CERTMATE_URL="https://certmate.company.com"
API_TOKEN="${CERTMATE_TOKEN}"
DOMAIN="${1:-example.com}"
CERT_DIR="/etc/ssl/certs/${DOMAIN}"
BACKUP_DIR="/backup/certs/${DOMAIN}/$(date +%Y%m%d_%H%M%S)"

# Functions
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}

create_backup() {
    if [[ -d "$CERT_DIR" ]]; then
        log "Creating backup of existing certificates"
        mkdir -p "$BACKUP_DIR"
        cp -r "$CERT_DIR"/* "$BACKUP_DIR/" || true
    fi
}

download_certificate() {
    log "Downloading certificate for ${DOMAIN}"
    
    # Download with retry logic
    for i in {1..3}; do
        if curl -f -H "Authorization: Bearer $API_TOKEN" \
                -o "${DOMAIN}-tls.zip" \
                "$CERTMATE_URL/$DOMAIN/tls"; then
            log "Certificate downloaded successfully"
            return 0
        else
            log "Download attempt $i failed, retrying..."
            sleep 5
        fi
    done
    
    log "Failed to download certificate after 3 attempts"
    return 1
}

extract_certificate() {
    log "Extracting certificate to ${CERT_DIR}"
    mkdir -p "$CERT_DIR"
    unzip -o "${DOMAIN}-tls.zip" -d "$CERT_DIR"
    
    # Set proper permissions
    chmod 600 "$CERT_DIR"/*.pem
    chown root:ssl-cert "$CERT_DIR"/*.pem
}

reload_services() {
    log "Reloading web services"
    systemctl reload nginx || log "Failed to reload nginx"
    systemctl reload apache2 || log "Failed to reload apache2"
    systemctl reload haproxy || log "Failed to reload haproxy"
}

cleanup() {
    rm -f "${DOMAIN}-tls.zip"
}

# Main execution
main() {
    log "Starting certificate update for ${DOMAIN}"
    
    create_backup
    download_certificate
    extract_certificate
    reload_services
    cleanup
    
    log "Certificate update completed for ${DOMAIN}"
}

# Trap cleanup on exit
trap cleanup EXIT

# Run main function
main "$@"

Advanced Ansible Playbook:

---
- name: Manage SSL certificates with CertMate
  hosts: web_servers
  become: yes
  vars:
    certmate_url: "https://certmate.company.com"
    api_token: "{{ vault_certmate_token }}"
    certificate_domains:
      - name: "api.company.com"
        dns_provider: "cloudflare"
        nginx_sites: ["api"]
        services_to_reload: ["nginx"]
      - name: "web.company.com"
        dns_provider: "route53"
        nginx_sites: ["web", "admin"]
        services_to_reload: ["nginx", "haproxy"]
  
  tasks:
    - name: Create certificate directories
      file:
        path: "/etc/ssl/certs/{{ item.name }}"
        state: directory
        owner: root
        group: ssl-cert
        mode: '0750'
      loop: "{{ certificate_domains }}"
      
    - name: Check certificate expiry
      uri:
        url: "{{ certmate_url }}/api/certificates/{{ item.name }}/deployment-status"
        method: GET
        headers:
          Authorization: "Bearer {{ api_token }}"
      register: cert_status
      loop: "{{ certificate_domains }}"
      
    - name: Create new certificates if needed
      uri:
        url: "{{ certmate_url }}/api/certificates/create"
        method: POST
        headers:
          Authorization: "Bearer {{ api_token }}"
          Content-Type: "application/json"
        body_format: json
        body:
          domain: "{{ item.name }}"
          dns_provider: "{{ item.dns_provider }}"
      loop: "{{ certificate_domains }}"
      when: cert_status.results[ansible_loop.index0].json.needs_renewal | default(false)
      
    - name: Download certificates
      uri:
        url: "{{ certmate_url }}/{{ item.name }}/tls"
        method: GET
        headers:
          Authorization: "Bearer {{ api_token }}"
        dest: "/tmp/{{ item.name }}-tls.zip"
        creates: "/tmp/{{ item.name }}-tls.zip"
      loop: "{{ certificate_domains }}"
      
    - name: Extract certificates
      unarchive:
        src: "/tmp/{{ item.name }}-tls.zip"
        dest: "/etc/ssl/certs/{{ item.name }}/"
        owner: root
        group: ssl-cert
        mode: '0640'
        remote_src: yes
      loop: "{{ certificate_domains }}"
      notify: 
        - reload nginx
        - reload haproxy
        - restart services
      
    - name: Verify certificate installation
      openssl_certificate:
        path: "/etc/ssl/certs/{{ item.name }}/fullchain.pem"
        provider: assertonly
        has_expired: no
        valid_in: 86400  # Valid for at least 1 day
      loop: "{{ certificate_domains }}"
      
    - name: Update nginx SSL configuration
      template:
        src: "nginx-ssl.conf.j2"
        dest: "/etc/nginx/sites-available/{{ item.1 }}"
        backup: yes
      loop: "{{ certificate_domains | subelements('nginx_sites') }}"
      notify: reload nginx
      
    - name: Cleanup temporary files
      file:
        path: "/tmp/{{ item.name }}-tls.zip"
        state: absent
      loop: "{{ certificate_domains }}"
  
  handlers:
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded
        
    - name: reload haproxy
      systemd:
        name: haproxy
        state: reloaded
        
    - name: restart services
      systemd:
        name: "{{ item }}"
        state: restarted
      loop: "{{ services_to_restart | default([]) }}"

⚙️ Configuration Guide

🔧 Environment Variables

Variable Required Default Description
API_BEARER_TOKEN - Bearer token for API authentication
SECRET_KEY auto-generated Flask secret key for sessions
HOST 127.0.0.1 Server bind address
PORT 8000 Server port
FLASK_ENV production Flask environment
FLASK_DEBUG false Enable debug mode

🌐 DNS Provider Configuration

  1. Go to Cloudflare API Tokens
  2. Click "Create Token" → "Custom token"
  3. Set permissions:
    • Zone: DNS:Edit + Zone:Read
    • Zone Resources: Include specific zones or all zones
  4. Copy the generated token
# Environment variable
CLOUDFLARE_TOKEN=your_cloudflare_api_token_here
  1. Create IAM user with Route53 permissions
  2. Attach policy: Route53FullAccess or custom policy:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange",
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": "*"
        }
    ]
}
# Environment variables
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_DEFAULT_REGION=us-east-1
  1. Create Service Principal:
az ad sp create-for-rbac --name "CertMate" --role "DNS Zone Contributor" --scopes "/subscriptions/{subscription-id}/resourceGroups/{resource-group}"
# Environment variables
AZURE_SUBSCRIPTION_ID=your_subscription_id
AZURE_RESOURCE_GROUP=your_resource_group_name
AZURE_TENANT_ID=your_tenant_id
AZURE_CLIENT_ID=your_client_id
AZURE_CLIENT_SECRET=your_client_secret
  1. Create service account with DNS Administrator role
  2. Download JSON key file
# Environment variables
GOOGLE_PROJECT_ID=your_project_id
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
# Environment variables
POWERDNS_API_URL=https://your-powerdns-server:8081
POWERDNS_API_KEY=your_api_key
certmate/
├── 📄 app.py                    # Main Flask application
├── 📄 requirements.txt          # Python dependencies
├── 📄 docker-compose.yml        # Docker Compose configuration
├── 📄 Dockerfile               # Container build instructions
├── 📄 nginx.conf               # Nginx reverse proxy config
├── 📄 .env.example             # Environment template
├── 📚 README.md                # This documentation
├── 📚 INSTALLATION.md          # Detailed installation guide
├── 📚 DNS_PROVIDERS.md         # DNS provider configuration
├── 📚 CONTRIBUTING.md          # Contribution guidelines
├── 📁 certificates/            # Certificate storage
│   └── 📁 {domain}/
│       ├── 🔐 cert.pem         # Server certificate
│       ├── 🔐 chain.pem        # Certificate chain
│       ├── 🔐 fullchain.pem    # Full chain
│       └── 🔐 privkey.pem      # Private key
├── 📁 data/                    # Application data
│   └── ⚙️ settings.json        # Persistent settings
├── 📁 logs/                    # Application logs
├── 📁 letsencrypt/             # Let's Encrypt working directory
│   ├── 📁 config/              # Certbot configuration
│   ├── 📁 work/                # Certbot working files
│   └── 📁 logs/                # Certbot logs
└── 📁 templates/               # Web interface templates
    ├── 🌐 index.html           # Main dashboard
    └── ⚙️ settings.html        # Settings page

🔒 Security & Best Practices

🛡️ Security Considerations

Authentication & Authorization

  • Strong Bearer Tokens: Use cryptographically secure tokens (32+ characters)
  • Token Rotation: Regularly rotate API tokens
  • Environment Variables: Never commit tokens to version control
  • HTTPS Only: Always use HTTPS in production environments
  • IP Restrictions: Implement firewall rules to restrict access
  • File Permissions: Private keys stored with 600 permissions
  • Directory Permissions: Certificate directories with 700 permissions
  • Backup Encryption: Encrypt certificate backups
  • Access Logging: Monitor certificate access patterns
# Example firewall rules (iptables)
# Allow only specific IPs to access CertMate
iptables -A INPUT -p tcp --dport 8000 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -j DROP

⚡ Performance Optimization

# docker-compose.prod.yml
version: '3.8'
services:
  certmate:
    image: certmate:latest
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
    environment:
      - FLASK_ENV=production
      - GUNICORN_WORKERS=4
      - GUNICORN_THREADS=2
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

Load Balancing with Nginx

upstream certmate_backend {
    server certmate1:8000;
    server certmate2:8000;
    server certmate3:8000;
}

server {
    listen 443 ssl http2;
    server_name certmate.company.com;
    
    ssl_certificate /etc/ssl/certs/certmate.company.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/certs/certmate.company.com/privkey.pem;
    
    location / {
        proxy_pass http://certmate_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # API rate limiting
        limit_req zone=api burst=10 nodelay;
    }
}
#!/bin/bash
# /opt/scripts/backup-certmate.sh

BACKUP_DIR="/backup/certmate/$(date +%Y%m%d_%H%M%S)"
CERT_DIR="/opt/certmate/certificates"
DATA_DIR="/opt/certmate/data"
RETENTION_DAYS=30

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Backup certificates
tar -czf "$BACKUP_DIR/certificates.tar.gz" "$CERT_DIR"

# Backup application data
tar -czf "$BACKUP_DIR/data.tar.gz" "$DATA_DIR"

# Backup database if using external DB
# mysqldump certmate > "$BACKUP_DIR/database.sql"

# Encrypt backups
gpg --cipher-algo AES256 --compress-algo 1 --symmetric \
    --output "$BACKUP_DIR/certificates.tar.gz.gpg" \
    "$BACKUP_DIR/certificates.tar.gz"

# Cleanup old backups
find /backup/certmate -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;

echo "Backup completed: $BACKUP_DIR"
#!/bin/bash
# Recovery from backup

BACKUP_DATE="20241225_120000"
BACKUP_DIR="/backup/certmate/$BACKUP_DATE"

# Stop services
docker-compose down

# Restore certificates
gpg --decrypt "$BACKUP_DIR/certificates.tar.gz.gpg" | \
    tar -xzf - -C /opt/certmate/

# Restore data
tar -xzf "$BACKUP_DIR/data.tar.gz" -C /opt/certmate/

# Set permissions
chown -R 1000:1000 /opt/certmate/certificates
chmod -R 700 /opt/certmate/certificates

# Start services
docker-compose up -d

echo "Recovery completed from backup: $BACKUP_DATE"

📊 Monitoring & Observability

# Basic health check
curl -f http://localhost:8000/health

# Detailed health with auth
curl -H "Authorization: Bearer your_token" \
     http://localhost:8000/api/certificates

Prometheus Metrics Integration

# Add to app.py for Prometheus monitoring
from prometheus_client import Counter, Histogram, generate_latest

# Metrics
certificate_requests = Counter('certmate_certificate_requests_total', 
                              'Total certificate requests', ['domain', 'status'])
certificate_expiry = Histogram('certmate_certificate_expiry_days',
                              'Days until certificate expiry', ['domain'])

@app.route('/metrics')
def metrics():
    return generate_latest()
# docker-compose.logging.yml
version: '3.8'
services:
  certmate:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: certmate
        fluentd-async-connect: "true"
        
  fluentd:
    image: fluent/fluentd:v1.14
    volumes:
      - ./fluentd/conf:/fluentd/etc
      - ./logs:/var/log/fluentd
    ports:
      - "24224:24224"
      - "24224:24224/udp"

📈 Grafana Dashboard Example

{
  "dashboard": {
    "title": "CertMate SSL Certificate Monitoring",
    "panels": [
      {
        "title": "Certificate Expiry Status",
        "targets": [
          {
            "expr": "certmate_certificate_expiry_days < 30",
            "legendFormat": "Expiring Soon ({{domain}})"
          }
        ],
        "alert": {
          "conditions": [
            {
              "query": {"queryType": "", "refId": "A"},
              "reducer": {"type": "last", "params": []},
              "evaluator": {"params": [30], "type": "lt"}
            }
          ],
          "executionErrorState": "alerting",
          "frequency": "1h",
          "handler": 1,
          "name": "Certificate Expiring",
          "noDataState": "no_data",
          "notifications": []
        }
      }
    ]
  }
}

🚨 Alerting Configuration

# Add webhook notification support
import requests

def send_webhook_notification(domain, event_type, details):
    webhook_url = os.getenv('WEBHOOK_URL')
    if not webhook_url:
        return
        
    payload = {
        'domain': domain,
        'event': event_type,
        'timestamp': datetime.now().isoformat(),
        'details': details
    }
    
    try:
        requests.post(webhook_url, json=payload, timeout=10)
    except Exception as e:
        logger.error(f"Failed to send webhook: {e}")

Slack Integration Example

# Slack notification script
#!/bin/bash
SLACK_WEBHOOK="your_slack_webhook_url"
DOMAIN="$1"
STATUS="$2"
MESSAGE="Certificate for $DOMAIN: $STATUS"

curl -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"🔐 $MESSAGE\"}" \
    "$SLACK_WEBHOOK"

🔧 Troubleshooting Guide

🚨 Common Issues & Solutions

Certificate Creation Failures

Issue: DNS validation failed

# Check DNS propagation
dig TXT _acme-challenge.example.com @8.8.8.8

# Verify DNS provider credentials
curl -H "Authorization: Bearer cf_token" \
     "https://api.cloudflare.com/client/v4/user/tokens/verify"

Issue: Rate limit exceeded

# Let's Encrypt rate limits:
# - 50 certificates per registered domain per week
# - 5 duplicate certificates per week
# - 300 new orders per account per 3 hours

# Check rate limit status
curl "https://crt.sh/?q=example.com&output=json" | jq length

Issue: Permission denied accessing certificate files

# Fix file permissions
sudo chown -R certmate:certmate /opt/certmate/certificates
sudo chmod -R 700 /opt/certmate/certificates
sudo chmod 600 /opt/certmate/certificates/*/privkey.pem

API Authentication Issues

Issue: 401 Unauthorized

# Verify token format
curl -H "Authorization: Bearer your_token_here" \
     http://localhost:8000/api/certificates

# Check token in settings
docker exec certmate cat /app/data/settings.json | jq .api_bearer_token

Issue: Token not found

# Reset API token
docker exec -it certmate python -c "
import json
with open('/app/data/settings.json', 'r+') as f:
    data = json.load(f)
    data['api_bearer_token'] = 'new_secure_token_here'
    f.seek(0)
    json.dump(data, f, indent=2)
    f.truncate()
"

Docker & Container Issues

Issue: Container won't start

# Check logs
docker-compose logs certmate

# Verify environment variables
docker-compose config

# Check port conflicts
netstat -tulpn | grep :8000

Issue: Volume mount issues

# Fix volume permissions
sudo chown -R 1000:1000 ./certificates ./data ./logs

# Check volume mounts
docker inspect certmate | jq '.[0].Mounts'

DNS Provider Specific Issues

Cloudflare:

# Verify API token permissions
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
     -H "Authorization: Bearer your_token_here"

# Check zone access
curl -X GET "https://api.cloudflare.com/client/v4/zones" \
     -H "Authorization: Bearer your_token_here"

AWS Route53:

# Test AWS credentials
aws sts get-caller-identity

# Check Route53 permissions
aws route53 list-hosted-zones

Azure DNS:

# Verify service principal
az login --service-principal \
    -u $AZURE_CLIENT_ID \
    -p $AZURE_CLIENT_SECRET \
    --tenant $AZURE_TENANT_ID

# Check DNS zone access
az network dns zone list

Enable debug logging for troubleshooting:

# Environment variable
FLASK_DEBUG=true
FLASK_ENV=development

# Or in Docker Compose
docker-compose -f docker-compose.yml -f docker-compose.debug.yml up

Before seeking help, please provide:

# Collect system information
echo "=== CertMate Debug Info ==="
echo "Version: $(docker exec certmate python -c 'import app; print(getattr(app, "__version__", "unknown"))')"
echo "Python: $(docker exec certmate python --version)"
echo "OS: $(docker exec certmate cat /etc/os-release | head -2)"
echo "Certbot: $(docker exec certmate certbot --version)"
echo "DNS Plugins: $(docker exec certmate pip list | grep certbot-dns)"
echo "Certificates: $(docker exec certmate ls -la /app/certificates)"
echo "Settings: $(docker exec certmate cat /app/data/settings.json | jq .)"

📚 Complete Documentation Set

Check out our examples repository for:

  • Production deployment configurations
  • Integration scripts for popular tools
  • Terraform modules
  • Kubernetes manifests
  • CI/CD pipeline examples

🚀 Roadmap & Future Features

  • 🔄 Certificate Templates - Predefined certificate configurations
  • 📊 Advanced Analytics - Certificate usage and performance metrics
  • 🔐 ACME v2 Features - External account binding, certificate transparency
  • 🌍 Multi-Region Support - Geographic certificate distribution
  • 📱 Mobile App - iOS/Android certificate monitoring
  • 🤖 AI-Powered Renewal - Intelligent renewal scheduling
  • 🔌 Plugin System - Custom DNS provider plugins
  • 📈 Enterprise Dashboard - Multi-tenant certificate management
Version Release Date Key Features
v2.0.0 2024-12-25 Multi-DNS provider support, enhanced API
v1.5.0 2024-11-15 Docker improvements, monitoring features
v1.0.0 2024-10-01 Initial release with Cloudflare support

🤝 Community Contributions

We welcome contributions! Areas where we need help:

  • Documentation - Tutorials, use cases, translations
  • Testing - DNS provider testing, edge cases
  • Integrations - New DNS providers, monitoring tools
  • Features - UI improvements, API enhancements

We love contributions! CertMate is an open-source project and we welcome:

🛠️ Types of Contributions

  • 🐛 Bug Reports - Help us identify and fix issues
  • 💡 Feature Requests - Suggest new functionality
  • 📖 Documentation - Improve guides and examples
  • 🧪 Testing - Test new features and edge cases
  • 💻 Code - Submit pull requests with improvements

🚀 Quick Start for Contributors

# Fork and clone the repository
git clone https://github.com/fabriziosalmi/certmate.git
cd certmate

# Create development environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -r requirements-dev.txt

# Set up pre-commit hooks
pre-commit install

# Run tests
pytest

# Start development server
python app.py

📋 Contribution Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Thanks to all contributors who make CertMate better!

Contributors

This project is licensed under the MIT License - see the LICENSE file for details.

  • Commercial Use - Use in commercial projects
  • Modification - Modify and distribute changes
  • Distribution - Distribute the software
  • Private Use - Use privately
  • Liability - No warranty or liability
  • Patent Grant - No patent rights granted

联系我们 contact @ memedata.com