Skip to content

PVE Certificates

Cloud Codger edited this page Sep 4, 2026 · 1 revision

Configure Proxmox for Let's Encrypt Certificates

This page explains how to configure the PVE Certificate Management to use the ACME Let's Encrypt endpoint using the validation of dns-01 challenges with the AWS Route53 DNS plugin.

Steps to configure the Proxmox hosts for HTTPS certificates that get created using Let's Encrypt and automatically renewed using the Route53 plugin.

Prerequisites

  • A Domain name. Commands here use the SHOWCASE_BASE_DOMAIN environment variable.
  • An Email address to use for the account {cloud@${SHOWCASE_BASE_DOMAIN}}.
  • An AWS account.
  • The awscli application installed.
    • A profile configured with permissions to create IAM Policies and IAM Users {codger}.
  • A Registered Domain Name with AWS Route 53 {${SHOWCASE_BASE_DOMAIN}}.

Note

Values inside {}s above are those used below. Replace them everywhere below with the values used for your configuration.

AWS Setup

These steps can be done in the AWS web interface if the account has not been configured with an access key and secret key with appropriate rights. This only needs to be done once and if the PVE cluster was destroyed and re-built, the same AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY created for Route53 updates can be used to configure certificates on the re-built cluster. Don't confuse these keys with those used for the steps here, which are assumed to have much greater access rights.

Variables

AWS_DNS_NAME="${SHOWCASE_BASE_DOMAIN}"
AWS_PROFILE="codger"
AWS_USER="certbot-route53"

AWS zone ARN

Get the ARN for the zone (replace the dns name and profile values).

AWS_R53_ARN=$(aws route53 list-hosted-zones-by-name \
  --dns-name "${AWS_DNS_NAME}" --profile "${AWS_PROFILE}" \
  --query "HostedZones[0].Id" --output text | sed 's#^/#arn:aws:route53:::#')

AWS Policy

Create an IAM Policy for Let's Encrypt.

aws iam create-policy \
    --policy-name certbot-dns-route53 \
    --description "Allows Route53 operations for Certbot" \
    --profile ${AWS_PROFILE} \
    --policy-document '{
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "VisualEditor0",
          "Effect": "Allow",
          "Action": [
            "route53:GetChange",
            "route53:ListHostedZones",
            "route53:ListResourceRecordSets"
          ],
          "Resource": "*"
        },
        {
          "Sid": "VisualEditor1",
          "Effect": "Allow",
          "Action": "route53:ChangeResourceRecordSets",
          "Resource": "'${AWS_R53_ARN}'"
        }
      ]
    }'

AWS User

Create an AWS IAM user with the above role.

aws iam create-user --profile "${AWS_PROFILE}" --user-name "${AWS_USER}"

Get the IAM Policy ARN.

AWS_POLICY_ARN=$(aws iam list-policies --profile "${AWS_PROFILE}" 
  --query "Policies[?PolicyName=='certbot-dns-route53'].Arn" --output text)

Attach the IAM Policy to the user.

aws iam attach-user-policy --profile "${AWS_PROFILE}" --user-name "${AWS_USER}" --policy-arn ${AWS_POLICY_ARN}

AWS User API Keys

Create an API access key for the user that can be used with Let's Encrypt Certbot.

aws iam create-access-key --profile "${AWS_PROFILE}" --user-name "${AWS_USER}" > ~/.secrets/aws_dns_access_key.json

Store the Access Key and Secret Key in a file usable by the pvenode acme command.

sed -En 's/.*AccessKeyId.: .([^"]+).,/AWS_ACCESS_KEY_ID=\1/p; s/.*SecretAccessKey.: .([^"]+).,/AWS_SECRET_ACCESS_KEY=\1/p' ~/.secrets/aws_dns_access_key.json > ~/.secrets/aws_dns_access_key

Create ACME account

Create a default ACME account on one of the PVE nodes. For example, gadget1. This creates it for the Datacenter in the PVE cluster.

ssh gadget1 "pvesh create /cluster/acme/account --contact cloud@${SHOWCASE_BASE_DOMAIN} --tos_url https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf"

or (requires answering prompts)

ssh gadget1 pvenode acme account register default cloud@${SHOWCASE_BASE_DOMAIN}

Create ACME DNS Plugin

This creates it for the Datacenter in the PVE cluster.

Copy up the Access key file.

scp ~/.secrets/aws_dns_access_key gadget1:

Create the plugin. The name Route53_site can be changed, but must then also be changed in the pvenode config set commands below.

ssh gadget1 pvenode acme plugin add dns Route53_site -api aws -data aws_dns_access_key

Remove the Access key file.

ssh gadget1 rm aws_dns_access_key

ACME Certificates

Create an ACME domain on each PVE node. Change gadget1.lab.${SHOWCASE_BASE_DOMAIN} to your FQDN for the PVE node.

ssh gadget1 pvenode config set --acmedomain0 domain=gadget1.lab.${SHOWCASE_BASE_DOMAIN},plugin=Route53_site
ssh gadget2 pvenode config set --acmedomain0 domain=gadget2.lab.${SHOWCASE_BASE_DOMAIN},plugin=Route53_site
ssh gadget3 pvenode config set --acmedomain0 domain=gadget3.lab.${SHOWCASE_BASE_DOMAIN},plugin=Route53_site

Order the new certificate on each PVE node.

ssh gadget1 pvenode acme cert order
ssh gadget2 pvenode acme cert order
ssh gadget3 pvenode acme cert order

Clone this wiki locally