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.

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 -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: