UPDATE 2018-07-30: Added optional saving of changed ipset sets on service stop. Thanks to this comment by Derhomp.

UPDATE 2020-04-14: Removed unnecessary DefaultDependencies=no line, that prevented ExecStop commands from running on shutdown/reboot. Thanks to @pepoluan.

UPDATE 2021-05-14: Added -exist option, allowing correct service restart when ip sets are already in use by iptables. Thanks to @stefanlasiewski.

I could not find any standard solution for saving ipset rules together with iptables. Apparently, everybody who uses them have to create custom shell scripts for this task.

There are two most popular solutions for managing firewall in Ubuntu/Debian:

  • ufw - I don’t like it, but it is default.
  • iptables-persistent - if you are capable of writing firewall rules without crutches.

Using ipset with iptables has a subtelty: all sets should be defined before loading iptables rules that reffer to them.

Also, you can not destroy a set used by iptables rule, and you can not create a set with the same name as used one. So you can not just run ipset restore -file myipset if saved sets are already used by iptables.

Simpliest approach is to create all ipset sets once before loading any iptables rules.

Here is a systemd service to do that:

/etc/systemd/system/ipset-persistent.service:

[Unit]
Description=ipset persistent configuration
Before=network.target

# ipset sets should be loaded before iptables
# Because creating iptables rules with names of non-existent sets is not possible
Before=netfilter-persistent.service
Before=ufw.service

ConditionFileNotEmpty=/etc/iptables/ipset

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ipset restore -exist -file /etc/iptables/ipset
# Uncomment to save changed sets on reboot
# ExecStop=/sbin/ipset save -file /etc/iptables/ipset
ExecStop=/sbin/ipset flush
ExecStopPost=/sbin/ipset destroy

[Install]
WantedBy=multi-user.target

RequiredBy=netfilter-persistent.service
RequiredBy=ufw.service

Now all that’s left is to install it:

systemctl daemon-reload
systemctl enable ipset-persistent.service