ipv6 and iptables - setting up basic rules

I have come to realise my IPv6 ports are not going through iptables, and thus are accessible for attacks. I haven't seen any yet, but I'm sure its only a matter of time. As such, I'm trying to shore up the firewall for ipv6. I came across this script that configures the ip6tables rules:

#!/bin/bash

# ip6tables single-host firewall script

# Define your command variables
ipt6="/sbin/ip6tables"

# Flush all rules and delete all chains
# for a clean startup
$ipt6 -F
$ipt6 -X

# Zero out all counters
$ipt6 -Z

# Default policies: deny all incoming
# Unrestricted outgoing

$ipt6 -P INPUT DROP
$ipt6 -P FORWARD DROP
$ipt6 -P OUTPUT ACCEPT

# Must allow loopback interface
$ipt6 -A INPUT -i lo -j ACCEPT

# Reject connection attempts not initiated from the host
$ipt6 -A INPUT -p tcp --syn -j DROP

# Allow return connections initiated from the host
$ipt6 -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Accept all ICMP v6 packets
$ipt6 -A INPUT -p ipv6-icmp -j ACCEPT

# Optional rules to allow other LAN hosts access to services. Delete $ipt6 -A INPUT -p tcp --syn -j DROP

# Allow DHCPv6 from LAN only
$ipt6 -A INPUT -m state --state NEW -m udp -p udp -s fe80::/10 --dport 546 -j ACCEPT

# Allow connections from SSH clients
$ipt6 -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

# Allow HTTP and HTTPS traffic 
$ipt6 -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
$ipt6 -A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

# Allow access to SMTP, POP3, and IMAP
$ipt6 -A INPUT -m state --state NEW -p tcp -m multiport --dport 25,110,143 -j ACCEPT

While this does stop what I wanted, it also seems to not allow 80 and 443 ports?

$ipt6 -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
$ipt6 -A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

It simply hangs when I try and access from another server:

curl -v -6 http://backups.foo.org:80
* Rebuilt URL to: http://backups.foo.org:80/
*   Trying 2a00:1098:80:a1::1...
* TCP_NODELAY set

ipv4 works fine:

curl -v -4 http://backups.foo.org:80
* Rebuilt URL to: http://backups.foo.org:80/
*   Trying 93.93.135.111...
* TCP_NODELAY set
* Connected to backups.foo.org (93.93.135.169) port 80 (#0)
> GET / HTTP/1.1
> Host: backups.foo.org
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx
< Date: Tue, 23 Feb 2021 07:52:32 GMT
< Content-Type: text/html
< Content-Length: 162
< Connection: keep-alive
< Location: https://backups.foo.org/
<
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host backups.foo.org left intact

What am I missing? Basically, I just want to block ipv6 ports on services that are sensitive (MySQL, Exim, SMTP etc).

UPDATE: As suggested, I have removed:

$ipt6 -A INPUT -p tcp --syn -j DROP

Then run the script again, and the ip6tables looks like this now:

root@backups:~# ip6tables --list -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all      ::/0                 ::/0
ACCEPT     all      ::/0                 ::/0                 ctstate RELATED,ESTABLISHED
ACCEPT     icmpv6    ::/0                 ::/0
ACCEPT     udp      fe80::/10            ::/0                 state NEW udp dpt:546
ACCEPT     tcp      ::/0                 ::/0                 state NEW tcp dpt:22
ACCEPT     tcp      ::/0                 ::/0                 state NEW tcp dpt:80
ACCEPT     tcp      ::/0                 ::/0                 state NEW tcp dpt:443
ACCEPT     tcp      ::/0                 ::/0                 state NEW multiport dports 25,110,143

Chain FORWARD (policy DROP)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

I have tested it:

curl -6 backups.foo.org
curl: (7) Failed to connect to backups.foo.org port 80: Connection refused

Again, it works with -4. The weird thing is that it does work from here:

https://tools.keycdn.com/ipv6-ping

I can ping from the same server, and it works fine:

ping backups.foo.org
PING backups.chambresdhotes.org(2a00:1098:80:a1::1 (2a00:1098:80:a1::1)) 56 data bytes
64 bytes from 2a00:1098:80:a1::1 (2a00:1098:80:a1::1): icmp_seq=1 ttl=59 time=1.08 ms
64 bytes from 2a00:1098:80:a1::1 (2a00:1098:80:a1::1): icmp_seq=2 ttl=59 time=1.03 ms
^X^C

As requested, the output of ip6tables-save as well:

 ip6tables-save
# Generated by ip6tables-save v1.6.1 on Tue Feb 23 08:57:59 2021
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [78:6090]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A INPUT -s fe80::/10 -p udp -m state --state NEW -m udp --dport 546 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m multiport --dports 25,110,143 -j ACCEPT
COMMIT

UPDATE 2:

As requested, the output from ss -lnpt. Interestingly, I don't see port 80 in there.

LISTEN    0    100  [::]:993       [::]:*  
LISTEN    0    100  [::]:995       [::]:*  
LISTEN    0    128  [::]:22122       [::]:*  
LISTEN    0    100  [::]:110       [::]:*  
LISTEN    0    128 ::1]:783       [::]:*   
LISTEN    0    100  [::]:143       [::]:*  
LISTEN    0    128  [::]:55413       [::]:*  
LISTEN    0    128 *:8181         *:*      
LISTEN    0    128 ::1]:53       [::]:*
LISTEN    0    128  [::]:55414   [::]:*
LISTEN    0    128  [::]:22      [::]:*
LISTEN    0    128 [::1]:8953    [::]:*  

Interestingly though, it shows up with netstat:

sudo netstat -tulpan | grep nginx
tcp        0      0 0.0.0.0:9183            0.0.0.0:*               LISTEN      1133/nginx: master
tcp        0      0 93.93.135.169:80        0.0.0.0:*               LISTEN      1161/nginx: master
tcp        0      0 127.0.0.1:8084          0.0.0.0:*               LISTEN      1161/nginx: master
tcp        0      0 93.93.135.169:443       0.0.0.0:*               LISTEN      1161/nginx: master
tcp6       0      0 :::80                   :::*                    LISTEN      1161/nginx: master
tcp6       0      0 :::443                  :::*                    LISTEN      1161/nginx: master
udp        0      0 127.0.0.1:51104         127.0.0.53:53           ESTABLISHED 1135/nginx: worker

This is the lesson not to use security scripts without understanding any single line.

I suspect this part is a culprit:

# Reject connection attempts not initiated from the host
$ipt6 -A INPUT -p tcp --syn -j DROP

It really disables any incoming TCPv6 communication. It also must disable any "related" TCPv6 communication (for instance, "active" FTP), because it appears before ctstate line.

Just remove it. It is useless. All unmatched packets will be dropped by the policy anyway, so why dropping anything early in the chain, without leaving a possibility to selectively enable services? I don't understand why ever this line appeared in the script.