Skip to content

netfilter: MAILCOW isolation rule blocks all incoming TCP traffic / chain not flushed on re-initialization #7320

Description

@pomland-94

Contribution guidelines

Checklist prior issue creation

  • I understand that failure to follow below instructions may cause this issue to be closed.
  • I understand that vague, incomplete or inaccurate information may cause this issue to be closed.
  • I understand that this form is intended solely for reporting software bugs and not for support-related inquiries.
  • I understand that all responses are voluntary and community-driven, and do not constitute commercial support.
  • I confirm that I have reviewed previous issues to ensure this matter has not already been addressed.
  • I confirm that my environment meets all prerequisite requirements as specified in the official documentation.

Description

The netfilter container adds a blanket DROP tcp -- 0.0.0.0/0 0.0.0.0/0 /* mailcow isolation */ rule to the MAILCOW chain without any prior ACCEPT rules for mail ports (25, 465, 587, 993, 995, 143, 110, 4190). This effectively blocks all incoming TCP connections including legitimate SMTP traffic on port 25, even though DISABLE_NETFILTER_ISOLATION_RULE=y is set in mailcow.conf.

Additionally, the MAILCOW chain is not flushed before re-initialization, causing rules to accumulate in duplicate on every netfilter restart.

Observed MAILCOW chain in broken state:

Chain MAILCOW (4 references)
num  target  prot  opt  source     destination
1    DROP    tcp   --   0.0.0.0/0  0.0.0.0/0   /* mailcow isolation */
2    DROP    tcp   --   0.0.0.0/0  0.0.0.0/0   /* mailcow isolation */

After multiple restarts the chain accumulates further (ban list rules + isolation DROP appearing at positions 60 and 120), still with no ACCEPT rules for mail ports in between.

The result: SYN packets arrive on eth0 (confirmed via tcpdump) but no SYN-ACK is sent — external mail servers including DockerHub notifications and OVH cannot connect.

Steps to reproduce:

  1. Deploy mailcow with default config (DISABLE_NETFILTER_ISOLATION_RULE=n)
  2. Check the MAILCOW chain: iptables -L MAILCOW -n --line-numbers
  3. Observe: only bare DROP rules, no ACCEPT rules for mail ports
  4. Try external connection: telnet <mail-server> 25 → times out
  5. Confirm via tcpdump -i any port 25 -n: SYN packets arrive but no SYN-ACK is sent
  6. Set DISABLE_NETFILTER_ISOLATION_RULE=y in mailcow.conf
  7. Restart netfilter: docker compose restart netfilter-mailcow
  8. Isolation DROP rule persists — chain must be manually flushed: iptables -F MAILCOW
  9. After next automatic netfilter restart, the problem reappears

Workaround (must be re-applied after every netfilter restart):

iptables -F MAILCOW
docker compose restart netfilter-mailcow

Logs:

# Warning: table ip filter is managed by iptables-nft, do not touch!
# Warning: table ip nat is managed by iptables-nft, do not touch!
# Warning: table ip6 filter is managed by iptables-nft, do not touch!
# Warning: table ip6 nat is managed by iptables-nft, do not touch!
2026-06-09 17:00:42 INFO: Using NFTables backend
2026-06-09 17:00:42 INFO: Clearing all bans
2026-06-09 17:00:43 INFO: Initializing mailcow netfilter chain
2026-06-09 17:00:44 INFO: Setting MAILCOW isolation
2026-06-09 17:00:44 INFO: Watching Redis channel F2B_CHANNEL

 
No errors logged — netfilter initializes successfully but sets the isolation DROP without prior ACCEPT rules for mail ports.

Which branch are you using?

master (stable)

Which architecture are you using?

x86_64

Operating System:

Debian GNU/Linux 13 (trixie)

Server/VM specifications:

Netcup VPS 500 G12 NUE — 2 CPU Cores, 2 GB RAM

Is Apparmor, SELinux or similar active?

no

Virtualization technology:

KVM

Docker version:

29.5.3

docker-compose version or docker compose version:

v5.1.4

mailcow version:

2026-05c

Reverse proxy:

none

Logs of git diff:

Only changes are:
- `data/assets/ssl-example/cert.pem` and `key.pem` (replaced example cert with own self-signed cert)
- `data/conf/postfix/main.cf` (added postscreen DNSBL config and `myhostname` override in the user overrides section)
No changes to netfilter-related code.

Logs of iptables -L -vn:

Chain INPUT (policy ACCEPT 370K packets, 98M bytes)
 pkts bytes target     prot opt in     out     source               destination
 421K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 415K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 415K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
1412K  441M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
1411K  441M DOCKER-USER  all  --  *      *       ::/0                 ::/0
1411K  441M DOCKER-FORWARD  all  --  *      *       ::/0                 ::/0
    0     0 MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
    0     0 MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 
