I am aware of the grub kernel params method but I'd like to understand why the sysctl approach is not working.
On a 20.04 server if I add net.ipv6.conf.(all|default|lo).disable_ipv6=1 (presumably ".all." should be enough), to /etc/sysctl.conf (or a separate /etc/sysctl.d/ file), on boot it only disables ipv6 on the loopback, the main interface still has it.
Since it works for loopback, the sysctl conf files are being processed on boot.