Skip to content

New tutorial: TLS with Cloudflare Origin Certificate on Hetzner Load Balancer using Pulumi#1427

Merged
svenja11 merged 5 commits into
hetzneronline:masterfrom
salemaljebaly:add-tutorial-cloudflare-origin-cert-pulumi-hetzner
Apr 2, 2026
Merged

New tutorial: TLS with Cloudflare Origin Certificate on Hetzner Load Balancer using Pulumi#1427
svenja11 merged 5 commits into
hetzneronline:masterfrom
salemaljebaly:add-tutorial-cloudflare-origin-cert-pulumi-hetzner

Conversation

@salemaljebaly
Copy link
Copy Markdown
Contributor

Description

This tutorial explains how to provision a Hetzner Load Balancer with TLS termination using a Cloudflare Origin Certificate — without relying on Hetzner managed certificates or Let's Encrypt.

It covers:

  • Generating a 15-year Cloudflare Origin Certificate in the Cloudflare dashboard
  • Uploading the certificate to Hetzner and configuring HTTPS termination at the Load Balancer
  • Provisioning a proxied Cloudflare DNS A record that hides the real Load Balancer IP
  • Configuring nginx on app servers to restore real visitor IPs via CF-Connecting-IP
  • A dynamic script that fetches Cloudflare IP ranges at boot and weekly via cron — no hardcoded ranges

This is the third tutorial in the Pulumi + Hetzner series, building on:

Note: The prerequisite tutorials are already published. The link to the TLS termination tutorial (the previous step) is currently under review in PR #1415.

Checklist

  • Written in English
  • Original content, not published elsewhere
  • All tools used are free and open source
  • Tested and validated on a real Hetzner Cloud project
  • Previewed in the Hetzner Markdown test suite
  • License block included at the bottom
  • No sensitive data in the tutorial

I have read and understood the Contributor's Certificate of Origin available at the end of
https://raw.githubusercontent.com/hetzneronline/community-content/master/tutorial-template.md
and I hereby certify that I meet the contribution criteria described in it.
Signed-off-by: Salem Aljebaly salemaljebaly@gmail.com

…r Load Balancer using Pulumi

New tutorial covering how to provision a Hetzner Load Balancer with TLS
termination using a Cloudflare Origin Certificate and a proxied DNS A record.
@svenja11
Copy link
Copy Markdown
Collaborator

Thank you for your contribution @salemaljebaly. I tested your tutorial and ran into some issues. In step 2 you say:

HCLOUD_TOKEN and CLOUDFLARE_API_TOKEN are picked up automatically by the Hetzner and Cloudflare providers from the environment — no pulumi config set needed for them.

However, in step 4, I get the following error:

holu@example-server:~/hetzner-cloudflare-lb-pulumi$ set -a && source .env && set +a
holu@example-server:~/hetzner-cloudflare-lb-pulumi$ pulumi preview
Previewing update (dev):
     Type                 Name                              Plan       Info
 +   pulumi:pulumi:Stack  hetzner-cloudflare-lb-pulumi-dev  create     1 error

Diagnostics:
  pulumi:pulumi:Stack (hetzner-cloudflare-lb-pulumi-dev):
    error: Missing required configuration variable 'hetzner-cloudflare-lb-pulumi:hcloudToken'
        please set a value using the command `pulumi config set --secret hetzner-cloudflare-lb-pulumi:hcloudToken <value>`

Resources:
    + 1 to create
    1 errored

I had to run this:

pulumi config set --secret hcloudToken "$HCLOUD_TOKEN"

Same for the other values in .env.

After everything was added, I got the following warning:

warning: Record is deprecated: cloudflare.index/record.Record has been deprecated in favor of cloudflare.index/dnsrecord.DnsRecord

This is the output of pulumi up:

