[Netfilter] add mailcow isolation rule to MAILCOW chain
[Netfilter] add mailcow rule to docker-user chain [Netfilter] add mailcow isolation rule to MAILCOW chain [Netfilter] add mailcow isolation rule to MAILCOW chain [Netfilter] set mailcow isolation rule before redis [Netfilter] clear bans in redis after connecting [Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft [Netfilter] stop container after mariadb, redis, dovecot, solr [Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft [Netfilter] add exception for mailcow isolation rule for HA setups [Netfilter] add exception for mailcow isolation rule for HA setups [Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE [Netfilter] fix wrong var name [Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE to update and generate_config sh
This commit is contained in:
		
							parent
							
								
									deb6f0babc
								
							
						
					
					
						commit
						b236fd3ac6
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -13,6 +13,7 @@ data/conf/dovecot/acl_anyone
 | 
			
		||||
data/conf/dovecot/dovecot-master.passwd
 | 
			
		||||
data/conf/dovecot/dovecot-master.userdb
 | 
			
		||||
data/conf/dovecot/extra.conf
 | 
			
		||||
data/conf/dovecot/mail_replica.conf
 | 
			
		||||
data/conf/dovecot/global_sieve_*
 | 
			
		||||
data/conf/dovecot/last_login
 | 
			
		||||
data/conf/dovecot/lua
 | 
			
		||||
 | 
			
		||||
@ -335,6 +335,15 @@ sys.exit()
 | 
			
		||||
EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Set mail_replica for HA setups
 | 
			
		||||
if [[ -n ${MAILCOW_REPLICA_IP} && -n ${DOVEADM_REPLICA_PORT} ]]; then
 | 
			
		||||
  cat <<EOF > /etc/dovecot/mail_replica.conf
 | 
			
		||||
# Autogenerated by mailcow
 | 
			
		||||
mail_replica = tcp:${MAILCOW_REPLICA_IP}:${DOVEADM_REPLICA_PORT}
 | 
			
		||||
EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 401 is user dovecot
 | 
			
		||||
if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then
 | 
			
		||||
	openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem
 | 
			
		||||
 | 
			
		||||
@ -21,28 +21,6 @@ from modules.IPTables import IPTables
 | 
			
		||||
from modules.NFTables import NFTables
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# connect to redis
 | 
			
		||||
while True:
 | 
			
		||||
  try:
 | 
			
		||||
    redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
 | 
			
		||||
    redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
 | 
			
		||||
    if "".__eq__(redis_slaveof_ip):
 | 
			
		||||
      r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0)
 | 
			
		||||
    else:
 | 
			
		||||
      r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0)
 | 
			
		||||
    r.ping()
 | 
			
		||||
  except Exception as ex:
 | 
			
		||||
    print('%s - trying again in 3 seconds'  % (ex))
 | 
			
		||||
    time.sleep(3)
 | 
			
		||||
  else:
 | 
			
		||||
    break
 | 
			
		||||
pubsub = r.pubsub()
 | 
			
		||||
 | 
			
		||||
# rename fail2ban to netfilter
 | 
			
		||||
if r.exists('F2B_LOG'):
 | 
			
		||||
  r.rename('F2B_LOG', 'NETFILTER_LOG')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# globals
 | 
			
		||||
WHITELIST = []
 | 
			
		||||
BLACKLIST= []
 | 
			
		||||
@ -50,18 +28,8 @@ bans = {}
 | 
			
		||||
quit_now = False
 | 
			
		||||
exit_code = 0
 | 
			
		||||
lock = Lock()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# init Logger
 | 
			
		||||
logger = Logger(r)
 | 
			
		||||
# init backend
 | 
			
		||||
backend = sys.argv[1]
 | 
			
		||||
if backend == "nftables":
 | 
			
		||||
  logger.logInfo('Using NFTables backend')
 | 
			
		||||
  tables = NFTables("MAILCOW", logger)
 | 
			
		||||
else:
 | 
			
		||||
  logger.logInfo('Using IPTables backend')
 | 
			
		||||
  tables = IPTables("MAILCOW", logger)
 | 
			
		||||
chain_name = "MAILCOW"
 | 
			
		||||
r = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def refreshF2boptions():
 | 
			
		||||
@ -250,9 +218,10 @@ def clear():
 | 
			
		||||
  with lock:
 | 
			
		||||
    tables.clearIPv4Table()
 | 
			
		||||
    tables.clearIPv6Table()
 | 
			
		||||
    r.delete('F2B_ACTIVE_BANS')
 | 
			
		||||
    r.delete('F2B_PERM_BANS')
 | 
			
		||||
    pubsub.unsubscribe()
 | 
			
		||||
    if r:
 | 
			
		||||
      r.delete('F2B_ACTIVE_BANS')
 | 
			
		||||
      r.delete('F2B_PERM_BANS')
 | 
			
		||||
      pubsub.unsubscribe()
 | 
			
		||||
 | 
			
		||||
def watch():
 | 
			
		||||
  logger.logInfo('Watching Redis channel F2B_CHANNEL')
 | 
			
		||||
@ -409,15 +378,60 @@ def quit(signum, frame):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
  refreshF2boptions()
 | 
			
		||||
  # init Logger
 | 
			
		||||
  logger = Logger(None)
 | 
			
		||||
 | 
			
		||||
  # init backend
 | 
			
		||||
  backend = sys.argv[1]
 | 
			
		||||
  if backend == "nftables":
 | 
			
		||||
    logger.logInfo('Using NFTables backend')
 | 
			
		||||
    tables = NFTables(chain_name, logger)
 | 
			
		||||
  else:
 | 
			
		||||
    logger.logInfo('Using IPTables backend')
 | 
			
		||||
    tables = IPTables(chain_name, logger)
 | 
			
		||||
 | 
			
		||||
  # In case a previous session was killed without cleanup
 | 
			
		||||
  clear()
 | 
			
		||||
 | 
			
		||||
  # Reinit MAILCOW chain
 | 
			
		||||
  # Is called before threads start, no locking
 | 
			
		||||
  logger.logInfo("Initializing mailcow netfilter chain")
 | 
			
		||||
  tables.initChainIPv4()
 | 
			
		||||
  tables.initChainIPv6()
 | 
			
		||||
 | 
			
		||||
  if os.getenv("DISABLE_NETFILTER_ISOLATION_RULE").lower() in ("y", "yes"):
 | 
			
		||||
    logger.logInfo(f"Skipping {chain_name} isolation")
 | 
			
		||||
  else:
 | 
			
		||||
    logger.logInfo(f"Setting {chain_name} isolation")
 | 
			
		||||
    tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP"))
 | 
			
		||||
 | 
			
		||||
  # connect to redis
 | 
			
		||||
  while True:
 | 
			
		||||
    try:
 | 
			
		||||
      redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
 | 
			
		||||
      redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
 | 
			
		||||
      if "".__eq__(redis_slaveof_ip):
 | 
			
		||||
        r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0)
 | 
			
		||||
      else:
 | 
			
		||||
        r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0)
 | 
			
		||||
      r.ping()
 | 
			
		||||
    except Exception as ex:
 | 
			
		||||
      print('%s - trying again in 3 seconds'  % (ex))
 | 
			
		||||
      time.sleep(3)
 | 
			
		||||
    else:
 | 
			
		||||
      break
 | 
			
		||||
  pubsub = r.pubsub()
 | 
			
		||||
  Logger.r = r
 | 
			
		||||
 | 
			
		||||
  # rename fail2ban to netfilter
 | 
			
		||||
  if r.exists('F2B_LOG'):
 | 
			
		||||
    r.rename('F2B_LOG', 'NETFILTER_LOG')
 | 
			
		||||
  # clear bans in redis
 | 
			
		||||
  r.delete('F2B_ACTIVE_BANS')
 | 
			
		||||
  r.delete('F2B_PERM_BANS')
 | 
			
		||||
  
 | 
			
		||||
  refreshF2boptions()
 | 
			
		||||
 | 
			
		||||
  watch_thread = Thread(target=watch)
 | 
			
		||||
  watch_thread.daemon = True
 | 
			
		||||
  watch_thread.start()
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import iptc
 | 
			
		||||
