We use a custom init-script, of course.
I can use for-loops to iterate over a list of ports, parse other config files like the vpn-users, etc.
And iptables-restore is surely the most "canonical" way of saving it.
What I want to add:
Please note that current version of iptables will for every single invokation ask the kernel to give it back the full list of chains. Then it will make the one change you ask it to do. Then it will upload the list again.
This is slow (O(n^2)), for us it needs 5 seconds which is too long ;-)
If you use iptables-restore, it all goes through in one quick operation.