Diagnostics:
  hcloud:index:UploadedCertificate (tls-cert):
    error:   sdk-v2/provider2.go:572: sdk.helper_schema: missing field [Certificate] in [hcloud.CertificateCreateOpts]: provider=hcloud@1.32.1
    error: 1 error occurred:
        * missing field [Certificate] in [hcloud.CertificateCreateOpts]

  pulumi:pulumi:Stack (hetzner-cloudflare-lb-pulumi-dev):
    warning: Record is deprecated: cloudflare.index/record.Record has been deprecated in favor of cloudflare.index/dnsrecord.DnsRecord
    error: update failed

@svenja11 svenja11 added the needs action Something has to be updated label Mar 31, 2026
@salemaljebaly
Copy link
Copy Markdown
Contributor Author

salemaljebaly commented Mar 31, 2026

Thank you for your contribution @salemaljebaly. I tested your tutorial and ran into some issues. In step 2 you say:

HCLOUD_TOKEN and CLOUDFLARE_API_TOKEN are picked up automatically by the Hetzner and Cloudflare providers from the environment — no pulumi config set needed for them.

However, in step 4, I get the following error:

holu@example-server:~/hetzner-cloudflare-lb-pulumi$ set -a && source .env && set +a
holu@example-server:~/hetzner-cloudflare-lb-pulumi$ pulumi preview
Previewing update (dev):
     Type                 Name                              Plan       Info
 +   pulumi:pulumi:Stack  hetzner-cloudflare-lb-pulumi-dev  create     1 error

Diagnostics:
  pulumi:pulumi:Stack (hetzner-cloudflare-lb-pulumi-dev):
    error: Missing required configuration variable 'hetzner-cloudflare-lb-pulumi:hcloudToken'
        please set a value using the command `pulumi config set --secret hetzner-cloudflare-lb-pulumi:hcloudToken <value>`

Resources:
    + 1 to create
    1 errored

I had to run this:

pulumi config set --secret hcloudToken "$HCLOUD_TOKEN"

Same for the other values in .env.

After everything was added, I got the following warning:

warning: Record is deprecated: cloudflare.index/record.Record has been deprecated in favor of cloudflare.index/dnsrecord.DnsRecord

This is the output of pulumi up:

Diagnostics:
  hcloud:index:UploadedCertificate (tls-cert):
    error:   sdk-v2/provider2.go:572: sdk.helper_schema: missing field [Certificate] in [hcloud.CertificateCreateOpts]: provider=hcloud@1.32.1
    error: 1 error occurred:
        * missing field [Certificate] in [hcloud.CertificateCreateOpts]

  pulumi:pulumi:Stack (hetzner-cloudflare-lb-pulumi-dev):
    warning: Record is deprecated: cloudflare.index/record.Record has been deprecated in favor of cloudflare.index/dnsrecord.DnsRecord
    error: update failed

Thank you @svenja11 for the detailed feedback! All issues are fixed:

  1. hcloudToken error — index.ts now reads DOMAIN, CLOUDFLARE_ZONE_ID, TLS_CERT, and TLS_PRIVATE_KEY directly via process.env. Providers auto-read HCLOUD_TOKEN and
    CLOUDFLARE_API_TOKEN from the environment — no pulumi config set needed.
  2. cloudflare.Record deprecated — updated to cloudflare.DnsRecord.
  3. missing field [Certificate] — the .env example and Step 1 now show that the PEM values must be wrapped in double quotes for multiline support:
  TLS_CERT="-----BEGIN CERTIFICATE-----                                                                                                                                                 
  ...                                                                      
  -----END CERTIFICATE-----"              

Re-validated from scratch with pulumi new typescript -y using only the tutorial code.

@svenja11
Copy link
Copy Markdown
Collaborator

svenja11 commented Apr 2, 2026

Thank you for updating the tutorial, I tested it again and it works now 🙂

@svenja11 svenja11 added ready and removed needs action Something has to be updated labels Apr 2, 2026
@svenja11 svenja11 merged commit bfacaa2 into hetzneronline:master Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants