The easiest way is using Terraform.
Here is a parameterized Terraform script for doing it:
terraform {
required_providers {
acme = {
source = "vancluever/acme"
version = "~>2.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~>4.0"
}
}
}
provider "acme" {
server_url = "https://acme-v02-staging.api.letsencrypt.org/directory" # This is the staging address, you don't get real certs from here. Remove 'staging' from the URL for production certificates
}
provider "cloudflare" {
api_token = var.cloudflare_token
}
resource "tls_private_key" "private_key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "acme_registration" "reg" {
account_key_pem = tls_private_key.private_key.private_key_pem
email_address = var.registration_email
}
resource "acme_certificate" "certificate" {
account_key_pem = acme_registration.reg.account_key_pem
common_name = var.domain
subject_alternative_names = [var.fqdn]
dns_challenge {
provider = "cloudflare"
config = {
CF_DNS_API_TOKEN = var.cloudflare_token
}
}
}
resource "local_file" "public_cert" {
filename = "path/to/site/fullchain.pem"
content = "${acme_certificate.certificate.certificate_pem}${acme_certificate.certificate.issuer_pem}"
}
resource "local_sensitive_file" "private_key" {
filename = "path/to/site/privkey.pem"
content = acme_certificate.certificate.private_key_pem
}
variable "cloudflare_token" {
type = string
description = "Cloudflare token"
}
variable "domain" {
type = string
description = "The domain name for the certificates (ex. example.com)"
variable "fqdn" {
type = string
description = "The Fully Qualified Domain Name (ex. subdomain.example.com)"
}
variable "registration_email" {
type = string
description = "The registration email for Let's Encrypt so they can send renewal notifications"
}
Note: The Cloudflare token needs DNS:edit privs.
And there you go! Free trusted TLS certs!