Automated SSL certificate management for Proxmox Virtual Environment using Let's Encrypt and Cloudflare DNS validation.
By default, Proxmox uses a self-signed SSL certificate, which triggers browser security warnings and can't be verified. This guide eliminates those warnings by implementing trusted SSL certificates from Let's Encrypt that automatically renew.
Benefits:
- ✅ No more browser security warnings
- ✅ Trusted certificates from Let's Encrypt
- ✅ Automatic renewal every 60 days
- ✅ DNS validation (no need to expose port 80)
- ✅ Works behind firewalls and NAT
Use Cases:
- Home lab Proxmox servers accessed remotely
- Small business virtualization environments
- Development/testing infrastructure
- Any Proxmox installation requiring secure HTTPS access
This setup uses:
- Let's Encrypt for free, trusted SSL certificates
- Cloudflare DNS validation to prove domain ownership
- Built-in ACME client in Proxmox VE (version 6.1+)
- Automatic certificate renewal every 60 days
What you'll need:
- A computer to connect from (Windows, Mac, or Linux)
- Your Proxmox server's IP address
- Root password for Proxmox
- Open PowerShell or download PuTTY
- If using PowerShell, type:
Replace
ssh root@YOUR_PROXMOX_IPYOUR_PROXMOX_IPwith your actual Proxmox IP (e.g.,192.168.1.100) - When prompted "Are you sure you want to continue connecting?", type
yes - Enter your root password when prompted
- Open Terminal
- Type:
Replace
ssh root@YOUR_PROXMOX_IP
YOUR_PROXMOX_IPwith your actual Proxmox IP (e.g.,192.168.1.100) - When prompted "Are you sure you want to continue connecting?", type
yes - Enter your root password when prompted
How to find your Proxmox IP:
- Log into the Proxmox web interface
- Look at the URL bar - it's the part before
:8006 - Or click on your node name → System → Network
You're connected when you see:
root@pve:~#
Now that you're connected via SSH, copy and paste these commands:
# Download the validator script
wget https://raw.githubusercontent.com/leeroy4000/proxmox-ssl-setup/main/proxmox-ssl-validator.sh
# Make it executable
chmod +x proxmox-ssl-validator.sh
# Run pre-installation checks
./proxmox-ssl-validator.sh --pre-checkWhat these commands do:
wgetdownloads the script from GitHubchmod +xmakes the script executable (runnable)./proxmox-ssl-validator.sh --pre-checkruns the validation
The script will ask you for:
- Your Cloudflare API Token (from Step 1 below)
- Your Cloudflare Zone ID (from Step 2 below)
- Your domain name (e.g.,
example.com) - Your Proxmox subdomain (e.g.,
proxmox.example.com)
- Connect to Proxmox (via SSH - see "Getting Started" above)
- Run pre-checks to validate your setup is ready
- Get Cloudflare credentials (API token and Zone ID)
- Create DNS record for your Proxmox server
- Configure certificates in Proxmox web interface (GUI steps)
- Run post-checks to verify everything works
First time? See the "Getting Started" section above for detailed SSH instructions.
Already connected via SSH? Run:
./proxmox-ssl-validator.sh --pre-checkThis validates:
- Proxmox version compatibility
- Internet connectivity
- Cloudflare credentials (you'll need these from steps below)
- DNS configuration
- Port accessibility
You'll need these for the pre-check script and for Proxmox configuration.
See Steps 1-2 in the detailed setup below for how to get:
- Cloudflare API Token
- Cloudflare Zone ID
Complete Steps 1-7 in the "Manual Setup" section below (using the Proxmox web interface).
Connect to Proxmox via SSH again and run:
./proxmox-ssl-validator.sh --post-checkThis verifies:
- Certificate installation
- Certificate validity
- Auto-renewal configuration
- Web interface accessibility
- Proxmox VE 6.1 or newer
- Domain managed by Cloudflare
- Subdomain pointing to Proxmox (e.g.,
proxmox.yourdomain.com) - Cloudflare API Token with both Zone DNS Edit AND Zone Read permissions
- Cloudflare Zone ID for your domain
The following steps are performed in the Proxmox web interface (not SSH).
Access it by opening a browser and going to: https://YOUR_PROXMOX_IP:8006
CRITICAL: The API token must have BOTH permissions listed below. Missing either will cause certificate ordering to fail with "Authentication error" or "Error add txt for domain".
- Log into Cloudflare Dashboard
- Go to My Profile → API Tokens
- Click Create Token
- Use Edit zone DNS template
- Configure permissions:
- Permissions (
⚠️ BOTH are REQUIRED):- Zone → DNS → Edit ✅
- Zone → Zone → Read ✅
- Zone Resources: Include → Specific zone →
yourdomain.com
- Permissions (
- Click Continue to summary → Create Token
- Copy the API token (save it - you won't see it again!)
Already have a token? If you created a token before reading this and only have Zone → DNS → Edit permission, you can edit the existing token in Cloudflare to add Zone → Zone → Read. The token string doesn't change, so you don't need to update anything in Proxmox after editing permissions.
- In Cloudflare Dashboard, click on your domain
- Go to Overview page
- Scroll down on the right side
- Copy the Zone ID (looks like:
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6) - Save this - you'll need it for Proxmox
- In Cloudflare Dashboard → DNS
- Add new A record:
- Name:
proxmox(orpve,hypervisor, etc.) - IPv4 address: Your public IP address
- Proxy status: Orange cloud OFF ⚪ (gray cloud)
- TTL: Auto
- Name:
- Click Save
Result: proxmox.yourdomain.com
Important: Disable Cloudflare proxy (gray cloud) for Proxmox. The orange cloud (proxy enabled) will break the connection.
- Log into Proxmox web interface (
https://proxmox-ip:8006) - Click on Datacenter (top left in tree)
- Navigate to ACME section
- Click Add button under "Accounts"
- Configure account:
- Account Name:
letsencrypt-production - E-Mail: Your email address
- ACME Directory:
Let's Encrypt V2 - Accept TOS: ✅ Check the box
- Account Name:
- Click Register
- Should see success message
- Still in Datacenter → ACME
- Switch to Challenge Plugins tab
- Click Add
- Configure plugin:
- Plugin ID:
cloudflare - DNS API:
Cloudflare Managed DNS(ordns_cf) - API Data: Enter in this format:
CF_Token=your_cloudflare_api_token_here CF_Zone_ID=your_zone_id_here⚠️ Both are required! Replace with your actual token and Zone ID from Steps 1 & 2
- Plugin ID:
- Click Add
- In the tree, click on your Proxmox node (e.g.,
pve) - Go to System → Certificates
- Click Add button under "ACME"
- Configure domain:
- Challenge Type:
DNS - Plugin:
cloudflare(select from dropdown) - Domain:
proxmox.yourdomain.com(your full subdomain)
- Challenge Type:
- Click Add
- Still in System → Certificates view
- Click Order Certificates Now button at the top
- Wait 20-30 seconds for the process to complete
- Should see success message showing certificate details
- Web interface will automatically reload with new certificate
- Close browser completely (clear cache)
- Navigate to:
https://proxmox.yourdomain.com:8006 - Should see:
- ✅ Secure lock icon
- ✅ Valid certificate from Let's Encrypt
- ✅ No certificate warnings
- Click the lock icon to verify:
- Issued to: proxmox.yourdomain.com
- Issued by: Let's Encrypt (R10, R11, or similar)
- Valid until: ~90 days from issue date
Connect to Proxmox via SSH (see "Getting Started" section) and run:
./proxmox-ssl-validator.sh --post-checkThis will comprehensively test:
- Certificate installation
- Certificate validity
- Let's Encrypt issuer
- Domain name match
- Auto-renewal configuration
- HTTPS accessibility
The included proxmox-ssl-validator.sh script provides comprehensive validation:
- Verifies Proxmox version supports ACME
- Tests internet connectivity to Let's Encrypt
- Validates Cloudflare API credentials
- Checks DNS record configuration
- Verifies port 8006 accessibility
- Confirms certificate installation
- Verifies certificate validity via HTTPS
- Checks certificate issuer (Let's Encrypt)
- Validates domain name match
- Tests auto-renewal configuration
- Confirms web interface accessibility
# Before setup - check prerequisites
./proxmox-ssl-validator.sh --pre-check
# After certificate installation - verify everything works
./proxmox-ssl-validator.sh --post-check
# Run complete validation (both modes)
./proxmox-ssl-validator.sh --full
# Show help
./proxmox-ssl-validator.sh --help- Proxmox automatically renews certificates 30 days before expiry
- Renewal runs via cron job
- No manual intervention needed
If you need to renew manually:
- Go to Node → System → Certificates
- Click Order Certificates Now
- New certificate will be issued and applied
- Node → System → Certificates
- Shows current certificate and expiration date
Or use command line:
pvenode cert infoIf you have a Proxmox cluster with multiple nodes:
Each node gets its own subdomain and certificate:
pve1.yourdomain.com→ Node 1pve2.yourdomain.com→ Node 2pve3.yourdomain.com→ Node 3
Repeat Steps 3-7 for each node.
One certificate with multiple domains:
- When adding domains in Step 6, click Add multiple times
- Add each node's domain name
- All nodes can use the same certificate
Problem: API token is missing Zone → Zone → Read permission
Solution:
- Log into Cloudflare Dashboard → My Profile → API Tokens
- Find your token and click Edit
- Verify permissions include BOTH:
- Zone → DNS → Edit ✅
- Zone → Zone → Read ✅
- Save changes (token string stays the same - no need to update Proxmox)
- Try ordering certificate again
Test your token:
# This should return "success":true
curl -X GET "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"Problem: Missing Zone ID in Proxmox plugin configuration
Solution:
- Go to Datacenter → ACME → Challenge Plugins → Edit cloudflare plugin
- Verify API Data field contains both lines:
CF_Token=your_token CF_Zone_ID=your_zone_id - Both CF_Token AND CF_Zone_ID must be present
- Click OK to save
- Try ordering certificate again
Quick validation:
./proxmox-ssl-validator.sh --pre-checkThis will test your Cloudflare credentials before you configure Proxmox.
Problem: Browser cached old self-signed certificate
Solution:
- Close browser completely and reopen
- Hard refresh:
Ctrl + Shift + R(Windows/Linux) orCmd + Shift + R(Mac) - Try incognito/private window
- Try different browser
- Clear browser SSL state
Problem: DNS not resolving or firewall blocking
Solution:
- Can still access via IP:
https://PROXMOX_IP:8006(certificate warning is normal) - Check DNS resolves:
nslookup proxmox.yourdomain.com - Verify port 8006 is open (if accessing from outside network)
- Check pfSense firewall rules if accessing through VPN
Automated check:
./proxmox-ssl-validator.sh --post-checkProblem: Proxmox can't reach Let's Encrypt servers
Solution:
- Check Proxmox has internet access:
ping 8.8.8.8from shell - Check DNS resolution:
ping letsencrypt.org - Verify firewall allows outbound HTTPS (port 443)
- Check proxy settings if using one
Automated check:
./proxmox-ssl-validator.sh --pre-checkProblem: Token doesn't have required permissions
Solution:
- You can either edit your existing token OR create a new one in Cloudflare
- Required permissions (BOTH needed):
- Zone → DNS → Edit ✅
- Zone → Zone → Read ✅
- Scope to specific zone (your domain)
- If you edited an existing token, no need to update Proxmox (token string doesn't change)
- If you created a new token, update the Proxmox plugin with the new token
- ✅ Access Proxmox through VPN only (most secure)
⚠️ If exposing to internet, use strong passwords and 2FA- ✅ Limit access by IP in pfSense firewall rules
- ✅ Use non-standard port (change from 8006 to something else)
Only forward port 8006 if you need external access:
- Better: Use VPN and access over private network
- Alternative: Use reverse proxy (Caddy, nginx) on port 443
- ✅ Let's Encrypt certificates auto-renew (no expired certs!)
- ✅ Private keys stay on Proxmox server (never shared)
- ✅ Use DNS validation (no need to expose port 80)
- ✅ Use API tokens (not Global API Key)
- ✅ Scope tokens to specific zones only
- ✅ Use both required permissions (DNS Edit + Zone Read)
- ✅ Rotate tokens periodically
Instead of exposing Proxmox directly, use Caddy or nginx:
- Standard HTTPS port (443) instead of 8006
- Reverse proxy handles SSL automatically
- Can add authentication layer
- Single entry point for multiple services
proxmox.yourdomain.com {
reverse_proxy https://PROXMOX_INTERNAL_IP:8006 {
transport http {
tls_insecure_skip_verify
}
}
}
Then access via: https://proxmox.yourdomain.com (no port number!)
pvenode cert infopvenode acme account listpvenode acme cert renewls -la /etc/pve/nodes/$(hostname)/pveproxy-ssl.*curl -X GET "https://api.cloudflare.com/client/v4/zones?name=yourdomain.com" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"# Pre-installation checks
./proxmox-ssl-validator.sh --pre-check
# Post-installation verification
./proxmox-ssl-validator.sh --post-check┌─────────────────┐
│ Your Browser │
└────────┬────────┘
│ HTTPS (Port 8006)
│
▼
┌─────────────────┐ DNS Query ┌──────────────┐
│ Cloudflare │◄────────────────────►│ DNS Resolver │
│ DNS Server │ └──────────────┘
└────────┬────────┘
│ Resolves to Proxmox IP
│
▼
┌─────────────────────────────────────────┐
│ Proxmox VE Server │
│ ┌───────────────────────────────────┐ │
│ │ Built-in ACME Client │ │
│ │ • Requests cert from Let's Enc. │ │
│ │ • Uses Cloudflare DNS validation │ │
│ │ • Auto-renews every 60 days │ │
│ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ SSL Certificate (Let's Encrypt) │ │
│ │ • Trusted by all browsers │ │
│ │ • 90-day validity │ │
│ │ • Stored in /etc/pve/ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
▲
│ ACME Challenge
│
┌────────┴────────┐
│ Let's Encrypt │
│ CA Servers │
└─────────────────┘
This setup was developed for my home lab environment running Proxmox VE on multiple nodes. The goal was to eliminate browser security warnings while maintaining secure access via VPN and ensuring certificates automatically renew.
Environment:
- 3-node Proxmox cluster
- pfSense firewall with site-to-site VPN
- Cloudflare-managed domains
- Remote access via OpenVPN
The validation script was added to ensure reliable certificate deployment and to catch configuration issues early in the setup process.
README.md- This comprehensive setup guideproxmox-ssl-validator.sh- Automated validation script- Pre-installation checks
- Post-installation verification
- Certificate validation
- Auto-renewal testing
Issues and pull requests welcome! If you find bugs or have suggestions for improving the setup process or validation script, please open an issue.
MIT License - Feel free to use and modify for your own projects.
- Proxmox Wiki: https://pve.proxmox.com/wiki/Certificate_Management
- Let's Encrypt: https://letsencrypt.org/
- Cloudflare API Docs: https://developers.cloudflare.com/api/
- ACME Protocol: https://tools.ietf.org/html/rfc8555
✅ Proxmox now has valid SSL certificate from Let's Encrypt
✅ Auto-renewal every 60 days (30 days before expiry)
✅ DNS validation via Cloudflare (no ports to open)
✅ Secure access to Proxmox web interface
✅ Automated validation and verification