cf-ips-to-hcloud-fw
Update Hetzner Cloud firewall rules with current Cloudflare IP ranges
100K+
This tool, cf-ips-to-hcloud-fw, helps you keep your Hetzner Cloud firewall
rules up-to-date with the current Cloudflare IP ranges.
cf-ips-to-hcloud-fw fetches the current Cloudflare IP
ranges and updates your Hetzner Cloud firewall
rules using the hcloud
API.
The tool specifically targets incoming firewall rules and replaces the
networks with Cloudflare networks if their description contains
__CLOUDFLARE_IPS_V4__, __CLOUDFLARE_IPS_V6__ or __CLOUDFLARE_IPS__.
| Text in rule description | Cloudflare IP ranges |
|---|---|
__CLOUDFLARE_IPS_V4__ | IPv4 only |
__CLOUDFLARE_IPS_V6__ | IPv6 only |
__CLOUDFLARE_IPS__ | IPv4 + IPv6 |
Note: Having both __CLOUDFLARE_IPS_V4__ and __CLOUDFLARE_IPS_V6__ in a rule
description is equivalent to having __CLOUDFLARE_IPS__ there.
To install cf-ips-to-hcloud-fw using Python, we recommend using
pipx or uvx.
Both are tools for installing and running Python applications in isolated
environments. If you already have uv installed, uvx is the quickest option.
pipx (Recommended for Most Users)Install cf-ips-to-hcloud-fw using pipx:
pipx install cf-ips-to-hcloud-fw
Verify the installation:
cf-ips-to-hcloud-fw -h
You should see the usage information for cf-ips-to-hcloud-fw.
To upgrade cf-ips-to-hcloud-fw, run:
Tip
To upgrade `cf-ips-to-hcloud-fw`, run `pipx upgrade cf-ips-to-hcloud-fw`.
uvx (Recommended for uv Users)If you have uv installed, you can run cf-ips-to-hcloud-fw directly without
installing it:
uvx cf-ips-to-hcloud-fw -c config.yaml
This approach automatically downloads and runs the latest version in an isolated environment without modifying your system Python.
Tip
`uvx` always fetches and runs the latest version, so no upgrade command is needed.
pipWe strongly recommend using a virtual environment when installing Python
packages with pip. This helps to avoid conflicts between packages and allows you
to manage packages on a per-project basis.
Create a virtual environment:
python3 -m venv cf-ips-to-hcloud-fw-venv
Install cf-ips-to-hcloud-fw into the virtual environment:
./cf-ips-to-hcloud-fw-venv/bin/pip3 install cf-ips-to-hcloud-fw
Verify the installation:
./cf-ips-to-hcloud-fw-venv/bin/cf-ips-to-hcloud-fw -h
You should see the usage information for cf-ips-to-hcloud-fw.
Tip
To upgrade `cf-ips-to-hcloud-fw` in your virtual environment, run `./cf-ips-to-hcloud-fw-venv/bin/pip3 install --upgrade cf-ips-to-hcloud-fw`.
As an alternative, cf-ips-to-hcloud-fw can be run using Docker or a Kubernetes
CronJob. Simply mount your configuration file as /usr/src/app/config.yaml.
Here's an example using Docker:
docker run --rm \
--mount type=bind,source=$(pwd)/config.yaml,target=/usr/src/app/config.yaml,readonly \
jkreileder/cf-ips-to-hcloud-fw:1.3.0
(Add --pull=always if you use a rolling image tag.)
Alternatively, for a single project you can skip the mounted file and pass the
token and firewalls as environment variables (see Using Environment
Variables). The image auto-detects
a mounted config.yaml and otherwise falls back to these variables, so no
command override is needed:
docker run --rm \
-e HCLOUD_TOKEN=your-api-token \
-e HCLOUD_FIREWALLS=$'firewall-1\nfirewall-2' \
jkreileder/cf-ips-to-hcloud-fw:1.3.0
Docker images for cf-ips-to-hcloud-fw are available for both linux/amd64 and
linux/arm64 architectures. The Docker images support the following tags:
1: This tag always points to the latest 1.x.x release.1.3: This tag always points to the latest 1.3.x release.1.3.0: This tag points to the specific 1.3.0 release.main: This tag points to the most recent development version of
cf-ips-to-hcloud-fw. Use this at your own risk as it may contain unstable
changes.You can find the Docker images at:
jkreileder/cf-ips-to-hcloud-fw or docker.io/jkreileder/cf-ips-to-hcloud-fwquay.io/jkreileder/cf-ips-to-hcloud-fwghcr.io/jkreileder/cf-ips-to-hcloud-fwHere's an example of how to create a Kubernetes Secret for your configuration:
apiVersion: v1
kind: Secret
metadata:
name: cf-ips-to-hcloud-fw-config
type: Opaque
stringData:
config.yaml: |
- token: API_TOKEN_FOR_PROJECT_1
firewalls:
- firewall-1
- firewall-2
- token: API_TOKEN_FOR_PROJECT_2
firewalls:
- default
And here's an example of a Kubernetes CronJob that uses the Secret:
apiVersion: batch/v1
kind: CronJob
metadata:
name: cf-ips-to-hcloud-fw
spec:
schedule: "0 * * * *" # Run every hour
jobTemplate:
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534
containers:
- name: cf-ips-to-hcloud-fw
image: jkreileder/cf-ips-to-hcloud-fw:1.3.0
# imagePullPolicy: Always # Uncomment this if you use a rolling image tag
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: config-volume
mountPath: /usr/src/app/config.yaml
subPath: config.yaml
volumes:
- name: config-volume
secret:
secretName: cf-ips-to-hcloud-fw-config
restartPolicy: OnFailure
For a single project, you can drop the Secret, volume, and volumeMounts above
and instead supply the token and firewalls via env (for example from a
Secret). No command override is needed — with no config.yaml mounted, the tool
falls back to these variables:
containers:
- name: cf-ips-to-hcloud-fw
image: jkreileder/cf-ips-to-hcloud-fw:1.3.0
env:
- name: HCLOUD_TOKEN
valueFrom:
secretKeyRef:
name: cf-ips-to-hcloud-fw-token
key: token
- name: HCLOUD_FIREWALLS
value: |
firewall-1
firewall-2
To prepare your Hetzner Cloud Firewall:
Set the rule descriptions: Include __CLOUDFLARE_IPS_V4__,
__CLOUDFLARE_IPS_V6__, or __CLOUDFLARE_IPS__ in the description of any
incoming firewall rule where you want to insert Cloudflare networks. This
will be used as a marker to identify which rules should be updated with the
Cloudflare IP ranges.
Generate an API token: You'll need an API token with write permissions for the project that contains the firewall. This token will be used to authenticate your requests to the Hetzner Cloud API. You can generate a token in the Hetzner Cloud Console by going to "Security" > "API Tokens" > "Generate API Token".
To configure the application, you'll need to create a config.yaml file with
your API tokens and the names of the firewalls you want to update:
- token: API_TOKEN_FOR_PROJECT_1 # Token with read-write permissions for a Hetzner Cloud project
firewalls:
- firewall-1
- firewall-2
- token: API_TOKEN_FOR_PROJECT_2 # Token with read-write permissions for another Hetzner Cloud project
firewalls:
- default
On POSIX systems, the tool checks config file permissions before loading the file:
For local files, prefer owner-only access (for example chmod 600 config.yaml)
where practical.
For the common single-project case — typical in Docker and Kubernetes — you can
skip the config file entirely and provide the token and firewalls through
environment variables instead. When -c/--config is omitted, the tool builds a
single project from:
HCLOUD_TOKEN: API token with read-write permissions for the Hetzner Cloud
project.HCLOUD_FIREWALLS: newline-separated list of firewall names to update, one
name per line. Newlines are used as the separator so names may contain commas
and spaces (for example ICMP, SSH 222 IPv6, Cloudflare).export HCLOUD_TOKEN=your-api-token
export HCLOUD_FIREWALLS=$'firewall-1\nfirewall-2'
cf-ips-to-hcloud-fw
This keeps the token out of any on-disk file and lets you pass it as a native Docker/Kubernetes secret.
Configuration is resolved in this order: an explicit -c/--config file is the
sole source; otherwise a config.yaml in the working directory is used if
present; otherwise the environment variables above are used. A present config
file therefore takes precedence over the environment variables.
Run the tool with your configuration file:
cf-ips-to-hcloud-fw -c config.yaml
-c, --config FILE: Path to the configuration file. If omitted, a
config.yaml in the working directory is used when present, otherwise a single
project is built from the HCLOUD_TOKEN and HCLOUD_FIREWALLS environment
variables (see Using Environment Variables)-d, --debug: Enable debug logging for troubleshooting-v, --version: Display the installed versionExample with debug logging:
cf-ips-to-hcloud-fw -c config.yaml -d
Build provenance metadata and SBOM attestations are published with every artifact so you can verify their authenticity and contents.
These attestations are cryptographically signed. Use the commands below to validate
the signatures. For GitHub-hosted artifacts you can further restrict verification
with --signer-workflow. Container attestations can be fetched with docker scout attest get after verifying build provenance.
GH_REPO=jkreileder/cf-ips-to-hcloud-fw
VERSION=1.3.0
# Verifying build provenance
gh attestation verify cf_ips_to_hcloud_fw-$VERSION-py3-none-any.whl \
--repo $GH_REPO \
--signer-workflow $GH_REPO/.github/workflows/python-package.yaml@refs/tags/v$VERSION
gh attestation verify cf_ips_to_hcloud_fw-$VERSION.tar.gz \
--repo $GH_REPO \
--signer-workflow $GH_REPO/.github/workflows/python-package.yaml@refs/tags/v$VERSION
# Verifying and showing SBOM (only available for the the wheel)
gh attestation verify cf_ips_to_hcloud_fw-$VERSION-py3-none-any.whl \
--repo $GH_REPO \
--signer-workflow $GH_REPO/.github/workflows/python-package.yaml@refs/tags/v$VERSION \
--predicate-type https://spdx.dev/Document/v2.3
# Add --format json --jq '.[].verificationResult.statement.predicate' to also output the SBOM
It's recommended that you use an immutable image reference (pin to a digest) to avoid TOCTOU attacks.
Build provenance:
GH_REPO=jkreileder/cf-ips-to-hcloud-fw
IMAGE_REPO=docker.io/jkreileder/cf-ips-to-hcloud-fw
VERSION=1.3.0
IMAGE=$IMAGE_REPO@$(crane digest $IMAGE_REPO:$VERSION)
# Verifying build provenance
gh attestation verify oci://$IMAGE \
--repo $GH_REPO \
--signer-workflow $GH_REPO/.github/workflows/docker.yaml@refs/tags/v$VERSION
# The SBOMs are attached to the now verified image, you can view with
DIGEST=$(docker scout attest list --format json $IMAGE --predicate-type https://spdx.dev/Document \
| jq -r 'limit(1; .[] | select(.reference | startswith("jkreileder/cf-ips-to-hcloud-fw")) | .digest)')
docker scout attest get $IMAGE $DIGEST --predicate-type https://spdx.dev/Document
Contributions are welcome! Please see CONTRIBUTING.md for guidelines on how to contribute to this project.
If you discover a security vulnerability, please see SECURITY.md for responsible disclosure instructions.
Content type
Image
Digest
sha256:722063fe0…
Size
13.5 kB
Last updated
1 day ago
docker pull jkreileder/cf-ips-to-hcloud-fw:sha256-e0676e4a1d0a103a8532825a66770f2612e93b937af8f7e3ea80fd0ebcf05263.att