# Proxmox ACME Certificate Setup with Cloudflare DNS-01

## Overview

This guide provides step-by-step instructions for configuring Let's Encrypt certificates on Proxmox nodes using Cloudflare DNS-01 validation. This setup enables automatic certificate issuance and renewal without exposing Proxmox to the internet.

## Prerequisites

### Domain Requirements

- Domain must be managed by Cloudflare DNS
- Domain must be active in Cloudflare account
- DNS records for Proxmox nodes must exist (or will be created automatically)

**Current Setup:**
- **Domain**: `sankofa.nexus`
- **Proxmox Nodes**: 
  - `ml110-01.sankofa.nexus` (192.168.11.10) - Admin functions
  - `r630-01.sankofa.nexus` (192.168.11.11) - VMs and heavy lifting

### Proxmox Requirements

- Proxmox VE 6.0+ (ACME plugin included)
- Administrative access to Proxmox web UI
- Network connectivity from Proxmox to Cloudflare API (outbound HTTPS)

### Cloudflare Requirements

- Cloudflare account with DNS management access
- Ability to create API tokens

## Step 1: Create Cloudflare API Token

### Purpose

The API token allows Proxmox ACME plugin to create and delete DNS TXT records for domain validation.

### Instructions

1. **Log in to Cloudflare Dashboard**
   - Go to [https://dash.cloudflare.com](https://dash.cloudflare.com)
   - Select your account

2. **Navigate to API Tokens**
   - Click your profile icon (top right)
   - Select **"My Profile"**
   - Click **"API Tokens"** in the left sidebar
   - Click **"Create Token"**

3. **Configure Token Permissions**

   **Option A: Use Template (Recommended)**
   - Scroll to **"Edit zone DNS"** template
   - Click **"Use template"**
   - Continue to Zone Resources

   **Option B: Custom Token**
   - Click **"Create Custom Token"**
   - **Token Name**: `proxmox-acme-dns01` (or descriptive name)
   - **Permissions**: 
     - Resource: `Zone`
     - Permission: `DNS`
     - Permission Level: `Edit`
   - Click **"Continue to summary"**

4. **Configure Zone Resources**
   - **Include**: Select **"Specific zone"**
   - **Zone**: Select `sankofa.nexus`
   - **DNS**: `Edit` (should be pre-selected)
   - Review permissions summary

5. **Create Token**
   - Click **"Continue to summary"**
   - Review configuration
   - Click **"Create Token"**
   - **CRITICAL**: Copy the token immediately (shown only once)
   - Store securely (password manager recommended)

### Security Best Practices

- **Scope**: Token scoped to `sankofa.nexus` zone only (not "All zones")
- **Permissions**: DNS Edit only (minimal required permissions)
- **Naming**: Use descriptive token name for easy identification
- **Rotation**: Rotate token periodically (recommended: every 90 days)
- **Storage**: Never commit token to version control
- **Access**: Limit who has access to the token

### Token Format

The token will look like:
```
abcdef1234567890abcdef1234567890abcdef12
```

## Step 2: Configure ACME Account in Proxmox

### On ml110-01 (Admin Node)

1. **Access Proxmox Web UI**
   - Navigate to `https://ml110-01.sankofa.nexus:8006`
   - Log in with administrative credentials

2. **Navigate to ACME Accounts**
   - Click **"Datacenter"** in the left sidebar
   - Expand **"ACME"** section
   - Click **"Accounts"**

3. **Add ACME Account**
   - Click **"Add"** button
   - **Directory**: Select **"Let's Encrypt"** (production)
   - **Email**: Enter your administrative email address
     - Used for certificate expiration notifications
     - Example: `admin@sankofa.nexus`
   - **Name**: `letsencrypt-prod`
   - Click **"Register"**

4. **Verify Account Creation**
   - Account should appear in the list
   - Status should show as active/registered

## Step 3: Configure Cloudflare DNS Plugin

1. **Navigate to ACME DNS Plugins**
   - In **"Datacenter"** → **"ACME"** section
   - Click **"DNS Plugin"**

2. **Add DNS Plugin**
   - Click **"Add"** button
   - **ID**: `cloudflare-dns` (or descriptive identifier)
   - **Plugin**: Select **"cloudflare"** from dropdown
   - **API Token**: Paste the Cloudflare API token from Step 1
   - **Domain**: `sankofa.nexus`
   - Click **"Create"**

3. **Verify Plugin Configuration**
   - Plugin should appear in the list
   - Status should be valid

### Troubleshooting Plugin Configuration

**Error: "Invalid API token"**
- Verify token was copied correctly (no extra spaces)
- Ensure token has DNS Edit permissions for `sankofa.nexus` zone
- Check token hasn't been deleted or rotated in Cloudflare

**Error: "Zone not found"**
- Verify domain spelling matches exactly
- Ensure domain is in your Cloudflare account
- Check you have DNS management access to the zone

## Step 4: Order Certificates

### Wildcard Certificate (Recommended)

1. **Navigate to ACME Certificates**
   - In **"Datacenter"** → **"ACME"** section
   - Click **"Certificates"**

2. **Order Wildcard Certificate**
   - Click **"Order Certificate"**
   - **ACME Account**: Select `letsencrypt-prod`
   - **DNS Plugin**: Select `cloudflare-dns`
   - **Domain**: `*.sankofa.nexus`
   - **Name**: `wildcard-sankofa-nexus` (optional, for identification)
   - Click **"Order"**

3. **Monitor Certificate Order**
   - Certificate status will show as "Ordering..."
   - Proxmox will automatically:
     - Create DNS TXT record via Cloudflare API
     - Wait for DNS propagation
     - Validate domain ownership
     - Download certificate
   - Process typically takes 1-2 minutes

4. **Verify Certificate**
   - Status should change to "Valid" or "Active"
   - Certificate should show expiration date (~90 days from now)
   - Click certificate to view details (SANs, issuer, etc.)

### Single-Host Certificates (Optional)

While the wildcard certificate covers all subdomains, you may want specific certificates for clarity or compliance.

#### Certificate for ml110-01

1. **Order Certificate**
   - Click **"Order Certificate"**
   - **ACME Account**: `letsencrypt-prod`
   - **DNS Plugin**: `cloudflare-dns`
   - **Domain**: `ml110-01.sankofa.nexus`
   - **Name**: `ml110-01-sankofa-nexus`
   - Click **"Order"**

2. **Wait for Validation**
   - Same process as wildcard certificate
   - Status should become "Valid"

#### Certificate for r630-01

1. **Order Certificate**
   - Click **"Order Certificate"**
   - **ACME Account**: `letsencrypt-prod`
   - **DNS Plugin**: `cloudflare-dns`
   - **Domain**: `r630-01.sankofa.nexus`
   - **Name**: `r630-01-sankofa-nexus`
   - Click **"Order"**

2. **Wait for Validation**
   - Status should become "Valid"

## Step 5: Apply Certificates to Nodes

### Apply Wildcard Certificate to All Nodes

1. **Navigate to Certificates**
   - Click **"Datacenter"** in left sidebar
   - Click **"Certificates"** (not under ACME section)

2. **Select Certificate**
   - Find `wildcard-sankofa-nexus` in the list
   - Click on the certificate name

3. **Edit Certificate Assignment**
   - Click **"Edit"** button
   - Check boxes for both nodes:
     - `ml110-01` (Admin node)
     - `r630-01` (VM node)
   - Click **"OK"**

4. **Verify Application**
   - Certificate should show as assigned to both nodes
   - Nodes will automatically use the certificate for HTTPS

### Apply Single-Host Certificates (if created)

Single-host certificates are automatically used by the matching node when present.

To verify:
- Check certificate details show correct hostname
- Certificate should automatically appear on the matching node

## Step 6: Verify Certificate Installation

### Method 1: Proxmox Web UI

1. **Check Certificate Status**
   - **Datacenter** → **Certificates**
   - Verify certificates show as "Valid"
   - Check expiration dates (should be ~90 days)

2. **Test HTTPS Connection**
   - Access Proxmox web UI via HTTPS
   - Browser should show valid certificate (green lock icon)
   - Certificate should show as issued by "Let's Encrypt"
   - Click lock icon to view certificate details

### Method 2: Command Line (from Proxmox node)

```bash
# Check certificate on ml110-01
openssl s_client -connect ml110-01.sankofa.nexus:8006 -servername ml110-01.sankofa.nexus < /dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer

# Check certificate on r630-01
openssl s_client -connect r630-01.sankofa.nexus:8006 -servername r630-01.sankofa.nexus < /dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
```

Expected output:
- **Issuer**: Should show "Let's Encrypt"
- **Subject**: Should include node hostname
- **Valid From/To**: Should show current date and ~90 days future

### Method 3: Using Verification Script

Run the provided verification script:

```bash
./scripts/verify-proxmox-certs.sh
```

This script will:
- Check certificate validity on both nodes
- Verify expiration dates
- Test SSL connections
- Report certificate status

## Step 7: Update Cloudflare Tunnel Configurations

After certificates are installed, update tunnel configurations to remove `skipVerify: true`.

### Files to Update

- `cloudflare/tunnel-configs/proxmox-site-1.yaml` (ml110-01)
- `cloudflare/tunnel-configs/proxmox-site-2.yaml` (r630-01)
- `cloudflare/tunnel-configs/proxmox-site-3.yaml` (if applicable)

### Changes Required

**Before:**
```yaml
originRequest:
  tls:
    skipVerify: true
```

**After:**
```yaml
originRequest:
  tls:
    skipVerify: false
```

Or simply remove the `tls` section entirely (defaults to `skipVerify: false`).

### Apply Changes

1. Update configuration files
2. Copy updated configs to Proxmox nodes
3. Restart cloudflared tunnel service:
   ```bash
   systemctl restart cloudflared-tunnel
   ```
4. Verify tunnel connectivity:
   ```bash
   systemctl status cloudflared-tunnel
   ```

## Auto-Renewal

### How It Works

Proxmox ACME plugin automatically renews certificates before expiration:
- Renewal typically occurs 30 days before expiration
- Process is automatic (no manual intervention)
- Renewal uses same DNS-01 validation process
- No downtime required

### Verification

1. **Check Auto-Renewal Status**
   - **Datacenter** → **ACME** → **Certificates**
   - Certificates should show auto-renewal enabled
   - Check renewal date (should be ~30 days before expiration)

2. **Monitor Renewal**
   - Proxmox logs renewal attempts
   - Check logs if renewal fails:
     ```bash
     journalctl -u pvedaemon -f | grep -i acme
     ```

3. **Email Notifications**
   - Let's Encrypt sends expiration warnings to account email
   - Proxmox may also send notifications on renewal failure

## Troubleshooting

### Certificate Order Fails

**Symptom**: Certificate status shows "Failed" or "Error"

**Possible Causes**:
1. **Invalid API Token**
   - Verify token in DNS Plugin configuration
   - Test token in Cloudflare API directly
   - Create new token if necessary

2. **DNS Propagation Delay**
   - Wait 5-10 minutes and retry
   - Check DNS TXT records manually:
     ```bash
     dig _acme-challenge.sankofa.nexus TXT
     ```

3. **Rate Limiting**
   - Let's Encrypt has rate limits (50 certs/week/domain)
   - Wait and retry later
   - Use staging environment for testing

4. **Network Connectivity**
   - Verify Proxmox can reach Cloudflare API (outbound HTTPS)
   - Check firewall rules
   - Test connectivity:
     ```bash
     curl -I https://api.cloudflare.com
     ```

**Solution**: Check Proxmox logs:
```bash
journalctl -u pvedaemon | grep -i acme | tail -50
```

### Certificate Not Applied to Node

**Symptom**: Node still uses self-signed certificate

**Possible Causes**:
1. Certificate not assigned to node
2. Node needs restart (rare)
3. Certificate format issue

**Solution**:
1. Check certificate assignment in **Datacenter** → **Certificates**
2. Verify certificate is valid and not expired
3. Restart pveproxy service if needed:
   ```bash
   systemctl restart pveproxy
   ```

### DNS TXT Records Not Created

**Symptom**: Certificate validation fails, TXT records missing

**Possible Causes**:
1. API token lacks permissions
2. Token expired or deleted
3. Cloudflare API error

**Solution**:
1. Verify API token in DNS Plugin configuration
2. Test token manually:
   ```bash
   curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
     -H "Authorization: Bearer YOUR_TOKEN"
   ```
3. Check Cloudflare API status page

### Auto-Renewal Fails

**Symptom**: Certificate expires, not renewed automatically

**Possible Causes**:
1. API token expired or rotated
2. Network connectivity issues
3. Let's Encrypt rate limiting
4. DNS plugin configuration changed

**Solution**:
1. Check renewal logs:
   ```bash
   journalctl -u pvedaemon | grep -i "acme\|renewal" | tail -100
   ```
2. Verify API token is still valid
3. Manually trigger renewal:
   - Go to **Datacenter** → **ACME** → **Certificates**
   - Select certificate
   - Click **"Renew"** (if available)

### Certificate Shows as Invalid in Browser

**Symptom**: Browser shows certificate error despite valid certificate

**Possible Causes**:
1. Browser cache issue
2. Certificate chain incomplete
3. Wrong certificate applied

**Solution**:
1. Clear browser cache and cookies
2. Try incognito/private browsing mode
3. Verify certificate via command line (see Step 6)
4. Check certificate chain is complete

## Certificate Management

### View Certificate Details

**In Proxmox Web UI**:
- **Datacenter** → **Certificates**
- Click certificate name to view details:
  - Subject Alternative Names (SANs)
  - Issuer
  - Valid from/to dates
  - Serial number
  - Public key fingerprint

**Via Command Line**:
```bash
# View certificate file
cat /etc/pve/nodes/ml110-01/pveproxy-ssl.pem

# Parse certificate details
openssl x509 -in /etc/pve/nodes/ml110-01/pveproxy-ssl.pem -text -noout
```

### Revoke Certificate

If a certificate is compromised or no longer needed:

1. **Via Proxmox Web UI**:
   - **Datacenter** → **ACME** → **Certificates**
   - Select certificate
   - Click **"Revoke"**
   - Confirm revocation

2. **Note**: Revoked certificates cannot be reused
   - Order new certificate if needed
   - Let's Encrypt tracks revoked certificates

### Delete Certificate

To remove a certificate from Proxmox:

1. **Remove from Nodes**:
   - **Datacenter** → **Certificates**
   - Select certificate
   - Click **"Edit"**
   - Uncheck all nodes
   - Click **"OK"**

2. **Delete Certificate**:
   - **Datacenter** → **ACME** → **Certificates**
   - Select certificate
   - Click **"Delete"**
   - Confirm deletion

## Token Rotation

### When to Rotate

- Every 90 days (recommended)
- After security incident
- If token is compromised
- As part of security policy

### Rotation Procedure

1. **Create New Token**
   - Follow Step 1 to create new Cloudflare API token
   - Use same permissions and zone scope

2. **Update DNS Plugin**
   - **Datacenter** → **ACME** → **DNS Plugin**
   - Select `cloudflare-dns` plugin
   - Click **"Edit"**
   - Replace **API Token** with new token
   - Click **"OK"**

3. **Verify Certificates Still Work**
   - Check certificate status
   - Test HTTPS connections
   - Monitor for 24-48 hours

4. **Revoke Old Token**
   - Go to Cloudflare Dashboard
   - **My Profile** → **API Tokens**
   - Find old token
   - Click **"Revoke"**
   - Confirm revocation

### Testing New Token

Before rotating, test new token works:

```bash
# Test token can read DNS records
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer NEW_TOKEN" \
  -H "Content-Type: application/json"

# Test token can create DNS records (careful!)
# This creates a test record - delete it after testing
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer NEW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"TXT","name":"_acme-test.sankofa.nexus","content":"test","ttl":120}'
```

## Security Considerations

### API Token Security

- **Never commit tokens to version control**
- **Store tokens in password manager**
- **Use separate tokens for different purposes**
- **Rotate tokens regularly**
- **Monitor token usage in Cloudflare**

### Certificate Security

- **Let's Encrypt certificates are public** (anyone can view them)
- **Private keys are stored securely on Proxmox**
- **Automatic renewal prevents expiration**
- **Monitor certificate expiration dates**

### Network Security

- **Proxmox nodes should be behind firewall**
- **Only allow necessary outbound connections**
- **Monitor Cloudflare API access**
- **Use VPN or private network when possible**

### Access Control

- **Limit who can modify ACME configuration**
- **Audit certificate changes**
- **Review certificate assignments regularly**
- **Monitor for unauthorized certificate issuance**

## Compliance

### Certificate Requirements

- **Valid certificates required for compliance (SOC 2, ISO 27001)**
- **Automatic renewal ensures continuous validity**
- **Certificate audit trail in Proxmox logs**
- **Let's Encrypt certificates meet industry standards**

### Monitoring and Auditing

- **Log all certificate operations**
- **Monitor certificate expiration**
- **Audit API token usage**
- **Review certificate assignments quarterly**

## Related Documentation

- [TLS Configuration Guide](./TLS_CONFIGURATION.md) - General TLS/SSL configuration
- [DNS Configuration](./DNS_CONFIGURATION.md) - DNS setup for Proxmox
- [Cloudflare Domain Setup](./CLOUDFLARE_DOMAIN_SETUP.md) - Cloudflare integration
- [Cloudflare Tunnel Configs](../cloudflare/tunnel-configs/) - Tunnel configuration files

## Verification Checklist

After completing setup, verify:

- [ ] Cloudflare API token created and stored securely
- [ ] ACME account registered in Proxmox
- [ ] Cloudflare DNS plugin configured
- [ ] Wildcard certificate ordered and valid
- [ ] Single-host certificates ordered (if applicable)
- [ ] Certificates applied to both nodes
- [ ] HTTPS connections show valid certificates
- [ ] Auto-renewal configured and verified
- [ ] Tunnel configurations updated (skipVerify removed)
- [ ] Verification script passes
- [ ] Email notifications configured

## Support

### Proxmox Resources

- [Proxmox ACME Documentation](https://pve.proxmox.com/pve-docs/chapter-pve-certificate-management.html)
- [Proxmox Forum](https://forum.proxmox.com/)

### Let's Encrypt Resources

- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)
- [Let's Encrypt Community](https://community.letsencrypt.org/)

### Cloudflare Resources

- [Cloudflare API Documentation](https://developers.cloudflare.com/api/)
- [Cloudflare DNS API](https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-list-dns-records)

## Last Updated

- **Date**: 2024-12-19
- **Status**: Complete
- **Next Review**: 2025-03-19

