Repository navigation
PVE 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.
- A Domain name. Commands here use the
SHOWCASE_BASE_DOMAINenvironment variable. - An Email address to use for the account {
cloud@${SHOWCASE_BASE_DOMAIN}}. - An AWS account.
- The
awscliapplication installed.- A profile configured with permissions to create IAM Policies and IAM Users {
codger}.
- A profile configured with permissions to create IAM Policies and IAM Users {
- 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.
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.
AWS_DNS_NAME="${SHOWCASE_BASE_DOMAIN}"
AWS_PROFILE="codger"
AWS_USER="certbot-route53"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:::#')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}'"
}
]
}'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}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.jsonStore 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_keyCreate 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}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_keyRemove the Access key file.
ssh gadget1 rm aws_dns_access_keyCreate 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_sitessh gadget2 pvenode config set --acmedomain0 domain=gadget2.lab.${SHOWCASE_BASE_DOMAIN},plugin=Route53_sitessh gadget3 pvenode config set --acmedomain0 domain=gadget3.lab.${SHOWCASE_BASE_DOMAIN},plugin=Route53_siteOrder the new certificate on each PVE node.
ssh gadget1 pvenode acme cert orderssh gadget2 pvenode acme cert orderssh gadget3 pvenode acme cert order