Page Menu
Home
WMGMC Issues
搜索
Configure Global Search
登录
Files
F16083
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
订阅
标记用于日后
授予令牌
Size
23 KB
Referenced Files
None
订阅者
None
View Options
diff --git a/data/Dockerfiles/dovecot/syslog-ng.conf b/data/Dockerfiles/dovecot/syslog-ng.conf
index ead195a5..b8cc44fd 100644
--- a/data/Dockerfiles/dovecot/syslog-ng.conf
+++ b/data/Dockerfiles/dovecot/syslog-ng.conf
@@ -1,31 +1,41 @@
@version: 3.8
@include "scl.conf"
options {
chain_hostnames(off);
flush_lines(0);
use_dns(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
internal();
};
destination d_combined { file("/var/log/combined.log"); };
-destination d_redis {
+destination d_redis_persistent_log {
redis(
host("redis-mailcow")
+ persist-name("redis1")
port(6379)
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
-filter f_mail { facility(mail) and not filter(f_debug); };
+destination d_redis_f2b_channel {
+ redis(
+ host("redis-mailcow")
+ persist-name("redis2")
+ port(6379)
+ command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
+ );
+};
+filter f_mail { facility(mail); };
log {
source(s_src);
destination(d_combined);
filter(f_mail);
- destination(d_redis);
+ destination(d_redis_persistent_log);
+ destination(d_redis_f2b_channel);
};
diff --git a/data/Dockerfiles/fail2ban/Dockerfile b/data/Dockerfiles/fail2ban/Dockerfile
index 9f81f14e..26fe9414 100644
--- a/data/Dockerfiles/fail2ban/Dockerfile
+++ b/data/Dockerfiles/fail2ban/Dockerfile
@@ -1,8 +1,8 @@
FROM python:2-alpine
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
RUN apk add -U --no-cache iptables ip6tables
-RUN pip install docker redis
+RUN pip install redis ipaddress
COPY logwatch.py /
CMD ["python2", "-u", "/logwatch.py"]
diff --git a/data/Dockerfiles/fail2ban/logwatch.py b/data/Dockerfiles/fail2ban/logwatch.py
index 74bc26b5..d431a072 100644
--- a/data/Dockerfiles/fail2ban/logwatch.py
+++ b/data/Dockerfiles/fail2ban/logwatch.py
@@ -1,205 +1,185 @@
#!/usr/bin/env python2
import re
import os
import time
import atexit
import signal
import ipaddress
import subprocess
from threading import Thread
-import docker
import redis
import time
import json
yes_regex = re.compile(r'([yY][eE][sS]|[yY])+$')
if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
print "Skipping Fail2ban container..."
raise SystemExit
r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0)
-client = docker.from_env()
-
-for container in client.containers.list():
- if "postfix-mailcow" in container.name:
- postfix_container = container.name
- elif "dovecot-mailcow" in container.name:
- dovecot_container = container.name
- elif "sogo-mailcow" in container.name:
- sogo_container = container.name
- elif "php-fpm-mailcow" in container.name:
- php_fpm_container = container.name
+pubsub = r.pubsub()
RULES = {}
-
-RULES[postfix_container] = {}
-RULES[dovecot_container] = {}
-RULES[sogo_container] = {}
-RULES[php_fpm_container] = {}
-
-RULES[postfix_container][1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .* authentication failed'
-RULES[dovecot_container][1] = '-login: Disconnected \(auth failed, .*\): user=.*, method=.*, rip=([0-9a-f\.:]+),'
-RULES[dovecot_container][2] = '-login: Disconnected \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
-RULES[dovecot_container][3] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
-RULES[dovecot_container][4] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
-RULES[sogo_container][1] = 'SOGo.* Login from \'([0-9a-f\.:]+)\' for user .* might not have worked'
-RULES[php_fpm_container][1] = 'mailcow UI: Invalid password for .* by ([0-9a-f\.:]+)'
-
+RULES[1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
+RULES[2] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
+RULES[3] = '-login: Disconnected \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
+RULES[4] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
+RULES[5] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
+RULES[6] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
+RULES[7] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
r.setnx("F2B_BAN_TIME", "1800")
r.setnx("F2B_MAX_ATTEMPTS", "10")
r.setnx("F2B_RETRY_WINDOW", "600")
bans = {}
log = {}
quit_now = False
def ban(address):
BAN_TIME = int(r.get("F2B_BAN_TIME"))
MAX_ATTEMPTS = int(r.get("F2B_MAX_ATTEMPTS"))
RETRY_WINDOW = int(r.get("F2B_RETRY_WINDOW"))
WHITELIST = r.hgetall("F2B_WHITELIST")
ip = ipaddress.ip_address(address.decode('ascii'))
if type(ip) is ipaddress.IPv6Address and ip.ipv4_mapped:
ip = ip.ipv4_mapped
address = str(ip)
if ip.is_private or ip.is_loopback:
return
self_network = ipaddress.ip_network(address.decode('ascii'))
if WHITELIST:
for wl_key in WHITELIST:
wl_net = ipaddress.ip_network(wl_key.decode('ascii'), False)
if wl_net.overlaps(self_network):
log['time'] = int(round(time.time()))
log['priority'] = "info"
log['message'] = "Address %s is whitelisted by rule %s" % (self_network, wl_net)
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "Address %s is whitelisted by rule %s" % (self_network, wl_net)
return
net = ipaddress.ip_network((address + ('/24' if type(ip) is ipaddress.IPv4Address else '/64')).decode('ascii'), strict=False)
net = str(net)
if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW:
bans[net] = { 'attempts': 0 }
active_window = RETRY_WINDOW
else:
active_window = time.time() - bans[net]['last_attempt']
bans[net]['attempts'] += 1
bans[net]['last_attempt'] = time.time()
active_window = time.time() - bans[net]['last_attempt']
if bans[net]['attempts'] >= MAX_ATTEMPTS:
log['time'] = int(round(time.time()))
log['priority'] = "crit"
log['message'] = "Banning %s" % net
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "Banning %s for %d minutes" % (net, BAN_TIME / 60)
if type(ip) is ipaddress.IPv4Address:
subprocess.call(["iptables", "-I", "INPUT", "-s", net, "-j", "REJECT"])
subprocess.call(["iptables", "-I", "FORWARD", "-s", net, "-j", "REJECT"])
else:
subprocess.call(["ip6tables", "-I", "INPUT", "-s", net, "-j", "REJECT"])
subprocess.call(["ip6tables", "-I", "FORWARD", "-s", net, "-j", "REJECT"])
r.hset("F2B_ACTIVE_BANS", "%s" % net, log['time'] + BAN_TIME)
else:
log['time'] = int(round(time.time()))
log['priority'] = "warn"
log['message'] = "%d more attempts in the next %d seconds until %s is banned" % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "%d more attempts in the next %d seconds until %s is banned" % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)
def unban(net):
log['time'] = int(round(time.time()))
log['priority'] = "info"
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
if not net in bans:
log['message'] = "%s is not banned, skipping unban and deleting from queue (if any)" % net
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "%s is not banned, skipping unban and deleting from queue (if any)" % net
r.hdel("F2B_QUEUE_UNBAN", "%s" % net)
return
log['message'] = "Unbanning %s" % net
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "Unbanning %s" % net
if type(ipaddress.ip_network(net.decode('ascii'))) is ipaddress.IPv4Network:
subprocess.call(["iptables", "-D", "INPUT", "-s", net, "-j", "REJECT"])
subprocess.call(["iptables", "-D", "FORWARD", "-s", net, "-j", "REJECT"])
else:
subprocess.call(["ip6tables", "-D", "INPUT", "-s", net, "-j", "REJECT"])
subprocess.call(["ip6tables", "-D", "FORWARD", "-s", net, "-j", "REJECT"])
r.hdel("F2B_ACTIVE_BANS", "%s" % net)
r.hdel("F2B_QUEUE_UNBAN", "%s" % net)
del bans[net]
def quit(signum, frame):
global quit_now
quit_now = True
def clear():
log['time'] = int(round(time.time()))
log['priority'] = "info"
log['message'] = "Clearing all bans"
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "Clearing all bans"
for net in bans.copy():
unban(net)
+ pubsub.unsubscribe()
-def watch(container):
+def watch():
log['time'] = int(round(time.time()))
log['priority'] = "info"
- log['message'] = "Watching %s" % container
+ log['message'] = "Watching Redis channel F2B_CHANNEL"
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
- print "Watching", container
- for msg in client.containers.get(container).attach(stream=True, logs=False):
- for rule_id, rule_regex in RULES[container].iteritems():
- result = re.search(rule_regex, msg)
- if result:
- addr = result.group(1)
- print "%s matched rule id %d in %s" % (addr, rule_id, container)
- log['time'] = int(round(time.time()))
- log['priority'] = "warn"
- log['message'] = "%s matched rule id %d in %s" % (addr, rule_id, container)
- r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
- ban(addr)
+ pubsub.subscribe("F2B_CHANNEL")
+ print "Subscribing to Redis channel F2B_CHANNEL"
+ while True:
+ for item in pubsub.listen():
+ for rule_id, rule_regex in RULES.iteritems():
+ if item['data'] and item['type'] == 'message':
+ result = re.search(rule_regex, item['data'])
+ if result:
+ addr = result.group(1)
+ print "%s matched rule id %d" % (addr, rule_id)
+ log['time'] = int(round(time.time()))
+ log['priority'] = "warn"
+ log['message'] = "%s matched rule id %d" % (addr, rule_id)
+ r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
+ ban(addr)
def autopurge():
while not quit_now:
BAN_TIME = int(r.get("F2B_BAN_TIME"))
MAX_ATTEMPTS = int(r.get("F2B_MAX_ATTEMPTS"))
QUEUE_UNBAN = r.hgetall("F2B_QUEUE_UNBAN")
if QUEUE_UNBAN:
for net in QUEUE_UNBAN:
unban(str(net))
for net in bans.copy():
if bans[net]['attempts'] >= MAX_ATTEMPTS:
if time.time() - bans[net]['last_attempt'] > BAN_TIME:
unban(net)
- time.sleep(30)
+ time.sleep(10)
if __name__ == '__main__':
- threads = []
- for container in RULES:
- threads.append(Thread(target=watch, args=(container,)))
- threads[-1].daemon = True
- threads[-1].start()
+
+ watch_thread = Thread(target=watch)
+ watch_thread.daemon = True
+ watch_thread.start()
autopurge_thread = Thread(target=autopurge)
autopurge_thread.daemon = True
autopurge_thread.start()
signal.signal(signal.SIGTERM, quit)
atexit.register(clear)
while not quit_now:
- for thread in threads:
- if not thread.isAlive():
- break
- time.sleep(0.1)
-
- clear()
+ time.sleep(0.5)
diff --git a/data/Dockerfiles/postfix/syslog-ng.conf b/data/Dockerfiles/postfix/syslog-ng.conf
index 2c1fce88..5aa18ac5 100644
--- a/data/Dockerfiles/postfix/syslog-ng.conf
+++ b/data/Dockerfiles/postfix/syslog-ng.conf
@@ -1,31 +1,41 @@
@version: 3.8
@include "scl.conf"
options {
chain_hostnames(off);
flush_lines(0);
use_dns(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
internal();
};
destination d_combined { file("/var/log/combined.log"); };
-destination d_redis {
+destination d_redis_persistent_log {
redis(
host("redis-mailcow")
+ persist-name("redis1")
port(6379)
- command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
+ command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
-filter f_mail { facility(mail) and not filter(f_debug); };
+destination d_redis_f2b_channel {
+ redis(
+ host("redis-mailcow")
+ persist-name("redis2")
+ port(6379)
+ command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
+ );
+};
+filter f_mail { facility(mail); };
log {
source(s_src);
destination(d_combined);
filter(f_mail);
- destination(d_redis);
+ destination(d_redis_persistent_log);
+ destination(d_redis_f2b_channel);
};
diff --git a/data/Dockerfiles/sogo/syslog-ng.conf b/data/Dockerfiles/sogo/syslog-ng.conf
index 6e9ba2a2..1e97345a 100644
--- a/data/Dockerfiles/sogo/syslog-ng.conf
+++ b/data/Dockerfiles/sogo/syslog-ng.conf
@@ -1,37 +1,45 @@
@version: 3.5
@include "scl.conf"
options {
chain_hostnames(off);
flush_lines(0);
use_dns(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
internal();
};
source s_sogo {
file("/var/log/sogo/sogo.log");
};
destination d_combined {
file("/var/log/combined.log");
};
-destination d_redis {
+destination d_redis_persistent_log {
redis(
host("redis-mailcow")
port(6379)
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
+destination d_redis_f2b_channel {
+ redis(
+ host("redis-mailcow")
+ port(6379)
+ command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
+ );
+};
log {
source(s_sogo);
source(s_src);
destination(d_combined);
};
log {
source(s_sogo);
- destination(d_redis);
+ destination(d_redis_persistent_log);
+ destination(d_redis_f2b_channel);
};
diff --git a/docker-compose.yml b/docker-compose.yml
index cfd5a4ec..8c1f62f5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,370 +1,370 @@
version: '2.1'
services:
unbound-mailcow:
image: mailcow/unbound:1.0
build: ./data/Dockerfiles/unbound
command: /usr/sbin/unbound
depends_on:
mysql-mailcow:
condition: service_healthy
healthcheck:
test: ["CMD", "nslookup", "mailcow.email", "127.0.0.1"]
interval: 30s
timeout: 7s
retries: 10
volumes:
- ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
restart: always
networks:
mailcow-network:
ipv4_address: 172.22.1.254
aliases:
- unbound
mysql-mailcow:
image: mariadb:10.1
command: mysqld --max_allowed_packet=128M
healthcheck:
test: ["CMD", "mysqladmin", "ping", "--host", "localhost", "--silent"]
interval: 10s
timeout: 7s
retries: 10
volumes:
- mysql-vol-1:/var/lib/mysql/
- ./data/conf/mysql/:/etc/mysql/conf.d/:ro
environment:
- MYSQL_ROOT_PASSWORD=${DBROOT}
- MYSQL_DATABASE=${DBNAME}
- MYSQL_USER=${DBUSER}
- MYSQL_PASSWORD=${DBPASS}
restart: always
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
ipv4_address: 172.22.1.250
aliases:
- mysql
redis-mailcow:
image: redis:alpine
depends_on:
unbound-mailcow:
condition: service_healthy
volumes:
- redis-vol-1:/data/
restart: always
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
ipv4_address: 172.22.1.249
aliases:
- redis
clamd-mailcow:
image: mailcow/clamd:1.1
build: ./data/Dockerfiles/clamd
restart: always
environment:
- SKIP_CLAMD=${SKIP_CLAMD:-n}
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
aliases:
- clamd
rspamd-mailcow:
image: mailcow/rspamd:1.1
build: ./data/Dockerfiles/rspamd
command: >
/bin/bash -c "
sleep 5;
/usr/bin/rspamd -f -u _rspamd -g _rspamd
"
depends_on:
- nginx-mailcow
volumes:
- ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:ro
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro
- ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro
- dkim-vol-1:/data/dkim
- rspamd-vol-1:/var/lib/rspamd
restart: always
logging:
options:
max-size: "5m"
dns:
- 172.22.1.254
dns_search: mailcow-network
hostname: rspamd
networks:
mailcow-network:
ipv4_address: 172.22.1.253
aliases:
- rspamd
php-fpm-mailcow:
image: mailcow/phpfpm:1.0
build: ./data/Dockerfiles/phpfpm
command: "php-fpm -d date.timezone=${TZ}"
depends_on:
- redis-mailcow
volumes:
- ./data/web:/web:ro
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
- dkim-vol-1:/data/dkim
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IMAP_PORT=${IMAP_PORT:-143}
- IMAPS_PORT=${IMAPS_PORT:-993}
- POP_PORT=${POP_PORT:-110}
- POPS_PORT=${POPS_PORT:-995}
- SIEVE_PORT=${SIEVE_PORT:-4190}
- SUBMISSION_PORT=${SUBMISSION_PORT:-587}
- SMTPS_PORT=${SMTPS_PORT:-465}
- SMTP_PORT=${SMTP_PORT:-25}
restart: always
logging:
options:
max-size: "5m"
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
aliases:
- phpfpm
sogo-mailcow:
image: mailcow/sogo:1.1
build: ./data/Dockerfiles/sogo
depends_on:
unbound-mailcow:
condition: service_healthy
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- TZ=${TZ}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
volumes:
- ./data/conf/sogo/:/etc/sogo/
- ./data/web/thunderbird-plugins:/thunderbird
restart: always
logging:
options:
max-size: "5m"
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
ipv4_address: 172.22.1.252
aliases:
- sogo
dovecot-mailcow:
image: mailcow/dovecot:1.2
build: ./data/Dockerfiles/dovecot
depends_on:
unbound-mailcow:
condition: service_healthy
volumes:
- ./data/conf/dovecot:/usr/local/etc/dovecot
- ./data/assets/ssl:/etc/ssl/mail/:ro
- ./data/conf/sogo/:/etc/sogo/
- vmail-vol-1:/var/vmail
- crypt-vol-1:/mail_crypt/
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
logging:
options:
max-size: "5m"
ports:
- "${IMAP_PORT:-143}:143"
- "${IMAPS_PORT:-993}:993"
- "${POP_PORT:-110}:110"
- "${POPS_PORT:-995}:995"
- "${SIEVE_PORT:-4190}:4190"
restart: always
dns:
- 172.22.1.254
dns_search: mailcow-network
hostname: ${MAILCOW_HOSTNAME}
networks:
mailcow-network:
aliases:
- dovecot
postfix-mailcow:
image: mailcow/postfix:1.1
build: ./data/Dockerfiles/postfix
depends_on:
unbound-mailcow:
condition: service_healthy
volumes:
- ./data/conf/postfix:/opt/postfix/conf
- ./data/assets/ssl:/etc/ssl/mail/:ro
- postfix-vol-1:/var/spool/postfix
- crypt-vol-1:/var/lib/zeyple
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
ports:
- "${SMTP_PORT:-25}:25"
- "${SMTPS_PORT:-465}:465"
- "${SUBMISSION_PORT:-587}:587"
restart: always
logging:
options:
max-size: "5m"
dns:
- 172.22.1.254
dns_search: mailcow-network
hostname: ${MAILCOW_HOSTNAME}
networks:
mailcow-network:
aliases:
- postfix
memcached-mailcow:
image: memcached:alpine
depends_on:
unbound-mailcow:
condition: service_healthy
restart: always
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
aliases:
- memcached
nginx-mailcow:
depends_on:
- sogo-mailcow
- php-fpm-mailcow
image: nginx:mainline-alpine
healthcheck:
test: ["CMD", "ping", "php-fpm-mailcow", "-c", "10"]
interval: 10s
timeout: 30s
retries: 5
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
nginx -g 'daemon off;'"
environment:
- HTTPS_PORT=${HTTPS_PORT:-443}
- HTTP_PORT=${HTTP_PORT:-80}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
volumes:
- ./data/web:/web:ro
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
- ./data/assets/ssl/:/etc/ssl/mail/:ro
- ./data/conf/nginx/:/etc/nginx/conf.d/:rw
logging:
options:
max-size: "5m"
ports:
- "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}"
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
restart: always
dns:
- 172.22.1.254
dns_search: mailcow-network
networks:
mailcow-network:
ipv4_address: 172.22.1.251
aliases:
- nginx
acme-mailcow:
depends_on:
- nginx-mailcow
image: mailcow/acme:1.11
build: ./data/Dockerfiles/acme
dns:
- 172.22.1.254
dns_search: mailcow-network
environment:
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n}
- SKIP_IP_CHECK=${SKIP_IP_CHECK:-n}
volumes:
- ./data/web/.well-known/acme-challenge:/var/www/acme:rw
- ./data/assets/ssl:/var/lib/acme/:rw
- ./data/assets/ssl-example:/var/lib/ssl-example/:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
# do not restart the container too often. Things get worse when we hit let's encrypt's ratelimit.
restart: on-failure:1
networks:
mailcow-network:
aliases:
- acme
fail2ban-mailcow:
image: mailcow/fail2ban:1.5
build: ./data/Dockerfiles/fail2ban
depends_on:
- dovecot-mailcow
- postfix-mailcow
- sogo-mailcow
- php-fpm-mailcow
- redis-mailcow
restart: always
privileged: true
environment:
- TZ=${TZ}
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no}
network_mode: "host"
dns:
- 172.22.1.254
dns_search: mailcow-network
volumes:
- - /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
+
ipv6nat:
image: robbertkl/ipv6nat
restart: always
privileged: true
network_mode: "host"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
networks:
mailcow-network:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.22.1.0/24
- subnet: fd4d:6169:6c63:6f77::/64
volumes:
vmail-vol-1:
mysql-vol-1:
dkim-vol-1:
redis-vol-1:
rspamd-vol-1:
postfix-vol-1:
crypt-vol-1:
File Metadata
详情
附加的
Mime Type
text/x-diff
Expires
9月 11 Thu, 1:42 PM (1 d, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5554
默认替代文本
(23 KB)
Attached To
Mode
rMAILCOW mailcow-tracking
附加的
Detach File
Event Timeline
Log In to Comment