Sem descrição

Paul Klumpp f02e8aed55 README: /etc/pve (pmxcfs) does not support chmod há 6 dias atrás
bash f99fb580a8 Python3 port with config file, GPLv3 license, README há 6 dias atrás
.gitignore f99fb580a8 Python3 port with config file, GPLv3 license, README há 6 dias atrás
LICENSE f99fb580a8 Python3 port with config file, GPLv3 license, README há 6 dias atrás
README.md f02e8aed55 README: /etc/pve (pmxcfs) does not support chmod há 6 dias atrás
manage_ipset.conf 145b738672 Merge into a single script with argparse and fail-safe multi-host há 6 dias atrás
manage_ipset.py bcf1fa59cd Fix CNAME handling: validate dig output as IP addresses há 6 dias atrás

README.md

manage-proxmox-ipset

Keep Proxmox cluster firewall IPSets in sync with DNS.

Hostnames are resolved repeatedly (A and AAAA) until no new IP addresses show up, so that all IPs behind a round-robin or anycast DNS record are collected. Afterwards the IPSet is synchronized: IPs that are gone are deleted, new IPs are added. Only the difference is written — no flush-and-refill.

One script, one config file. Python 3 standard library only — no pip installs needed. Requires pvesh (from pve-manager) and dig (from dnsutils) on the host.

Installation

Copy the script and the config to a Proxmox host (or any host with pvesh access to the cluster).

Note: /etc/pve is Proxmox's cluster filesystem (pmxcfs). It syncs its files to every node, but does not support chmod — scripts there cannot be made executable. Two options:

a) In /etc/pve — cluster-wide, run via python3:

cp manage_ipset.py manage_ipset.conf /etc/pve/
python3 /etc/pve/manage_ipset.py

b) Local and executable — e.g. /usr/local/sbin, per node:

install -m 755 manage_ipset.py /usr/local/sbin/
install -m 644 manage_ipset.conf /etc/
/usr/local/sbin/manage_ipset.py -c /etc/manage_ipset.conf

manage_ipset.conf is looked up next to the script unless -c is given.

Usage

# sync every IPSet from the config
python3 manage_ipset.py

# use a different config file
python3 manage_ipset.py -c /path/to/manage_ipset.conf

# sync a single IPSet directly
python3 manage_ipset.py github github.com github.io
python3 manage_ipset.py docker-io registry-1.docker.io --round 30

Cron

# every hour, /etc/pve install
0 * * * * python3 /etc/pve/manage_ipset.py

# local install
0 * * * * /usr/local/sbin/manage_ipset.py -c /etc/manage_ipset.conf

Config (manage_ipset.conf)

[defaults]
round=50
stale_after=10
# dns_server=1.1.1.1        # optional, default: system resolver
# timeout=15

golang
  host=go.dev

github
  host=github.com
  host=github.io round=10 stale_after=3
  • [defaults] section sets the global defaults. Optional.
  • An indented line host=... adds a host to the current IPSet. An IPSet may hold several hosts; their IPs are merged into one set.
  • Per-host options (optional): round, stale_after, dns_server, timeout.
  • Lines starting with # are comments.

Options

Option Meaning Default
round max. DNS query rounds per host 50
stale_after rounds without a new IP before stopping early 10
dns_server resolver to query (dig @server) system
timeout dig timeout in seconds 15

Hosts with many rotating IPs (big CDNs, registry-1.docker.io) benefit from a higher round; round=1 behaves like a single query.

How it works

  1. manage_ipset.py reads manage_ipset.conf and groups hosts by IPSet.
  2. For each host, dig +short host A / AAAA is run up to round times. As soon as stale_after consecutive rounds return no new IP, the loop stops.
  3. The collected IPs are compared against the current IPSet content (pvesh get /cluster/firewall/ipset/<name> --output-format json).
  4. Missing IPs are added (pvesh create ... --cidr), stale IPs are removed (pvesh delete .../<ip>).

If a host in an IPSet does not resolve, that IPSet is left untouched — a single broken hostname cannot strip the IPs of its siblings.

Notes

  • IPSet membership is matched by plain IP, ignoring the netmask that Proxmox stores per entry.
  • The script exits non-zero if any IPSet was skipped.
  • Legacy bash versions of both scripts are kept for reference in the bash/ directory.

License

GPLv3 — see LICENSE.

Copyright (C) 2026 Paul Klumpp