import time
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
class IPTables:
 | 
			
		||||
  def __init__(self, chain_name, logger):
 | 
			
		||||
@ -211,3 +212,41 @@ class IPTables:
 | 
			
		||||
    target = rule.create_target("SNAT")
 | 
			
		||||
    target.to_source = snat_target
 | 
			
		||||
    return rule
 | 
			
		||||
 | 
			
		||||
  def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""):
 | 
			
		||||
    try:
 | 
			
		||||
      chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name)
 | 
			
		||||
 | 
			
		||||
      # insert mailcow isolation rule
 | 
			
		||||
      rule = iptc.Rule()
 | 
			
		||||
      rule.in_interface = f'! {_interface}'
 | 
			
		||||
      rule.out_interface = _interface
 | 
			
		||||
      rule.protocol = 'tcp'
 | 
			
		||||
      rule.create_target("DROP")
 | 
			
		||||
      match = rule.create_match("multiport")
 | 
			
		||||
      match.dports = ','.join(map(str, _dports))
 | 
			
		||||
 | 
			
		||||
      if rule in chain.rules:
 | 
			
		||||
        chain.delete_rule(rule)
 | 
			
		||||
      chain.insert_rule(rule, position=0)
 | 
			
		||||
 | 
			
		||||
      # insert mailcow isolation exception rule
 | 
			
		||||
      if _allow != "":
 | 
			
		||||
        rule = iptc.Rule()
 | 
			
		||||
        rule.src = _allow
 | 
			
		||||
        rule.in_interface = f'! {_interface}'
 | 
			
		||||
        rule.out_interface = _interface
 | 
			
		||||
        rule.protocol = 'tcp'
 | 
			
		||||
        rule.create_target("ACCEPT")
 | 
			
		||||
        match = rule.create_match("multiport")
 | 
			
		||||
        match.dports = ','.join(map(str, _dports))
 | 
			
		||||
 | 
			
		||||
        if rule in chain.rules:
 | 
			
		||||
          chain.delete_rule(rule)
 | 
			
		||||
        chain.insert_rule(rule, position=0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      return True
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
      self.logger.logCrit(f"Error adding {self.chain_name} isolation: {e}")
 | 
			
		||||
      return False
 | 
			
		||||
@ -10,7 +10,8 @@ class Logger:
 | 
			
		||||
    tolog['time'] = int(round(time.time()))
 | 
			
		||||
    tolog['priority'] = priority
 | 
			
		||||
    tolog['message'] = message
 | 
			
		||||
    self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
 | 
			
		||||
    if self.r:
 | 
			
		||||
      self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
 | 
			
		||||
    print(message)
 | 
			
		||||
 | 
			
		||||
  def logWarn(self, message):
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import nftables
 | 
			
		||||
import ipaddress
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
class NFTables:
 | 
			
		||||
  def __init__(self, chain_name, logger):
 | 
			
		||||
@ -266,6 +267,17 @@ class NFTables:
 | 
			
		||||
 | 
			
		||||
    return self.nft_exec_dict(delete_command)
 | 
			
		||||
 | 
			
		||||
  def delete_filter_rule(self, _family:str, _chain: str, _handle:str):
 | 
			
		||||
    delete_command = self.get_base_dict()
 | 
			
		||||
    _rule_opts = {'family': _family,
 | 
			
		||||
                  'table': 'filter',
 | 
			
		||||
                  'chain': _chain,
 | 
			
		||||
                  'handle': _handle  }
 | 
			
		||||
    _delete = {'delete': {'rule': _rule_opts} }
 | 
			
		||||
    delete_command["nftables"].append(_delete)
 | 
			
		||||
 | 
			
		||||
    return self.nft_exec_dict(delete_command)
 | 
			
		||||
 | 
			
		||||
  def snat_rule(self, _family: str, snat_target: str, source_address: str):
 | 
			
		||||
    chain_name = self.nft_chain_names[_family]['nat']['postrouting']
 | 
			
		||||
 | 
			
		||||
@ -381,7 +393,7 @@ class NFTables:
 | 
			
		||||
          break
 | 
			
		||||
    return chain_handle
 | 
			
		||||
 | 
			
		||||
  def get_rules_handle(self, _family: str, _table: str, chain_name: str):
 | 
			
		||||
  def get_rules_handle(self, _family: str, _table: str, chain_name: str, _comment_filter = "mailcow"):
 | 
			
		||||
    rule_handle = []
 | 
			
		||||
    # Command: 'nft list chain {family} {table} {chain_name}'
 | 
			
		||||
    _chain_opts = {'family': _family, 'table': _table, 'name': chain_name}
 | 
			
		||||
@ -397,7 +409,7 @@ class NFTables:
 | 
			
		||||
 | 
			
		||||
        rule = _object["rule"]
 | 
			
		||||
        if rule["family"] == _family and rule["table"] == _table and rule["chain"] == chain_name:
 | 
			
		||||
          if rule.get("comment") and rule["comment"] == "mailcow":
 | 
			
		||||
          if rule.get("comment") and rule["comment"] == _comment_filter:
 | 
			
		||||
            rule_handle.append(rule["handle"])
 | 
			
		||||
    return rule_handle
 | 
			
		||||
 | 
			
		||||
@ -493,3 +505,152 @@ class NFTables:
 | 
			
		||||
        position+=1
 | 
			
		||||
 | 
			
		||||
    return position if rule_found else False
 | 
			
		||||
 | 
			
		||||
  def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""):
 | 
			
		||||
    family = "ip"
 | 
			
		||||
    table = "filter"
 | 
			
		||||
    comment_filter_drop = "mailcow isolation"
 | 
			
		||||
    comment_filter_allow = "mailcow isolation allow"
 | 
			
		||||
    json_command = self.get_base_dict()
 | 
			
		||||
 | 
			
		||||
    # Delete old mailcow isolation rules
 | 
			
		||||
    handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_drop)
 | 
			
		||||
    for handle in handles:
 | 
			
		||||
      self.delete_filter_rule(family, self.chain_name, handle)
 | 
			
		||||
    handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_allow)
 | 
			
		||||
    for handle in handles:
 | 
			
		||||
      self.delete_filter_rule(family, self.chain_name, handle)
 | 
			
		||||
 | 
			
		||||
    # insert mailcow isolation rule
 | 
			
		||||
    _match_dict_drop = [
 | 
			
		||||
      {
 | 
			
		||||
        "match": {
 | 
			
		||||
          "op": "!=",
 | 
			
		||||
          "left": {
 | 
			
		||||
            "meta": {
 | 
			
		||||
              "key": "iifname"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          "right": _interface
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "match": {
 | 
			
		||||
          "op": "==",
 | 
			
		||||
          "left": {
 | 
			
		||||
            "meta": {
 | 
			
		||||
              "key": "oifname"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          "right": _interface
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "match": {
 | 
			
		||||
          "op": "==",
 | 
			
		||||
          "left": {
 | 
			
		||||
            "payload": {
 | 
			
		||||
              "protocol": "tcp",
 | 
			
		||||
              "field": "dport"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          "right": {
 | 
			
		||||
            "set": _dports
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "counter": {
 | 
			
		||||
          "packets": 0,
 | 
			
		||||
          "bytes": 0
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "drop": None
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
    rule_drop = { "insert": { "rule": {
 | 
			
		||||
      "family": family,
 | 
			
		||||
      "table": table,
 | 
			
		||||
      "chain": self.chain_name,
 | 
			
		||||
      "comment": comment_filter_drop,
 | 
			
		||||
      "expr": _match_dict_drop
 | 
			
		||||
    }}}
 | 
			
		||||
    json_command["nftables"].append(rule_drop)
 | 
			
		||||
 | 
			
		||||
    # insert mailcow isolation allow rule
 | 
			
		||||
    if _allow != "":
 | 
			
		||||
      _match_dict_allow = [
 | 
			
		||||
        {
 | 
			
		||||
          "match": {
 | 
			
		||||
            "op": "==",
 | 
			
		||||
            "left": {
 | 
			
		||||
              "payload": {
 | 
			
		||||
                "protocol": "ip",
 | 
			
		||||
                "field": "saddr"
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "right": _allow
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "match": {
 | 
			
		||||
            "op": "!=",
 | 
			
		||||
            "left": {
 | 
			
		||||
              "meta": {
 | 
			
		||||
                "key": "iifname"
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "right": _interface
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "match": {
 | 
			
		||||
            "op": "==",
 | 
			
		||||
            "left": {
 | 
			
		||||
              "meta": {
 | 
			
		||||
                "key": "oifname"
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "right": _interface
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "match": {
 | 
			
		||||
            "op": "==",
 | 
			
		||||
            "left": {
 | 
			
		||||
              "payload": {
 | 
			
		||||
                "protocol": "tcp",
 | 
			
		||||
                "field": "dport"
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "right": {
 | 
			
		||||
              "set": _dports
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "counter": {
 | 
			
		||||
            "packets": 0,
 | 
			
		||||
            "bytes": 0
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "accept": None
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
      rule_allow = { "insert": { "rule": {
 | 
			
		||||
        "family": family,
 | 
			
		||||
        "table": table,
 | 
			
		||||
        "chain": self.chain_name,
 | 
			
		||||
        "comment": comment_filter_allow,
 | 
			
		||||
        "expr": _match_dict_allow
 | 
			
		||||
      }}}
 | 
			
		||||
      json_command["nftables"].append(rule_allow)
 | 
			
		||||
 | 
			
		||||
    success = self.nft_exec_dict(json_command)
 | 
			
		||||
    if success == False:
 | 
			
		||||
      self.logger.logCrit(f"Error adding {self.chain_name} isolation")
 | 
			
		||||
      return False
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
@ -247,6 +247,9 @@ plugin {
 | 
			
		||||
  mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
 | 
			
		||||
  mail_log_fields = uid box msgid size
 | 
			
		||||
  mail_log_cached_only = yes
 | 
			
		||||
 | 
			
		||||
  # Try set mail_replica
 | 
			
		||||
  !include_try /etc/dovecot/mail_replica.conf
 | 
			
		||||
}
 | 
			
		||||
service quota-warning {
 | 
			
		||||
  executable = script /usr/local/bin/quota_notify.py
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ services:
 | 
			
		||||
      image: mariadb:10.5
 | 
			
		||||
      depends_on:
 | 
			
		||||
        - unbound-mailcow
 | 
			
		||||
        - netfilter-mailcow
 | 
			
		||||
      stop_grace_period: 45s
 | 
			
		||||
      volumes:
 | 
			
		||||
        - mysql-vol-1:/var/lib/mysql/
 | 
			
		||||
@ -46,6 +47,8 @@ services:
 | 
			
		||||
      volumes:
 | 
			
		||||
        - redis-vol-1:/data/
 | 
			
		||||
      restart: always
 | 
			
		||||
      depends_on:
 | 
			
		||||
        - netfilter-mailcow
 | 
			
		||||
      ports:
 | 
			
		||||
        - "${REDIS_PORT:-127.0.0.1:7654}:6379"
 | 
			
		||||
      environment:
 | 
			
		||||
@ -222,6 +225,7 @@ services:
 | 
			
		||||
      image: mailcow/dovecot:1.27
 | 
			
		||||
      depends_on:
 | 
			
		||||
        - mysql-mailcow
 | 
			
		||||
        - netfilter-mailcow
 | 
			
		||||
      dns:
 | 
			
		||||
        - ${IPV4_NETWORK:-172.22.1}.254
 | 
			
		||||
      cap_add:
 | 
			
		||||
@ -242,6 +246,8 @@ services:
 | 
			
		||||
      environment:
 | 
			
		||||
        - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-}
 | 
			
		||||
        - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-}
 | 
			
		||||
        - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-}
 | 
			
		||||
        - DOVEADM_REPLICA_PORT=${DOVEADM_REPLICA_PORT:-}
 | 
			
		||||
        - LOG_LINES=${LOG_LINES:-9999}
 | 
			
		||||
        - DBNAME=${DBNAME}
 | 
			
		||||
        - DBUSER=${DBUSER}
 | 
			
		||||
@ -437,12 +443,6 @@ services:
 | 
			
		||||
    netfilter-mailcow:
 | 
			
		||||
      image: mailcow/netfilter:1.55
 | 
			
		||||
      stop_grace_period: 30s
 | 
			
		||||
      depends_on:
 | 
			
		||||
        - dovecot-mailcow
 | 
			
		||||
        - postfix-mailcow
 | 
			
		||||
        - sogo-mailcow
 | 
			
		||||
        - php-fpm-mailcow
 | 
			
		||||
        - redis-mailcow
 | 
			
		||||
      restart: always
 | 
			
		||||
      privileged: true
 | 
			
		||||
      environment:
 | 
			
		||||
@ -453,6 +453,8 @@ services:
 | 
			
		||||
        - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
 | 
			
		||||
        - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
 | 
			
		||||
        - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
 | 
			
		||||
        - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-}
 | 
			
		||||
        - DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n}
 | 
			
		||||
      network_mode: "host"
 | 
			
		||||
      volumes:
 | 
			
		||||
        - /lib/modules:/lib/modules:ro
 | 
			
		||||
@ -553,6 +555,8 @@ services:
 | 
			
		||||
    solr-mailcow:
 | 
			
		||||
      image: mailcow/solr:1.8.2
 | 
			
		||||
      restart: always
 | 
			
		||||
      depends_on:
 | 
			
		||||
        - netfilter-mailcow
 | 
			
		||||
      volumes:
 | 
			
		||||
        - solr-vol-1:/opt/solr/server/solr/dovecot-fts/data
 | 
			
		||||
      ports:
 | 
			
		||||
 | 
			
		||||
@ -494,6 +494,9 @@ WEBAUTHN_ONLY_TRUSTED_VENDORS=n
 | 
			
		||||
# Otherwise it will work normally.
 | 
			
		||||
SPAMHAUS_DQS_KEY=
 | 
			
		||||
 | 
			
		||||
# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n
 | 
			
		||||
# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost
 | 
			
		||||
DISABLE_NETFILTER_ISOLATION_RULE=n
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
mkdir -p data/assets/ssl
 | 
			
		||||
 | 
			
		||||
@ -481,6 +481,7 @@ CONFIG_ARRAY=(
 | 
			
		||||
  "WEBAUTHN_ONLY_TRUSTED_VENDORS"
 | 
			
		||||
  "SPAMHAUS_DQS_KEY"
 | 
			
		||||
  "SKIP_UNBOUND_HEALTHCHECK"
 | 
			
		||||
  "DISABLE_NETFILTER_ISOLATION_RULE"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
detect_bad_asn
 | 
			
		||||
@ -754,6 +755,13 @@ for option in ${CONFIG_ARRAY[@]}; do
 | 
			
		||||
      echo '# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n' >> mailcow.conf
 | 
			
		||||
      echo 'SKIP_UNBOUND_HEALTHCHECK=n' >> mailcow.conf
 | 
			
		||||
    fi
 | 
			
		||||
  elif [[ ${option} == "DISABLE_NETFILTER_ISOLATION_RULE" ]]; then
 | 
			
		||||
    if ! grep -q ${option} mailcow.conf; then
 | 
			
		||||
      echo "Adding new option \"${option}\" to mailcow.conf"
 | 
			
		||||
      echo '# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n' >> mailcow.conf
 | 
			
		||||
      echo '# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost' >> mailcow.conf
 | 
			
		||||
      echo 'DISABLE_NETFILTER_ISOLATION_RULE=n' >> mailcow.conf
 | 
			
		||||
    fi 
 | 
			
		||||
  elif ! grep -q ${option} mailcow.conf; then
 | 
			
		||||
    echo "Adding new option \"${option}\" to mailcow.conf"
 | 
			
		||||
    echo "${option}=n" >> mailcow.conf
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user