Chain OUTPUT (policy ACCEPT 259K packets, 20M bytes)
 pkts bytes target     prot opt in     out     source               destination
 
Chain MAILCOW (6 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  *      *       2001:470::/32        ::/0
    0     0 DROP       all  --  *      *       2604:a880::/32       ::/0
    [... ban list entries ...]

Logs of ip6tables -L -vn:

Chain INPUT (policy ACCEPT 370K packets, 98M bytes)
 pkts bytes target     prot opt in     out     source               destination
 421K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 415K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 415K  102M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
1412K  441M MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
1411K  441M DOCKER-USER  all  --  *      *       ::/0                 ::/0
1411K  441M DOCKER-FORWARD  all  --  *      *       ::/0                 ::/0
    0     0 MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
    0     0 MAILCOW    all  --  *      *       ::/0                 ::/0                 /* mailcow */
 
Chain OUTPUT (policy ACCEPT 259K packets, 20M bytes)
 pkts bytes target     prot opt in     out     source               destination
 
Chain MAILCOW (6 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  *      *       2001:470::/32        ::/0
    0     0 DROP       all  --  *      *       2604:a880::/32       ::/0
    [... ban list entries ...]

 
## Logs of iptables -L -vn -t nat:
 

Chain PREROUTING (policy ACCEPT 2102K packets, 145M bytes)
 pkts bytes target     prot opt in     out     source               destination
 745K   40M DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
 
Chain POSTROUTING (policy ACCEPT 3879 packets, 231K bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
1436K  109M MASQUERADE  all  --  *      !br-mailcow  172.22.1.0/24        0.0.0.0/0
 
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
 1102 59112 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:110 to:172.22.1.250:110
 1118 59456 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:143 to:172.22.1.250:143
 1116 62736 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:993 to:172.22.1.250:993
  710 39336 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:995 to:172.22.1.250:995
  885 52072 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:4190 to:172.22.1.250:4190
16698  947K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:80 to:172.22.1.11:80
43963 2545K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:443 to:172.22.1.11:443
10451  608K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:25 to:172.22.1.253:25
 1564 85436 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:465 to:172.22.1.253:465
 1630 93812 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:587 to:172.22.1.253:587

Logs of iptables -L -vn -t nat:

Chain PREROUTING (policy ACCEPT 2102K packets, 145M bytes)
 pkts bytes target     prot opt in     out     source               destination
 745K   40M DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
 
Chain POSTROUTING (policy ACCEPT 3879 packets, 231K bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
1436K  109M MASQUERADE  all  --  *      !br-mailcow  172.22.1.0/24        0.0.0.0/0
 
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
 1102 59112 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:110 to:172.22.1.250:110
 1118 59456 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:143 to:172.22.1.250:143
 1116 62736 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:993 to:172.22.1.250:993
  710 39336 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:995 to:172.22.1.250:995
  885 52072 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:4190 to:172.22.1.250:4190
16698  947K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:80 to:172.22.1.11:80
43963 2545K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:443 to:172.22.1.11:443
10451  608K DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:25 to:172.22.1.253:25
 1564 85436 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:465 to:172.22.1.253:465
 1630 93812 DNAT       tcp  --  !br-mailcow *       0.0.0.0/0  0.0.0.0/0  tcp dpt:587 to:172.22.1.253:587

Logs of ip6tables -L -vn -t nat:

Chain PREROUTING (policy ACCEPT 286K packets, 26M bytes)
 pkts bytes target     prot opt in     out     source               destination
32383 2625K DOCKER     all  --  *      *       ::/0                 ::/0                 ADDRTYPE match dst-type LOCAL
 
Chain POSTROUTING (policy ACCEPT 27477 packets, 2322K bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      !docker0  fdd0:91e9:ad79::/64  ::/0
 280K   25M MASQUERADE  all  --  *      !br-mailcow  fd4d:6169:6c63:6f77::/64  ::/0
 
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
   61  4556 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:110 to:[fd4d:6169:6c63:6f77::8]:110
  230 18332 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:143 to:[fd4d:6169:6c63:6f77::8]:143
  402 32244 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:993 to:[fd4d:6169:6c63:6f77::8]:993
   18  1132 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:995 to:[fd4d:6169:6c63:6f77::8]:995
  129  9984 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:25 to:[fd4d:6169:6c63:6f77::12]:25
  219 16956 DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:80 to:[fd4d:6169:6c63:6f77::f]:80
24772 2087K DNAT       tcp  --  !br-mailcow *  !fe80::/10  ::/0  tcp dpt:443 to:[fd4d:6169:6c63:6f77::f]:443

DNS check:

198.252.206.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions