You will learn how to build, install, and verify update-ipsets on a Linux server.
- Linux (amd64 or arm64)
- Go 1.26 or later
- pnpm (for building the embedded web UI)
Clone the repository and build:
git clone https://github.com/firehol/update-ipsets.git
cd update-ipsets
make buildThis produces a single update-ipsets binary in the project root. The binary has the web UI embedded — no separate static files to deploy.
Run the installer:
./install.shThe installer does these things in order:
- Installs UI dependencies and builds the embedded web UI (
pnpm --dir ui install --frozen-lockfile+pnpm --dir ui build) - Copies the fresh UI bundle into the embedded static directory
- Builds the Go binary with the UI baked in
- Creates the directory tree under
/opt/update-ipsets/ - Creates the
iplistssystem group and user if they do not already exist - Installs the binary to
/opt/update-ipsets/bin/update-ipsets - Deploys the feed catalog from
configs/firehol/to/opt/update-ipsets/etc/config/ - Copies Markdown templates from
configs/templates/markdown/to/opt/update-ipsets/etc/config/templates/markdown/ - Makes
bin/andetc/owned byroot:iplistswith group-only access, and ensures runtime directory roots are writable byiplists - Installs the systemd unit at
/etc/systemd/system/update-ipsets.service - Reloads systemd, then restarts the service if it is active, starts it if it is enabled but inactive, or leaves it stopped if it is not enabled
When the service is already running, normal installs keep the old daemon serving while the new binary, catalog, templates, and unit are installed. The running daemon does not watch those files automatically. It picks up the new binary and unit only at the final restart.
The generated systemd unit:
- runs as
User=iplistsandGroup=iplists - sets
UMask=0077so generated artifacts are private to the service user - serves the public listener on
127.0.0.1:18888 - serves admin on
127.0.0.1:18889with admin auth disabled - moves the admin listener to the Tailscale IPv4 address when
tailscale ip -4returns one - sets
MemoryHigh=2.75G,MemoryMax=3G, andGOMEMLIMIT=2560MiB - writes logs to the
iplistsjournal namespace
The Tailscale address is detected when install.sh writes the unit. If
Tailscale is added later or the address changes, rerun the installer or set
UPDATE_IPSETS_ADMIN_LISTEN_ARG in a drop-in.
The Tailscale default is for hosts where tailnet access is the admin access
control layer. On a shared, untrusted, or internet-reachable network, override
the admin listener and set UPDATE_IPSETS_ADMIN_AUTH_ARG=--admin-auth-mode=required
with credentials in a protected drop-in.
Pass a different path as an argument only for manual or experimental layouts:
./install.sh /opt/custom-pathThe installer copies the binary and catalog to that path and writes that path into the generated systemd unit. For repeatable managed installs, use one stable install directory so path overrides, backups, and service state stay together.
Add --no-restart to install without restarting the running service:
./install.sh --no-restartThe new binary takes effect on the next manual restart.
Normal installs do not recursively scan or rewrite the mutable runtime trees
under data/, cache/, lib/, web/, run/, and tmp/. The daemon creates
new runtime files with private permissions through the managed systemd
UMask=0077, and the installer only ensures the bounded directory roots exist
with the correct owner/group/mode.
If a migration or manual change damaged existing runtime permissions, run:
./install.sh --repair-runtime-permissionsThis explicit maintenance mode stops the active service, removes stale generated publish-stage directories, scans the mutable runtime trees, and changes only paths whose owner, group, or mode is wrong. It also compacts generated Git object stores when present.
The installer compares the repository catalog (configs/firehol/) against the active config directory (/opt/update-ipsets/etc/config/). When the content changed, it:
- Creates a timestamped backup:
/opt/update-ipsets/etc/config.bak.YYYYMMDDHHMMSS - Deploys the fresh catalog from the repository
When the content is identical, the installer leaves the active config untouched. This avoids triggering unnecessary reprocessing.
Any local changes to the config directory survive reinstalls in the backup copy. Merge your customizations back after upgrading.
Markdown templates are handled separately. The installer copies repository
templates from configs/templates/markdown/ into
/opt/update-ipsets/etc/config/templates/markdown/. If the installed templates
are identical, it leaves them untouched. If they differ, it overwrites matching
template files in place and does not create a separate template backup. Extra
local files under the template directory are not removed.
If you customize Markdown templates, keep a copy outside the installed template directory or keep a local patch, then reapply it after reinstalling. Template changes require a service restart; SIGHUP reloads the YAML catalog only.
Check the binary version:
/opt/update-ipsets/bin/update-ipsets versionCheck the service status:
systemctl status update-ipsetsInspect service logs:
journalctl --namespace=iplists -u update-ipsets -n 50Test the health endpoint:
curl http://localhost:18888/healthzA working installation returns ok.
- Systemd setup — customize the service with drop-in overrides
- TLS configuration — enable HTTPS
- Filesystem layout — understand the installed directory tree