Merge branch 'master' of https://github.com/andryyy/mailcow-dockerized into recipient_map
Conflicts: data/web/inc/init_db.inc.phpmaster
commit
c30448c4d8
|
@ -6,20 +6,38 @@ LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
COPY dl_files.sh bootstrap.sh ./
|
COPY dl_files.sh bootstrap.sh ./
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
RUN apk add --update \
|
ENV CLAMAV 0.99.3
|
||||||
&& apk add --no-cache clamav clamav-libunrar curl bash tini \
|
|
||||||
|
RUN apk add --no-cache --virtual build-dependencies alpine-sdk ncurses-dev zlib-dev bzip2-dev pcre-dev linux-headers fts-dev libxml2-dev libressl-dev \
|
||||||
|
&& apk add --no-cache curl bash tini libxml2 libbz2 pcre fts libressl \
|
||||||
|
&& wget -O - https://www.clamav.net/downloads/production/clamav-${CLAMAV}.tar.gz | tar xfvz - \
|
||||||
|
&& cd clamav-${CLAMAV} \
|
||||||
|
&& LIBS=-lfts ./configure \
|
||||||
|
--prefix=/usr \
|
||||||
|
--libdir=/usr/lib \
|
||||||
|
--sysconfdir=/etc/clamav \
|
||||||
|
--mandir=/usr/share/man \
|
||||||
|
--infodir=/usr/share/info \
|
||||||
|
--without-iconv \
|
||||||
|
--disable-llvm \
|
||||||
|
--with-user=clamav \
|
||||||
|
--with-group=clamav \
|
||||||
|
--with-dbdir=/var/lib/clamav \
|
||||||
|
--enable-clamdtop \
|
||||||
|
--enable-bigstack \
|
||||||
|
--with-pcre \
|
||||||
|
&& make -j4 \
|
||||||
|
&& make install \
|
||||||
|
&& make clean \
|
||||||
|
&& cd .. && rm -rf clamav-${CLAMAV} \
|
||||||
|
&& apk del build-dependencies \
|
||||||
|
&& addgroup -S clamav \
|
||||||
|
&& adduser -S -D -h /var/lib/clamav -s /sbin/nologin -G clamav -g clamav clamav \
|
||||||
|
&& mkdir -p /run/clamav \
|
||||||
|
&& chown clamav:clamav /run/clamav \
|
||||||
&& chmod +x /dl_files.sh \
|
&& chmod +x /dl_files.sh \
|
||||||
&& set -ex; /bin/bash /dl_files.sh \
|
&& set -ex; /bin/bash /dl_files.sh \
|
||||||
&& mkdir /run/clamav \
|
&& chmod 750 /run/clamav
|
||||||
&& chown clamav:clamav /run/clamav \
|
|
||||||
&& chmod 750 /run/clamav \
|
|
||||||
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/clamd.conf \
|
|
||||||
&& sed -i '/TCPSocket 3310/s/^#//g' /etc/clamav/clamd.conf \
|
|
||||||
&& sed -i 's#LogFile /var/log/clamav/clamd.log#LogFile /tmp/logpipe_clamd#g' /etc/clamav/clamd.conf \
|
|
||||||
&& sed -i 's/#PhishingSignatures yes/PhishingSignatures no/g' /etc/clamav/clamd.conf \
|
|
||||||
&& sed -i 's/#PhishingScanURLs yes/PhishingScanURLs no/g' /etc/clamav/clamd.conf \
|
|
||||||
&& sed -i 's#UpdateLogFile /var/log/clamav/freshclam.log#UpdateLogFile /tmp/logpipe_freshclam#g' /etc/clamav/freshclam.conf \
|
|
||||||
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/freshclam.conf
|
|
||||||
|
|
||||||
# Port provision
|
# Port provision
|
||||||
EXPOSE 3310
|
EXPOSE 3310
|
||||||
|
|
|
@ -33,7 +33,7 @@ open my $file, '<', "/etc/sogo/sieve.creds";
|
||||||
my $creds = <$file>;
|
my $creds = <$file>;
|
||||||
close $file;
|
close $file;
|
||||||
my ($master_user, $master_pass) = split /:/, $creds;
|
my ($master_user, $master_pass) = split /:/, $creds;
|
||||||
my $sth = $dbh->prepare("SELECT id, user1, user2, host1, authmech1, password1, exclude, port1, enc1, delete2duplicates, maxage, subfolder2, delete1, delete2 FROM imapsync WHERE active = 1 AND (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(last_run) > mins_interval * 60 OR last_run IS NULL) ORDER BY last_run");
|
my $sth = $dbh->prepare("SELECT id, user1, user2, host1, authmech1, password1, exclude, port1, enc1, delete2duplicates, maxage, subfolder2, delete1, delete2, automap, skipcrossduplicates, maxbytespersecond FROM imapsync WHERE active = 1 AND (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(last_run) > mins_interval * 60 OR last_run IS NULL) ORDER BY last_run");
|
||||||
$sth->execute();
|
$sth->execute();
|
||||||
my $row;
|
my $row;
|
||||||
|
|
||||||
|
@ -53,6 +53,9 @@ while ($row = $sth->fetchrow_arrayref()) {
|
||||||
$subfolder2 = @$row[11];
|
$subfolder2 = @$row[11];
|
||||||
$delete1 = @$row[12];
|
$delete1 = @$row[12];
|
||||||
$delete2 = @$row[13];
|
$delete2 = @$row[13];
|
||||||
|
$automap = @$row[14];
|
||||||
|
$skipcrossduplicates = @$row[15];
|
||||||
|
$maxbytespersecond = @$row[16];
|
||||||
|
|
||||||
$is_running = $dbh->prepare("UPDATE imapsync SET is_running = 1 WHERE id = ?");
|
$is_running = $dbh->prepare("UPDATE imapsync SET is_running = 1 WHERE id = ?");
|
||||||
$is_running->bind_param( 1, ${id} );
|
$is_running->bind_param( 1, ${id} );
|
||||||
|
@ -74,9 +77,12 @@ while ($row = $sth->fetchrow_arrayref()) {
|
||||||
($exclude eq "" ? () : ("--exclude", $exclude)),
|
($exclude eq "" ? () : ("--exclude", $exclude)),
|
||||||
($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)),
|
($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)),
|
||||||
($maxage eq "0" ? () : ('--maxage', $maxage)),
|
($maxage eq "0" ? () : ('--maxage', $maxage)),
|
||||||
|
($maxbytespersecond eq "0" ? () : ('--maxbytespersecond', $maxage)),
|
||||||
($delete2duplicates ne "1" ? () : ('--delete2duplicates')),
|
($delete2duplicates ne "1" ? () : ('--delete2duplicates')),
|
||||||
($delete1 ne "1" ? () : ('--delete')),
|
($delete1 ne "1" ? () : ('--delete')),
|
||||||
($delete2 ne "1" ? () : ('--delete2')),
|
($delete2 ne "1" ? () : ('--delete2')),
|
||||||
|
($automap ne "1" ? () : ('--automap')),
|
||||||
|
($skipcrossduplicates ne "1" ? () : ('--skipcrossduplicates')),
|
||||||
(!defined($enc1) ? () : ($enc1)),
|
(!defined($enc1) ? () : ($enc1)),
|
||||||
"--host1", $host1,
|
"--host1", $host1,
|
||||||
"--user1", $user1,
|
"--user1", $user1,
|
||||||
|
|
|
@ -14,11 +14,11 @@ import json
|
||||||
|
|
||||||
yes_regex = re.compile(r'([yY][eE][sS]|[yY])+$')
|
yes_regex = re.compile(r'([yY][eE][sS]|[yY])+$')
|
||||||
if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
|
if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
|
||||||
print "SKIP_FAIL2BAN=y, Skipping Fail2ban container..."
|
print 'SKIP_FAIL2BAN=y, Skipping Fail2ban container...'
|
||||||
time.sleep(31536000)
|
time.sleep(31536000)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0)
|
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0)
|
||||||
pubsub = r.pubsub()
|
pubsub = r.pubsub()
|
||||||
|
|
||||||
RULES = {}
|
RULES = {}
|
||||||
|
@ -29,19 +29,23 @@ RULES[4] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=(
|
||||||
RULES[5] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
RULES[5] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||||
RULES[6] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
RULES[6] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||||
|
|
||||||
r.setnx("F2B_BAN_TIME", "1800")
|
r.setnx('F2B_BAN_TIME', '1800')
|
||||||
r.setnx("F2B_MAX_ATTEMPTS", "10")
|
r.setnx('F2B_MAX_ATTEMPTS', '10')
|
||||||
r.setnx("F2B_RETRY_WINDOW", "600")
|
r.setnx('F2B_RETRY_WINDOW', '600')
|
||||||
|
r.setnx('F2B_NETBAN_IPV6', '64')
|
||||||
|
r.setnx('F2B_NETBAN_IPV4', '24')
|
||||||
|
|
||||||
bans = {}
|
bans = {}
|
||||||
log = {}
|
log = {}
|
||||||
quit_now = False
|
quit_now = False
|
||||||
|
|
||||||
def ban(address):
|
def ban(address):
|
||||||
BAN_TIME = int(r.get("F2B_BAN_TIME"))
|
BAN_TIME = int(r.get('F2B_BAN_TIME'))
|
||||||
MAX_ATTEMPTS = int(r.get("F2B_MAX_ATTEMPTS"))
|
MAX_ATTEMPTS = int(r.get('F2B_MAX_ATTEMPTS'))
|
||||||
RETRY_WINDOW = int(r.get("F2B_RETRY_WINDOW"))
|
RETRY_WINDOW = int(r.get('F2B_RETRY_WINDOW'))
|
||||||
WHITELIST = r.hgetall("F2B_WHITELIST")
|
WHITELIST = r.hgetall('F2B_WHITELIST')
|
||||||
|
NETBAN_IPV6 = '/' + str(r.get('F2B_NETBAN_IPV6'))
|
||||||
|
NETBAN_IPV4 = '/' + str(r.get('F2B_NETBAN_IPV4'))
|
||||||
|
|
||||||
ip = ipaddress.ip_address(address.decode('ascii'))
|
ip = ipaddress.ip_address(address.decode('ascii'))
|
||||||
if type(ip) is ipaddress.IPv6Address and ip.ipv4_mapped:
|
if type(ip) is ipaddress.IPv6Address and ip.ipv4_mapped:
|
||||||
|
@ -56,13 +60,13 @@ def ban(address):
|
||||||
wl_net = ipaddress.ip_network(wl_key.decode('ascii'), False)
|
wl_net = ipaddress.ip_network(wl_key.decode('ascii'), False)
|
||||||
if wl_net.overlaps(self_network):
|
if wl_net.overlaps(self_network):
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "info"
|
log['priority'] = 'info'
|
||||||
log['message'] = "Address %s is whitelisted by rule %s" % (self_network, wl_net)
|
log['message'] = 'Address %s is whitelisted by rule %s' % (self_network, wl_net)
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print "Address %s is whitelisted by rule %s" % (self_network, wl_net)
|
print 'Address %s is whitelisted by rule %s' % (self_network, wl_net)
|
||||||
return
|
return
|
||||||
|
|
||||||
net = ipaddress.ip_network((address + ('/24' if type(ip) is ipaddress.IPv4Address else '/64')).decode('ascii'), strict=False)
|
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)).decode('ascii'), strict=False)
|
||||||
net = str(net)
|
net = str(net)
|
||||||
|
|
||||||
if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW:
|
if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW:
|
||||||
|
@ -78,45 +82,45 @@ def ban(address):
|
||||||
|
|
||||||
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
if bans[net]['attempts'] >= MAX_ATTEMPTS:
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "crit"
|
log['priority'] = 'crit'
|
||||||
log['message'] = "Banning %s" % net
|
log['message'] = 'Banning %s' % net
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print "Banning %s for %d minutes" % (net, BAN_TIME / 60)
|
print 'Banning %s for %d minutes' % (net, BAN_TIME / 60)
|
||||||
if type(ip) is ipaddress.IPv4Address:
|
if type(ip) is ipaddress.IPv4Address:
|
||||||
subprocess.call(["iptables", "-I", "INPUT", "-s", net, "-j", "REJECT"])
|
subprocess.call(['iptables', '-I', 'INPUT', '-s', net, '-j', 'REJECT'])
|
||||||
subprocess.call(["iptables", "-I", "FORWARD", "-s", net, "-j", "REJECT"])
|
subprocess.call(['iptables', '-I', 'FORWARD', '-s', net, '-j', 'REJECT'])
|
||||||
else:
|
else:
|
||||||
subprocess.call(["ip6tables", "-I", "INPUT", "-s", net, "-j", "REJECT"])
|
subprocess.call(['ip6tables', '-I', 'INPUT', '-s', net, '-j', 'REJECT'])
|
||||||
subprocess.call(["ip6tables", "-I", "FORWARD", "-s", net, "-j", "REJECT"])
|
subprocess.call(['ip6tables', '-I', 'FORWARD', '-s', net, '-j', 'REJECT'])
|
||||||
r.hset("F2B_ACTIVE_BANS", "%s" % net, log['time'] + BAN_TIME)
|
r.hset('F2B_ACTIVE_BANS', '%s' % net, log['time'] + BAN_TIME)
|
||||||
else:
|
else:
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "warn"
|
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)
|
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))
|
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)
|
print '%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)
|
||||||
|
|
||||||
def unban(net):
|
def unban(net):
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "info"
|
log['priority'] = 'info'
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
if not net in bans:
|
if not net in bans:
|
||||||
log['message'] = "%s is not banned, skipping unban and deleting from queue (if any)" % net
|
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))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print "%s is not banned, skipping unban and deleting from queue (if any)" % net
|
print '%s is not banned, skipping unban and deleting from queue (if any)' % net
|
||||||
r.hdel("F2B_QUEUE_UNBAN", "%s" % net)
|
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
return
|
return
|
||||||
log['message'] = "Unbanning %s" % net
|
log['message'] = 'Unbanning %s' % net
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print "Unbanning %s" % net
|
print 'Unbanning %s' % net
|
||||||
if type(ipaddress.ip_network(net.decode('ascii'))) is ipaddress.IPv4Network:
|
if type(ipaddress.ip_network(net.decode('ascii'))) is ipaddress.IPv4Network:
|
||||||
subprocess.call(["iptables", "-D", "INPUT", "-s", net, "-j", "REJECT"])
|
subprocess.call(['iptables', '-D', 'INPUT', '-s', net, '-j', 'REJECT'])
|
||||||
subprocess.call(["iptables", "-D", "FORWARD", "-s", net, "-j", "REJECT"])
|
subprocess.call(['iptables', '-D', 'FORWARD', '-s', net, '-j', 'REJECT'])
|
||||||
else:
|
else:
|
||||||
subprocess.call(["ip6tables", "-D", "INPUT", "-s", net, "-j", "REJECT"])
|
subprocess.call(['ip6tables', '-D', 'INPUT', '-s', net, '-j', 'REJECT'])
|
||||||
subprocess.call(["ip6tables", "-D", "FORWARD", "-s", net, "-j", "REJECT"])
|
subprocess.call(['ip6tables', '-D', 'FORWARD', '-s', net, '-j', 'REJECT'])
|
||||||
r.hdel("F2B_ACTIVE_BANS", "%s" % net)
|
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||||
r.hdel("F2B_QUEUE_UNBAN", "%s" % net)
|
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
del bans[net]
|
del bans[net]
|
||||||
|
|
||||||
def quit(signum, frame):
|
def quit(signum, frame):
|
||||||
|
@ -125,21 +129,21 @@ def quit(signum, frame):
|
||||||
|
|
||||||
def clear():
|
def clear():
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "info"
|
log['priority'] = 'info'
|
||||||
log['message'] = "Clearing all bans"
|
log['message'] = 'Clearing all bans'
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
print "Clearing all bans"
|
print 'Clearing all bans'
|
||||||
for net in bans.copy():
|
for net in bans.copy():
|
||||||
unban(net)
|
unban(net)
|
||||||
pubsub.unsubscribe()
|
pubsub.unsubscribe()
|
||||||
|
|
||||||
def watch():
|
def watch():
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "info"
|
log['priority'] = 'info'
|
||||||
log['message'] = "Watching Redis channel F2B_CHANNEL"
|
log['message'] = 'Watching Redis channel F2B_CHANNEL'
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
pubsub.subscribe("F2B_CHANNEL")
|
pubsub.subscribe('F2B_CHANNEL')
|
||||||
print "Subscribing to Redis channel F2B_CHANNEL"
|
print 'Subscribing to Redis channel F2B_CHANNEL'
|
||||||
while True:
|
while True:
|
||||||
for item in pubsub.listen():
|
for item in pubsub.listen():
|
||||||
for rule_id, rule_regex in RULES.iteritems():
|
for rule_id, rule_regex in RULES.iteritems():
|
||||||
|
@ -150,18 +154,18 @@ def watch():
|
||||||
ip = ipaddress.ip_address(addr.decode('ascii'))
|
ip = ipaddress.ip_address(addr.decode('ascii'))
|
||||||
if ip.is_private or ip.is_loopback:
|
if ip.is_private or ip.is_loopback:
|
||||||
continue
|
continue
|
||||||
print "%s matched rule id %d" % (addr, rule_id)
|
print '%s matched rule id %d' % (addr, rule_id)
|
||||||
log['time'] = int(round(time.time()))
|
log['time'] = int(round(time.time()))
|
||||||
log['priority'] = "warn"
|
log['priority'] = 'warn'
|
||||||
log['message'] = "%s matched rule id %d" % (addr, rule_id)
|
log['message'] = '%s matched rule id %d' % (addr, rule_id)
|
||||||
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
|
r.lpush('F2B_LOG', json.dumps(log, ensure_ascii=False))
|
||||||
ban(addr)
|
ban(addr)
|
||||||
|
|
||||||
def autopurge():
|
def autopurge():
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
BAN_TIME = int(r.get("F2B_BAN_TIME"))
|
BAN_TIME = int(r.get('F2B_BAN_TIME'))
|
||||||
MAX_ATTEMPTS = int(r.get("F2B_MAX_ATTEMPTS"))
|
MAX_ATTEMPTS = int(r.get('F2B_MAX_ATTEMPTS'))
|
||||||
QUEUE_UNBAN = r.hgetall("F2B_QUEUE_UNBAN")
|
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
|
||||||
if QUEUE_UNBAN:
|
if QUEUE_UNBAN:
|
||||||
for net in QUEUE_UNBAN:
|
for net in QUEUE_UNBAN:
|
||||||
unban(str(net))
|
unban(str(net))
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
FROM php:7.1-fpm-alpine
|
FROM php:7.1-fpm-alpine
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ENV REDIS_PECL 3.1.4
|
ENV REDIS_PECL 3.1.6
|
||||||
ENV MEMCACHED_PECL 3.0.3
|
ENV MEMCACHED_PECL 3.0.4
|
||||||
ENV APCU_PECL 5.1.8
|
ENV APCU_PECL 5.1.9
|
||||||
ENV IMAGICK_PECL 3.4.3
|
ENV IMAGICK_PECL 3.4.3
|
||||||
|
ENV MAILPARSE_PECL 3.0.2
|
||||||
|
|
||||||
RUN apk add -U --no-cache libxml2-dev \
|
RUN apk add -U --no-cache libxml2-dev \
|
||||||
icu-dev \
|
icu-dev \
|
||||||
|
@ -41,27 +42,16 @@ RUN apk add -U --no-cache libxml2-dev \
|
||||||
Net_Sieve \
|
Net_Sieve \
|
||||||
NET_SMTP \
|
NET_SMTP \
|
||||||
Mail_mime \
|
Mail_mime \
|
||||||
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} mailparse \
|
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} mailparse-${MAILPARSE_PECL} \
|
||||||
&& docker-php-ext-enable redis apcu memcached imagick mailparse \
|
&& docker-php-ext-enable redis apcu memcached imagick mailparse \
|
||||||
&& pecl clear-cache \
|
&& pecl clear-cache \
|
||||||
&& docker-php-ext-configure intl \
|
&& docker-php-ext-configure intl \
|
||||||
&& docker-php-ext-install -j 4 intl gettext ldap sockets soap pdo pdo_mysql xmlrpc gd zip pcntl opcache \
|
&& docker-php-ext-install -j 4 intl gettext ldap sockets soap pdo pdo_mysql xmlrpc gd zip pcntl opcache \
|
||||||
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
||||||
&& docker-php-ext-install -j 4 imap \
|
&& docker-php-ext-install -j 4 imap \
|
||||||
&& apk del --purge autoconf g++ make libxml2-dev icu-dev imap-dev openssl-dev cyrus-sasl-dev pcre-dev libpng-dev libpng-dev libjpeg-turbo-dev libwebp-dev zlib-dev imagemagick-dev \
|
&& apk del --purge autoconf g++ make libxml2-dev icu-dev imap-dev openssl-dev cyrus-sasl-dev pcre-dev libpng-dev libpng-dev libjpeg-turbo-dev libwebp-dev zlib-dev imagemagick-dev
|
||||||
&& { \
|
|
||||||
echo 'opcache.enable=1'; \
|
|
||||||
echo 'opcache.enable_cli=1'; \
|
|
||||||
echo 'opcache.interned_strings_buffer=8'; \
|
|
||||||
echo 'opcache.max_accelerated_files=10000'; \
|
|
||||||
echo 'opcache.memory_consumption=128'; \
|
|
||||||
echo 'opcache.save_comments=1'; \
|
|
||||||
echo 'opcache.revalidate_freq=1'; \
|
|
||||||
} > /usr/local/etc/php/conf.d/opcache-recommended.ini
|
|
||||||
|
|
||||||
COPY ./docker-entrypoint.sh /
|
COPY ./docker-entrypoint.sh /
|
||||||
|
|
||||||
EXPOSE 9000
|
|
||||||
|
|
||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
CMD ["php-fpm"]
|
CMD ["php-fpm"]
|
||||||
|
|
|
@ -26,7 +26,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
syslog-ng-core \
|
syslog-ng-core \
|
||||||
syslog-ng-mod-redis \
|
syslog-ng-mod-redis \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& touch /etc/default/locale
|
&& touch /etc/default/locale \
|
||||||
|
&& printf '#!/bin/bash\n/usr/sbin/postconf -c /opt/postfix/conf "$@"' > /usr/local/sbin/postconf \
|
||||||
|
&& chmod +x /usr/local/sbin/postconf
|
||||||
|
|
||||||
RUN addgroup --system --gid 600 zeyple
|
RUN addgroup --system --gid 600 zeyple
|
||||||
RUN adduser --system --home /var/lib/zeyple --no-create-home --uid 600 --gid 600 --disabled-login zeyple
|
RUN adduser --system --home /var/lib/zeyple --no-create-home --uid 600 --gid 600 --disabled-login zeyple
|
||||||
|
|
|
@ -6,7 +6,7 @@ while read QUERY; do
|
||||||
echo "500 dunno"
|
echo "500 dunno"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
result=$(curl -s http://172.22.1.251:8081/forwardinghosts.php?host=${QUERY[1]})
|
result=$(curl -s http://nginx:8081/forwardinghosts.php?host=${QUERY[1]})
|
||||||
logger -t whitelist_forwardinghosts -p mail.info "Look up ${QUERY[1]} on whitelist, result $result"
|
logger -t whitelist_forwardinghosts -p mail.info "Look up ${QUERY[1]} on whitelist, result $result"
|
||||||
echo ${result}
|
echo ${result}
|
||||||
done
|
done
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
settings = "http://172.22.1.251:8081/settings.php";
|
settings = "http://nginx:8081/settings.php";
|
||||||
|
|
|
@ -18,11 +18,13 @@ done
|
||||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
||||||
|
|
||||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, home, kind, multiple_bookings) AS
|
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, sa_aliases, ad_aliases, home, kind, multiple_bookings) AS
|
||||||
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox
|
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(GROUP_CONCAT(ga.aliases SEPARATOR ' '), ''), IFNULL(gsa.send_as_acl, ''), IFNULL(gda.ad_alias, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox
|
||||||
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
|
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)')
|
||||||
|
LEFT OUTER JOIN grouped_sender_acl gsa ON gsa.username = mailbox.username
|
||||||
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
||||||
WHERE mailbox.active = '1';
|
WHERE mailbox.active = '1'
|
||||||
|
GROUP BY mailbox.username;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ while read line
|
||||||
<key>MailFieldNames</key>
|
<key>MailFieldNames</key>
|
||||||
<array>
|
<array>
|
||||||
<string>aliases</string>
|
<string>aliases</string>
|
||||||
|
<string>sa_aliases</string>
|
||||||
<string>ad_aliases</string>
|
<string>ad_aliases</string>
|
||||||
</array>
|
</array>
|
||||||
<key>KindFieldName</key>
|
<key>KindFieldName</key>
|
||||||
|
|
|
@ -191,6 +191,7 @@ phpfpm_checks() {
|
||||||
host_ip=$(get_container_ip php-fpm-mailcow)
|
host_ip=$(get_container_ip php-fpm-mailcow)
|
||||||
err_c_cur=${err_count}
|
err_c_cur=${err_count}
|
||||||
cgi-fcgi -bind -connect ${host_ip}:9000 | grep "Content-type" 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
cgi-fcgi -bind -connect ${host_ip}:9000 | grep "Content-type" 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
|
cgi-fcgi -bind -connect ${host_ip}:9001 | grep "Content-type" 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
/usr/lib/nagios/plugins/check_ping -4 -H ${host_ip} -w 2000,10% -c 4000,100% -p2 1>&2; err_count=$(( ${err_count} + $? ))
|
/usr/lib/nagios/plugins/check_ping -4 -H ${host_ip} -w 2000,10% -c 4000,100% -p2 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
|
|
@ -25,7 +25,7 @@ server {
|
||||||
add_header X-Download-Options noopen;
|
add_header X-Download-Options noopen;
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
server_name NC_SERVER_SUB;
|
server_name NC_SUBD;
|
||||||
|
|
||||||
root /web/nextcloud/;
|
root /web/nextcloud/;
|
||||||
|
|
||||||
|
@ -38,18 +38,26 @@ server {
|
||||||
location = /.well-known/carddav {
|
location = /.well-known/carddav {
|
||||||
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
}
|
}
|
||||||
|
|
||||||
location = /.well-known/caldav {
|
location = /.well-known/caldav {
|
||||||
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
default_type "text/plain";
|
||||||
|
root /web;
|
||||||
|
}
|
||||||
|
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
gzip_comp_level 4;
|
gzip_comp_level 4;
|
||||||
gzip_min_length 256;
|
gzip_min_length 256;
|
||||||
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
||||||
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
||||||
|
set_real_ip_from fd00::/8;
|
||||||
set_real_ip_from 172.22.1.1;
|
set_real_ip_from 10.0.0.0/8;
|
||||||
|
set_real_ip_from 172.16.0.0/12;
|
||||||
|
set_real_ip_from 192.168.0.0/16;
|
||||||
real_ip_header X-Forwarded-For;
|
real_ip_header X-Forwarded-For;
|
||||||
real_ip_recursive on;
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
@ -100,88 +108,3 @@ server {
|
||||||
access_log off;
|
access_log off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server {
|
|
||||||
include /etc/nginx/conf.d/listen_ssl.active;
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
charset utf-8;
|
|
||||||
override_charset on;
|
|
||||||
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
add_header X-Robots-Tag none;
|
|
||||||
add_header X-Download-Options noopen;
|
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
|
||||||
|
|
||||||
server_name NC_SERVER_SUB;
|
|
||||||
|
|
||||||
root /web/nextcloud/;
|
|
||||||
|
|
||||||
location = /robots.txt {
|
|
||||||
allow all;
|
|
||||||
log_not_found off;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /.well-known/carddav {
|
|
||||||
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
|
||||||
}
|
|
||||||
location = /.well-known/caldav {
|
|
||||||
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
|
||||||
}
|
|
||||||
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_comp_level 4;
|
|
||||||
gzip_min_length 256;
|
|
||||||
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
|
||||||
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
|
||||||
|
|
||||||
set_real_ip_from 172.22.1.1;
|
|
||||||
real_ip_header X-Forwarded-For;
|
|
||||||
real_ip_recursive on;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
rewrite ^ /index.php$uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
|
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
|
||||||
include fastcgi_params;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
|
||||||
fastcgi_param modHeadersAvailable true;
|
|
||||||
fastcgi_param front_controller_active true;
|
|
||||||
fastcgi_pass phpfpm:9000;
|
|
||||||
fastcgi_intercept_errors on;
|
|
||||||
fastcgi_request_buffering off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
|
|
||||||
try_files $uri/ =404;
|
|
||||||
index index.php;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.(?:css|js|woff|svg|gif)$ {
|
|
||||||
try_files $uri /index.php$uri$is_args$args;
|
|
||||||
add_header Cache-Control "public, max-age=15778463";
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
add_header X-Robots-Tag none;
|
|
||||||
add_header X-Download-Options noopen;
|
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
|
|
||||||
try_files $uri /index.php$uri$is_args$args;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
LogFile /tmp/logpipe_clamd
|
||||||
|
LogTime yes
|
||||||
|
LogClean yes
|
||||||
|
ExtendedDetectionInfo yes
|
||||||
|
PidFile /run/clamav/clamd.pid
|
||||||
|
OfficialDatabaseOnly no
|
||||||
|
LocalSocket /run/clamav/clamd.sock
|
||||||
|
TCPSocket 3310
|
||||||
|
StreamMaxLength 25M
|
||||||
|
MaxThreads 10
|
||||||
|
ReadTimeout 10
|
||||||
|
CommandReadTimeout 3
|
||||||
|
SendBufTimeout 200
|
||||||
|
MaxQueue 80
|
||||||
|
IdleTimeout 20
|
||||||
|
SelfCheck 3600
|
||||||
|
User clamav
|
||||||
|
AllowSupplementaryGroups yes
|
||||||
|
Foreground yes
|
||||||
|
DetectPUA yes
|
||||||
|
# See https://github.com/vrtadmin/clamav-faq/blob/master/faq/faq-pua.md
|
||||||
|
#ExcludePUA NetTool
|
||||||
|
#ExcludePUA PWTool
|
||||||
|
#IncludePUA Spy
|
||||||
|
#IncludePUA Scanner
|
||||||
|
#IncludePUA RAT
|
||||||
|
AlgorithmicDetection yes
|
||||||
|
ScanOLE2 yes
|
||||||
|
OLE2BlockMacros yes
|
||||||
|
ScanPDF yes
|
||||||
|
ScanSWF yes
|
||||||
|
ScanXMLDOCS yes
|
||||||
|
ScanHWP3 yes
|
||||||
|
ScanMail yes
|
||||||
|
PhishingSignatures no
|
||||||
|
PhishingScanURLs no
|
||||||
|
HeuristicScanPrecedence yes
|
||||||
|
ScanHTML yes
|
||||||
|
ScanArchive yes
|
||||||
|
MaxScanSize 50M
|
||||||
|
MaxFileSize 25M
|
||||||
|
MaxRecursion 5
|
||||||
|
MaxFiles 200
|
||||||
|
ScanOnAccess no
|
||||||
|
Bytecode yes
|
||||||
|
BytecodeSecurity TrustSigned
|
||||||
|
BytecodeTimeout 1000
|
|
@ -0,0 +1,17 @@
|
||||||
|
UpdateLogFile /tmp/logpipe_freshclam
|
||||||
|
LogTime yes
|
||||||
|
PidFile /run/clamav/freshclam.pid
|
||||||
|
DatabaseOwner clamav
|
||||||
|
AllowSupplementaryGroups yes
|
||||||
|
DNSDatabaseInfo current.cvd.clamav.net
|
||||||
|
DatabaseMirror database.clamav.net
|
||||||
|
MaxAttempts 4
|
||||||
|
ScriptedUpdates yes
|
||||||
|
Checks 6
|
||||||
|
NotifyClamd /etc/clamav/clamd.conf
|
||||||
|
Foreground yes
|
||||||
|
ConnectTimeout 20
|
||||||
|
ReceiveTimeout 20
|
||||||
|
TestDatabases yes
|
||||||
|
Bytecode yes
|
||||||
|
|
|
@ -10,7 +10,7 @@ server {
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_pass phpfpm:9000;
|
fastcgi_pass phpfpm:9001;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
|
|
@ -7,6 +7,13 @@ map $http_x_forwarded_proto $client_req_scheme {
|
||||||
https https;
|
https https;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
include /etc/nginx/conf.d/server_name.active;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
charset utf-8;
|
charset utf-8;
|
||||||
|
@ -17,6 +24,7 @@ server {
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
add_header X-Robots-Tag none;
|
add_header X-Robots-Tag none;
|
||||||
add_header X-Download-Options noopen;
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
index index.php index.html;
|
index index.php index.html;
|
||||||
|
@ -39,7 +47,10 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
# If behind reverse proxy, forwards the correct IP
|
# If behind reverse proxy, forwards the correct IP
|
||||||
set_real_ip_from 172.22.1.1;
|
set_real_ip_from 10.0.0.0/8;
|
||||||
|
set_real_ip_from 172.16.0.0/12;
|
||||||
|
set_real_ip_from 192.168.0.0/16;
|
||||||
|
set_real_ip_from fd00::/8;
|
||||||
real_ip_header X-Forwarded-For;
|
real_ip_header X-Forwarded-For;
|
||||||
real_ip_recursive on;
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
@ -65,7 +76,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /rspamd/ {
|
location /rspamd/ {
|
||||||
proxy_pass http://172.22.1.253:11334/;
|
proxy_pass http://rspamd:11334/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
@ -97,7 +108,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /Microsoft-Server-ActiveSync {
|
location ^~ /Microsoft-Server-ActiveSync {
|
||||||
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
proxy_pass http://sogo:20000/SOGo/Microsoft-Server-ActiveSync;
|
||||||
proxy_connect_timeout 1000;
|
proxy_connect_timeout 1000;
|
||||||
proxy_next_upstream timeout error;
|
proxy_next_upstream timeout error;
|
||||||
proxy_send_timeout 1000;
|
proxy_send_timeout 1000;
|
||||||
|
@ -119,7 +130,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /SOGo {
|
location ^~ /SOGo {
|
||||||
proxy_pass http://172.22.1.252:20000;
|
proxy_pass http://sogo:20000;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
@ -134,7 +145,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo.woa/WebServerResources/ {
|
location /SOGo.woa/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -144,7 +155,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /.woa/WebServerResources/ {
|
location /.woa/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -154,7 +165,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo/WebServerResources/ {
|
location /SOGo/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -164,7 +175,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
||||||
proxy_pass http://172.22.1.252:9192/$1.SOGo/Resources/$2;
|
proxy_pass http://sogo:9192/$1.SOGo/Resources/$2;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -195,6 +206,7 @@ server {
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
add_header X-Robots-Tag none;
|
add_header X-Robots-Tag none;
|
||||||
add_header X-Download-Options noopen;
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
index index.php index.html;
|
index index.php index.html;
|
||||||
|
@ -217,7 +229,10 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
# If behind reverse proxy, forwards the correct IP
|
# If behind reverse proxy, forwards the correct IP
|
||||||
set_real_ip_from 172.22.1.1;
|
set_real_ip_from 10.0.0.0/8;
|
||||||
|
set_real_ip_from 172.16.0.0/12;
|
||||||
|
set_real_ip_from 192.168.0.0/16;
|
||||||
|
set_real_ip_from fd00::/8;
|
||||||
real_ip_header X-Forwarded-For;
|
real_ip_header X-Forwarded-For;
|
||||||
real_ip_recursive on;
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
@ -243,7 +258,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /rspamd/ {
|
location /rspamd/ {
|
||||||
proxy_pass http://172.22.1.253:11334/;
|
proxy_pass http://rspamd:11334/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
@ -275,7 +290,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /Microsoft-Server-ActiveSync {
|
location ^~ /Microsoft-Server-ActiveSync {
|
||||||
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
proxy_pass http://sogo:20000/SOGo/Microsoft-Server-ActiveSync;
|
||||||
proxy_connect_timeout 1000;
|
proxy_connect_timeout 1000;
|
||||||
proxy_next_upstream timeout error;
|
proxy_next_upstream timeout error;
|
||||||
proxy_send_timeout 1000;
|
proxy_send_timeout 1000;
|
||||||
|
@ -297,7 +312,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /SOGo {
|
location ^~ /SOGo {
|
||||||
proxy_pass http://172.22.1.252:20000;
|
proxy_pass http://sogo:20000;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
@ -312,7 +327,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo.woa/WebServerResources/ {
|
location /SOGo.woa/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -322,7 +337,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /.woa/WebServerResources/ {
|
location /.woa/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -332,7 +347,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo/WebServerResources/ {
|
location /SOGo/WebServerResources/ {
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
proxy_pass http://sogo:9192/WebServerResources/;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -342,7 +357,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
||||||
proxy_pass http://172.22.1.252:9192/$1.SOGo/Resources/$2;
|
proxy_pass http://sogo:9192/$1.SOGo/Resources/$2;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.interned_strings_buffer=8
|
||||||
|
opcache.max_accelerated_files=10000
|
||||||
|
opcache.memory_consumption=128
|
||||||
|
opcache.save_comments=1
|
||||||
|
opcache.revalidate_freq=1
|
|
@ -0,0 +1,12 @@
|
||||||
|
[system]
|
||||||
|
user = www-data
|
||||||
|
group = www-data
|
||||||
|
pm = dynamic
|
||||||
|
pm.max_children = 10
|
||||||
|
pm.start_servers = 2
|
||||||
|
pm.min_spare_servers = 2
|
||||||
|
pm.max_spare_servers = 4
|
||||||
|
listen = [::]:9001
|
||||||
|
access.log = /proc/self/fd/2
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
|
@ -0,0 +1,11 @@
|
||||||
|
[www]
|
||||||
|
user = www-data
|
||||||
|
group = www-data
|
||||||
|
pm = ondemand
|
||||||
|
pm.max_children = 20
|
||||||
|
pm.process_idle_timeout = 20s
|
||||||
|
pm.max_requests = 800
|
||||||
|
listen = [::]:9000
|
||||||
|
access.log = /proc/self/fd/2
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
|
@ -9,7 +9,7 @@ smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_una
|
||||||
alias_maps = hash:/etc/aliases
|
alias_maps = hash:/etc/aliases
|
||||||
alias_database = hash:/etc/aliases
|
alias_database = hash:/etc/aliases
|
||||||
relayhost =
|
relayhost =
|
||||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 [fd4d:6169:6c63:6f77::]/64
|
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 [fd::]/8
|
||||||
mailbox_size_limit = 0
|
mailbox_size_limit = 0
|
||||||
recipient_delimiter = +
|
recipient_delimiter = +
|
||||||
inet_interfaces = all
|
inet_interfaces = all
|
||||||
|
|
|
@ -196,7 +196,7 @@ while ($row = array_shift($rows)) {
|
||||||
}
|
}
|
||||||
whitelist_header_<?=$username_sane;?> {
|
whitelist_header_<?=$username_sane;?> {
|
||||||
<?php
|
<?php
|
||||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(CONCAT('^', `value`, '$'), '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(CONCAT('\<', `value`, '\>'), '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||||
WHERE `object`= :object
|
WHERE `object`= :object
|
||||||
AND `option` = 'whitelist_from'");
|
AND `option` = 'whitelist_from'");
|
||||||
$stmt->execute(array(':object' => $row['object']));
|
$stmt->execute(array(':object' => $row['object']));
|
||||||
|
@ -288,7 +288,7 @@ while ($row = array_shift($rows)) {
|
||||||
}
|
}
|
||||||
blacklist_header_<?=$username_sane;?> {
|
blacklist_header_<?=$username_sane;?> {
|
||||||
<?php
|
<?php
|
||||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(CONCAT('^', `value`, '$'), '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(CONCAT('\<', `value`, '\>'), '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||||
WHERE `object`= :object
|
WHERE `object`= :object
|
||||||
AND `option` = 'blacklist_from'");
|
AND `option` = 'blacklist_from'");
|
||||||
$stmt->execute(array(':object' => $row['object']));
|
$stmt->execute(array(':object' => $row['object']));
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
whitelisted_ip = "http://172.22.1.251:8081/forwardinghosts.php";
|
whitelisted_ip = "http://nginx:8081/forwardinghosts.php";
|
||||||
|
|
|
@ -4,6 +4,6 @@ secure_ip = "172.16.0.0/12";
|
||||||
secure_ip = "10.0.0.0/8";
|
secure_ip = "10.0.0.0/8";
|
||||||
secure_ip = "127.0.0.1";
|
secure_ip = "127.0.0.1";
|
||||||
secure_ip = "::1";
|
secure_ip = "::1";
|
||||||
secure_ip = "fd4d:6169:6c63:6f77::/64"
|
secure_ip = "fd00::/8"
|
||||||
.include(try=true; priority=10) "$CONFDIR/override.d/worker-controller-password.inc"
|
.include(try=true; priority=10) "$CONFDIR/override.d/worker-controller-password.inc"
|
||||||
.include(try=true; priority=20) "$CONFDIR/override.d/worker-controller.custom.inc"
|
.include(try=true; priority=20) "$CONFDIR/override.d/worker-controller.custom.inc"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
PrivateDAndTViewer
|
PrivateDAndTViewer
|
||||||
);
|
);
|
||||||
|
|
||||||
WOWorkersCount = "20";
|
WOWorkersCount = "7";
|
||||||
SOGoACLsSendEMailNotifications = YES;
|
SOGoACLsSendEMailNotifications = YES;
|
||||||
SOGoAppointmentSendEMailNotifications = YES;
|
SOGoAppointmentSendEMailNotifications = YES;
|
||||||
SOGoDraftsFolderName = "Drafts";
|
SOGoDraftsFolderName = "Drafts";
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
SOGoMailingMechanism = smtp;
|
SOGoMailingMechanism = smtp;
|
||||||
SOGoSMTPAuthenticationType = plain;
|
SOGoSMTPAuthenticationType = plain;
|
||||||
|
|
||||||
SxVMemLimit = 512;
|
SxVMemLimit = 384;
|
||||||
|
|
||||||
SOGoMaximumPingInterval = 354;
|
SOGoMaximumPingInterval = 354;
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,11 @@ server:
|
||||||
do-udp: yes
|
do-udp: yes
|
||||||
do-tcp: yes
|
do-tcp: yes
|
||||||
do-daemonize: no
|
do-daemonize: no
|
||||||
access-control: 172.22.1.0/24 allow
|
access-control: 10.0.0.0/8 allow
|
||||||
access-control: fd4d:6169:6c63:6f77::/64 allow
|
access-control: 172.16.0.0/12 allow
|
||||||
|
access-control: 192.168.0.0/16 allow
|
||||||
|
access-control: fd00::/8 allow
|
||||||
|
access-control: fe80::/10 allow
|
||||||
directory: "/etc/unbound"
|
directory: "/etc/unbound"
|
||||||
username: unbound
|
username: unbound
|
||||||
auto-trust-anchor-file: trusted-key.key
|
auto-trust-anchor-file: trusted-key.key
|
||||||
|
@ -19,7 +22,6 @@ server:
|
||||||
private-address: 169.254.0.0/16
|
private-address: 169.254.0.0/16
|
||||||
private-address: fd00::/8
|
private-address: fd00::/8
|
||||||
private-address: fe80::/10
|
private-address: fe80::/10
|
||||||
private-address: fd4d:6169:6c63:6f77::/64
|
|
||||||
root-hints: "/etc/unbound/root.hints"
|
root-hints: "/etc/unbound/root.hints"
|
||||||
hide-identity: yes
|
hide-identity: yes
|
||||||
hide-version: yes
|
hide-version: yes
|
||||||
|
|
|
@ -168,29 +168,31 @@ $tfa_data = get_tfa();
|
||||||
if (!empty($dkim = dkim('details', $domain))) {
|
if (!empty($dkim = dkim('details', $domain))) {
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
||||||
<div class="col-xs-2">
|
<div class="col-md-3">
|
||||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong>
|
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong>
|
||||||
<p><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
<p class="dkim-label"><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
<p class="dkim-label"><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-md-8">
|
||||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||||
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class="visible-xs visible-sm">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
||||||
<div class="col-xs-2">
|
<div class="col-md-3">
|
||||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br /><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br /><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9"><pre>-</pre></div>
|
<div class="col-md-8"><pre>-</pre></div>
|
||||||
|
<hr class="visible-xs visible-sm">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
@ -198,29 +200,31 @@ $tfa_data = get_tfa();
|
||||||
if (!empty($dkim = dkim('details', $alias_domain))) {
|
if (!empty($dkim = dkim('details', $alias_domain))) {
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
||||||
<div class="col-xs-1 col-xs-offset-1">
|
<div class="col-md-2 col-md-offset-1">
|
||||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
||||||
<p><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
<p class="dkim-label"><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
<p class="dkim-label"><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-md-8">
|
||||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||||
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class="visible-xs visible-sm">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
||||||
<div class="col-xs-1 col-xs-offset-1">
|
<div class="col-md-2 col-md-offset-1">
|
||||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9"><pre>-</pre></div>
|
<div class="col-md-8"><pre>-</pre></div>
|
||||||
|
<hr class="visible-xs visible-sm">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
@ -230,18 +234,19 @@ $tfa_data = get_tfa();
|
||||||
if (!empty($dkim = dkim('details', $blind))) {
|
if (!empty($dkim = dkim('details', $blind))) {
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
||||||
<div class="col-xs-2">
|
<div class="col-md-3">
|
||||||
<p>Domain: <strong><?=htmlspecialchars($blind);?></strong>
|
<p>Domain: <strong><?=htmlspecialchars($blind);?></strong>
|
||||||
<p><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
<p class="dkim-label"><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
||||||
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
<p class="dkim-label"><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
<p class="dkim-label"><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-md-8">
|
||||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||||
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class="visible-xs visible-sm">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
@ -346,6 +351,20 @@ $tfa_data = get_tfa();
|
||||||
<label for="retry_window"><?=$lang['admin']['f2b_retry_window'];?>:</label>
|
<label for="retry_window"><?=$lang['admin']['f2b_retry_window'];?>:</label>
|
||||||
<input type="number" class="form-control" id="retry_window" name="retry_window" value="<?=$f2b_data['retry_window'];?>" required>
|
<input type="number" class="form-control" id="retry_window" name="retry_window" value="<?=$f2b_data['retry_window'];?>" required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="netban_ipv4"><?=$lang['admin']['f2b_netban_ipv4'];?>:</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon">/</span>
|
||||||
|
<input type="number" class="form-control" id="netban_ipv4" name="netban_ipv4" value="<?=$f2b_data['netban_ipv4'];?>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="netban_ipv6"><?=$lang['admin']['f2b_netban_ipv6'];?>:</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon">/</span>
|
||||||
|
<input type="number" class="form-control" id="netban_ipv6" name="netban_ipv6" value="<?=$f2b_data['netban_ipv6'];?>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="whitelist"><?=$lang['admin']['f2b_whitelist'];?>:</label>
|
<label for="whitelist"><?=$lang['admin']['f2b_whitelist'];?>:</label>
|
||||||
<textarea class="form-control" id="whitelist" name="whitelist" rows="5"><?=$f2b_data['whitelist'];?></textarea>
|
<textarea class="form-control" id="whitelist" name="whitelist" rows="5"><?=$f2b_data['whitelist'];?></textarea>
|
||||||
|
@ -427,7 +446,7 @@ $tfa_data = get_tfa();
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-success" id="edit_selected" data-item="self" data-id="quarantaine" data-api-url='edit/quarantaine' data-api-attr='{"action":"settings"}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
<button class="btn btn-default" id="edit_selected" data-item="self" data-id="quarantaine" data-api-url='edit/quarantaine' data-api-attr='{"action":"settings"}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -441,7 +460,7 @@ $tfa_data = get_tfa();
|
||||||
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
|
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
|
||||||
<p>
|
<p>
|
||||||
<input type="file" name="main_logo" class="filestyle" data-buttonName="btn-default" data-buttonText="Select" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
|
<input type="file" name="main_logo" class="filestyle" data-buttonName="btn-default" data-buttonText="Select" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
|
||||||
<button name="submit_main_logo" type="submit" class="btn btn-success"><span class="glyphicon glyphicon-cloud-upload"></span> <?=$lang['admin']['upload'];?></button>
|
<button name="submit_main_logo" type="submit" class="btn btn-default"><span class="glyphicon glyphicon-cloud-upload"></span> <?=$lang['admin']['upload'];?></button>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
<?php
|
<?php
|
||||||
|
@ -501,7 +520,7 @@ $tfa_data = get_tfa();
|
||||||
?>
|
?>
|
||||||
</table>
|
</table>
|
||||||
<p><div class="btn-group">
|
<p><div class="btn-group">
|
||||||
<button class="btn btn-sm btn-success" id="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
<button class="btn btn-sm btn-default" id="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
<button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
|
<button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
|
||||||
</div></p>
|
</div></p>
|
||||||
</form>
|
</form>
|
||||||
|
@ -526,7 +545,7 @@ $tfa_data = get_tfa();
|
||||||
<label for="help_text"><?=$lang['admin']['help_text'];?>:</label>
|
<label for="help_text"><?=$lang['admin']['help_text'];?>:</label>
|
||||||
<textarea class="form-control" id="help_text" name="help_text" rows="7"><?=$ui_texts['help_text'];?></textarea>
|
<textarea class="form-control" id="help_text" name="help_text" rows="7"><?=$ui_texts['help_text'];?></textarea>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-success" id="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
<button class="btn btn-default" id="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -117,3 +117,22 @@ legend {
|
||||||
.lang-link-disabled {
|
.lang-link-disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
.dkim-label {
|
||||||
|
margin: 0 0 2px !important;
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
nav .glyphicon {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
.logged-in-as {
|
||||||
|
border-left: 1px solid #E7E7E7;
|
||||||
|
}
|
||||||
|
#top {
|
||||||
|
padding-top: 70px;
|
||||||
|
}
|
|
@ -704,6 +704,8 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<input type="hidden" value="0" name="delete2duplicates">
|
<input type="hidden" value="0" name="delete2duplicates">
|
||||||
<input type="hidden" value="0" name="delete1">
|
<input type="hidden" value="0" name="delete1">
|
||||||
<input type="hidden" value="0" name="delete2">
|
<input type="hidden" value="0" name="delete2">
|
||||||
|
<input type="hidden" value="0" name="automap">
|
||||||
|
<input type="hidden" value="0" name="skipcrossduplicates">
|
||||||
<input type="hidden" value="0" name="active">
|
<input type="hidden" value="0" name="active">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="host1"><?=$lang['edit']['hostname'];?></label>
|
<label class="control-label col-sm-2" for="host1"><?=$lang['edit']['hostname'];?></label>
|
||||||
|
@ -743,6 +745,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['edit']['mins_interval'];?></label>
|
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['edit']['mins_interval'];?></label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="number" class="form-control" name="mins_interval" min="1" max="3600" value="<?=htmlspecialchars($result['mins_interval'], ENT_QUOTES, 'UTF-8');?>" required>
|
<input type="number" class="form-control" name="mins_interval" min="1" max="3600" value="<?=htmlspecialchars($result['mins_interval'], ENT_QUOTES, 'UTF-8');?>" required>
|
||||||
|
<small class="help-block">10-3600</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -754,7 +757,15 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
|
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="number" class="form-control" name="maxage" id="maxage" value="<?=htmlspecialchars($result['maxage'], ENT_QUOTES, 'UTF-8');?>">
|
<input type="number" class="form-control" name="maxage" id="maxage" min="0" max="32000" value="<?=htmlspecialchars($result['maxage'], ENT_QUOTES, 'UTF-8');?>">
|
||||||
|
<small class="help-block">0-32000</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="maxbytespersecond"><?=$lang['edit']['maxbytespersecond'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="number" class="form-control" name="maxbytespersecond" id="maxbytespersecond" min="0" max="125000000" value="<?=htmlspecialchars($result['maxbytespersecond'], ENT_QUOTES, 'UTF-8');?>">
|
||||||
|
<small class="help-block">0-125000000</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -784,6 +795,20 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="automap" <?=($result['automap']=="1") ? "checked" : "";?>> <?=$lang['edit']['automap'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="skipcrossduplicates" <?=($result['skipcrossduplicates']=="1") ? "checked" : "";?>> <?=$lang['edit']['skipcrossduplicates'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
@ -22,7 +22,9 @@ function setLang(sel) {
|
||||||
$.post( "<?= $_SERVER['REQUEST_URI']; ?>", {lang: sel} );
|
$.post( "<?= $_SERVER['REQUEST_URI']; ?>", {lang: sel} );
|
||||||
window.location.href = window.location.pathname + window.location.search;
|
window.location.href = window.location.pathname + window.location.search;
|
||||||
}
|
}
|
||||||
|
$(window).load(function() {
|
||||||
|
$(".overlay").hide();
|
||||||
|
});
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
window.mailcow_alert_box = function(message, type) {
|
window.mailcow_alert_box = function(message, type) {
|
||||||
msg = $('<span/>').html(message).text();
|
msg = $('<span/>').html(message).text();
|
||||||
|
|
|
@ -12,6 +12,8 @@ function fail2ban($_action, $_data = null) {
|
||||||
$data['ban_time'] = $redis->Get('F2B_BAN_TIME');
|
$data['ban_time'] = $redis->Get('F2B_BAN_TIME');
|
||||||
$data['max_attempts'] = $redis->Get('F2B_MAX_ATTEMPTS');
|
$data['max_attempts'] = $redis->Get('F2B_MAX_ATTEMPTS');
|
||||||
$data['retry_window'] = $redis->Get('F2B_RETRY_WINDOW');
|
$data['retry_window'] = $redis->Get('F2B_RETRY_WINDOW');
|
||||||
|
$data['netban_ipv4'] = $redis->Get('F2B_NETBAN_IPV4');
|
||||||
|
$data['netban_ipv6'] = $redis->Get('F2B_NETBAN_IPV6');
|
||||||
$wl = $redis->hGetAll('F2B_WHITELIST');
|
$wl = $redis->hGetAll('F2B_WHITELIST');
|
||||||
if (is_array($wl)) {
|
if (is_array($wl)) {
|
||||||
foreach ($wl as $key => $value) {
|
foreach ($wl as $key => $value) {
|
||||||
|
@ -50,6 +52,8 @@ function fail2ban($_action, $_data = null) {
|
||||||
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
|
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
|
||||||
$max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['active_int']);
|
$max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['active_int']);
|
||||||
$retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']);
|
$retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']);
|
||||||
|
$netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']);
|
||||||
|
$netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
|
@ -60,12 +64,20 @@ function fail2ban($_action, $_data = null) {
|
||||||
}
|
}
|
||||||
$wl = $_data['whitelist'];
|
$wl = $_data['whitelist'];
|
||||||
$ban_time = ($ban_time < 60) ? 60 : $ban_time;
|
$ban_time = ($ban_time < 60) ? 60 : $ban_time;
|
||||||
|
|
||||||
|
$netban_ipv4 = ($netban_ipv4 < 8) ? 8 : $netban_ipv4;
|
||||||
|
$netban_ipv6 = ($netban_ipv6 < 8) ? 8 : $netban_ipv6;
|
||||||
|
$netban_ipv4 = ($netban_ipv4 > 32) ? 32 : $netban_ipv4;
|
||||||
|
$netban_ipv6 = ($netban_ipv6 > 128) ? 128 : $netban_ipv6;
|
||||||
|
|
||||||
$max_attempts = ($max_attempts < 1) ? 1 : $max_attempts;
|
$max_attempts = ($max_attempts < 1) ? 1 : $max_attempts;
|
||||||
$retry_window = ($retry_window < 1) ? 1 : $retry_window;
|
$retry_window = ($retry_window < 1) ? 1 : $retry_window;
|
||||||
try {
|
try {
|
||||||
$redis->Set('F2B_BAN_TIME', $ban_time);
|
$redis->Set('F2B_BAN_TIME', $ban_time);
|
||||||
$redis->Set('F2B_MAX_ATTEMPTS', $max_attempts);
|
$redis->Set('F2B_MAX_ATTEMPTS', $max_attempts);
|
||||||
$redis->Set('F2B_RETRY_WINDOW', $retry_window);
|
$redis->Set('F2B_RETRY_WINDOW', $retry_window);
|
||||||
|
$redis->Set('F2B_NETBAN_IPV4', $netban_ipv4);
|
||||||
|
$redis->Set('F2B_NETBAN_IPV6', $netban_ipv6);
|
||||||
$redis->Del('F2B_WHITELIST');
|
$redis->Del('F2B_WHITELIST');
|
||||||
if(!empty($wl)) {
|
if(!empty($wl)) {
|
||||||
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
|
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
|
||||||
|
|
|
@ -459,8 +459,9 @@ function user_get_alias_details($username) {
|
||||||
while ($row = array_shift($run)) {
|
while ($row = array_shift($run)) {
|
||||||
$data['shared_aliases'] = $row['shared_aliases'];
|
$data['shared_aliases'] = $row['shared_aliases'];
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `direct_aliases` FROM `alias`
|
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(`address` SEPARATOR ', ') AS `direct_aliases` FROM `alias`
|
||||||
WHERE `goto` = :username_goto
|
WHERE `goto` = :username_goto
|
||||||
|
AND `address` NOT LIKE '@%'
|
||||||
AND `address` != :username_address");
|
AND `address` != :username_address");
|
||||||
$stmt->execute(
|
$stmt->execute(
|
||||||
array(
|
array(
|
||||||
|
@ -477,7 +478,13 @@ function user_get_alias_details($username) {
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
while ($row = array_shift($run)) {
|
while ($row = array_shift($run)) {
|
||||||
$data['ad_alias'] = $row['ad_alias'];
|
if (empty($data['direct_aliases'])) {
|
||||||
|
$data['direct_aliases'] = $row['ad_alias'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Probably faster than imploding
|
||||||
|
$data['direct_aliases'] .= ', ' . $row['ad_alias'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '✘') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
|
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '✘') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
|
|
|
@ -216,11 +216,14 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
$delete2duplicates = intval($_data['delete2duplicates']);
|
$delete2duplicates = intval($_data['delete2duplicates']);
|
||||||
$delete1 = intval($_data['delete1']);
|
$delete1 = intval($_data['delete1']);
|
||||||
$delete2 = intval($_data['delete2']);
|
$delete2 = intval($_data['delete2']);
|
||||||
|
$skipcrossduplicates = intval($_data['skipcrossduplicates']);
|
||||||
|
$automap = intval($_data['automap']);
|
||||||
$port1 = $_data['port1'];
|
$port1 = $_data['port1'];
|
||||||
$host1 = strtolower($_data['host1']);
|
$host1 = strtolower($_data['host1']);
|
||||||
$password1 = $_data['password1'];
|
$password1 = $_data['password1'];
|
||||||
$exclude = $_data['exclude'];
|
$exclude = $_data['exclude'];
|
||||||
$maxage = $_data['maxage'];
|
$maxage = $_data['maxage'];
|
||||||
|
$maxbytespersecond = $_data['maxbytespersecond'];
|
||||||
$subfolder2 = $_data['subfolder2'];
|
$subfolder2 = $_data['subfolder2'];
|
||||||
$user1 = $_data['user1'];
|
$user1 = $_data['user1'];
|
||||||
$mins_interval = $_data['mins_interval'];
|
$mins_interval = $_data['mins_interval'];
|
||||||
|
@ -231,6 +234,9 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
|
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
|
||||||
$maxage = "0";
|
$maxage = "0";
|
||||||
}
|
}
|
||||||
|
if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
|
||||||
|
$maxbytespersecond = "0";
|
||||||
|
}
|
||||||
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
|
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
|
@ -287,14 +293,17 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `delete2`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `active`)
|
$stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `delete2`, `automap`, `skipcrossduplicates`, `maxbytespersecond`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `active`)
|
||||||
VALUES (:user2, :exclude, :delete1, :delete2, :maxage, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :active)");
|
VALUES (:user2, :exclude, :delete1, :delete2, :automap, :skipcrossduplicates, :maxbytespersecond, :maxage, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :active)");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':user2' => $username,
|
':user2' => $username,
|
||||||
':exclude' => $exclude,
|
':exclude' => $exclude,
|
||||||
':maxage' => $maxage,
|
':maxage' => $maxage,
|
||||||
':delete1' => $delete1,
|
':delete1' => $delete1,
|
||||||
':delete2' => $delete2,
|
':delete2' => $delete2,
|
||||||
|
':automap' => $automap,
|
||||||
|
':skipcrossduplicates' => $skipcrossduplicates,
|
||||||
|
':maxbytespersecond' => $maxbytespersecond,
|
||||||
':subfolder2' => $subfolder2,
|
':subfolder2' => $subfolder2,
|
||||||
':host1' => $host1,
|
':host1' => $host1,
|
||||||
':authmech1' => 'PLAIN',
|
':authmech1' => 'PLAIN',
|
||||||
|
@ -1444,6 +1453,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
$delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
|
$delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
|
||||||
$delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
|
$delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
|
||||||
$delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
|
$delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
|
||||||
|
$automap = (isset($_data['automap'])) ? intval($_data['automap']) : $is_now['automap'];
|
||||||
|
$skipcrossduplicates = (isset($_data['skipcrossduplicates'])) ? intval($_data['skipcrossduplicates']) : $is_now['skipcrossduplicates'];
|
||||||
$port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
|
$port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
|
||||||
$password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
|
$password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
|
||||||
$host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
|
$host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
|
||||||
|
@ -1452,6 +1463,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
$mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
|
$mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
|
||||||
$exclude = (!empty($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
|
$exclude = (!empty($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
|
||||||
$maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
|
$maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
|
||||||
|
$maxbytespersecond = (isset($_data['maxbytespersecond']) && $_data['maxbytespersecond'] != "") ? intval($_data['maxbytespersecond']) : $is_now['maxbytespersecond'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
|
@ -1466,6 +1478,9 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
|
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
|
||||||
$maxage = "0";
|
$maxage = "0";
|
||||||
}
|
}
|
||||||
|
if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
|
||||||
|
$maxbytespersecond = "0";
|
||||||
|
}
|
||||||
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
|
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
|
@ -1502,14 +1517,33 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1, `delete2` = :delete2, `maxage` = :maxage, `subfolder2` = :subfolder2, `exclude` = :exclude, `host1` = :host1, `last_run` = :last_run, `user1` = :user1, `password1` = :password1, `mins_interval` = :mins_interval, `port1` = :port1, `enc1` = :enc1, `delete2duplicates` = :delete2duplicates, `active` = :active
|
$stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1,
|
||||||
|
`delete2` = :delete2,
|
||||||
|
`automap` = :automap,
|
||||||
|
`skipcrossduplicates` = :skipcrossduplicates,
|
||||||
|
`maxage` = :maxage,
|
||||||
|
`maxbytespersecond` = :maxbytespersecond,
|
||||||
|
`subfolder2` = :subfolder2,
|
||||||
|
`exclude` = :exclude,
|
||||||
|
`host1` = :host1,
|
||||||
|
`last_run` = :last_run,
|
||||||
|
`user1` = :user1,
|
||||||
|
`password1` = :password1,
|
||||||
|
`mins_interval` = :mins_interval,
|
||||||
|
`port1` = :port1,
|
||||||
|
`enc1` = :enc1,
|
||||||
|
`delete2duplicates` = :delete2duplicates,
|
||||||
|
`active` = :active
|
||||||
WHERE `id` = :id");
|
WHERE `id` = :id");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':delete1' => $delete1,
|
':delete1' => $delete1,
|
||||||
':delete2' => $delete2,
|
':delete2' => $delete2,
|
||||||
|
':automap' => $automap,
|
||||||
|
':skipcrossduplicates' => $skipcrossduplicates,
|
||||||
':id' => $id,
|
':id' => $id,
|
||||||
':exclude' => $exclude,
|
':exclude' => $exclude,
|
||||||
':maxage' => $maxage,
|
':maxage' => $maxage,
|
||||||
|
':maxbytespersecond' => $maxbytespersecond,
|
||||||
':subfolder2' => $subfolder2,
|
':subfolder2' => $subfolder2,
|
||||||
':host1' => $host1,
|
':host1' => $host1,
|
||||||
':user1' => $user1,
|
':user1' => $user1,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta http-equiv="Referrer-Policy" content="same-origin">
|
||||||
<title><?=$UI_TEXTS['title_name'];?></title>
|
<title><?=$UI_TEXTS['title_name'];?></title>
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="/js/html5shiv.min.js"></script>
|
<script src="/js/html5shiv.min.js"></script>
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
<link rel="shortcut icon" href="/favicon.png" type="image/png">
|
<link rel="shortcut icon" href="/favicon.png" type="image/png">
|
||||||
<link rel="icon" href="/favicon.png" type="image/png">
|
<link rel="icon" href="/favicon.png" type="image/png">
|
||||||
</head>
|
</head>
|
||||||
<body style="padding-top: 70px;" id="top">
|
<body id="top">
|
||||||
|
<div class="overlay"></div>
|
||||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
|
@ -93,12 +95,12 @@
|
||||||
<?php
|
<?php
|
||||||
if (isset($_SESSION['mailcow_cc_role'])) {
|
if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
?>
|
?>
|
||||||
<li<?= (preg_match("/quarantaine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantaine.php"><span style="font-size: 12px;" class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantaine']; ?></a></li>
|
<li<?= (preg_match("/quarantaine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantaine.php"><span class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantaine']; ?></a></li>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
if ($_SESSION['mailcow_cc_role'] == 'admin') {
|
if ($_SESSION['mailcow_cc_role'] == 'admin') {
|
||||||
?>
|
?>
|
||||||
<li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span style="font-size: 12px;" class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
|
<li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -126,11 +128,11 @@
|
||||||
}
|
}
|
||||||
if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
|
if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
|
||||||
?>
|
?>
|
||||||
<li><a href="#" style="border-left: 1px solid #E7E7E7;" onclick="logout.submit()"><?= sprintf($lang['header']['logged_in_as_logout'], $_SESSION['mailcow_cc_username']); ?></a></li>
|
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b><?= $_SESSION['mailcow_cc_username']; ?></b> <span class="glyphicon glyphicon-log-out"></span></a></li>
|
||||||
<?php
|
<?php
|
||||||
elseif (isset($_SESSION['dual-login'])):
|
elseif (isset($_SESSION['dual-login'])):
|
||||||
?>
|
?>
|
||||||
<li><a href="#" style="border-left: 1px solid #E7E7E7;" onclick="logout.submit()"><?= sprintf($lang['header']['logged_in_as_logout_dual'], $_SESSION['mailcow_cc_username'], $_SESSION['dual-login']['username']); ?></a></li>
|
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b><?= $_SESSION['mailcow_cc_username']; ?> <span class="text-info">(<?= $_SESSION['dual-login']['username']; ?>)</span> </b><span class="glyphicon glyphicon-log-out"></span></a></li>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "20012021_2202";
|
$db_version = "27012018_1721";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
@ -21,13 +21,14 @@ function init_db_schema() {
|
||||||
AND active = '1'
|
AND active = '1'
|
||||||
AND address NOT LIKE '@%'
|
AND address NOT LIKE '@%'
|
||||||
GROUP BY goto;",
|
GROUP BY goto;",
|
||||||
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as) AS
|
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
|
||||||
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as FROM sender_acl
|
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
|
||||||
WHERE send_as NOT LIKE '@%'
|
WHERE send_as NOT LIKE '@%'
|
||||||
GROUP BY logged_in_as;",
|
GROUP BY logged_in_as;",
|
||||||
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
|
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
|
||||||
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
|
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
|
||||||
LEFT OUTER JOIN alias_domain on target_domain=domain GROUP BY username;",
|
LEFT OUTER JOIN alias_domain ON target_domain=domain
|
||||||
|
GROUP BY username;",
|
||||||
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
|
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
|
||||||
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
||||||
WHERE filter_type = 'prefilter';",
|
WHERE filter_type = 'prefilter';",
|
||||||
|
@ -353,12 +354,15 @@ function init_db_schema() {
|
||||||
"password1" => "VARCHAR(255) NOT NULL",
|
"password1" => "VARCHAR(255) NOT NULL",
|
||||||
"exclude" => "VARCHAR(500) NOT NULL DEFAULT ''",
|
"exclude" => "VARCHAR(500) NOT NULL DEFAULT ''",
|
||||||
"maxage" => "SMALLINT NOT NULL DEFAULT '0'",
|
"maxage" => "SMALLINT NOT NULL DEFAULT '0'",
|
||||||
"mins_interval" => "VARCHAR(50) NOT NULL",
|
"mins_interval" => "VARCHAR(50) NOT NULL DEFAULT '0'",
|
||||||
|
"maxbytespersecond" => "VARCHAR(50) NOT NULL DEFAULT '0'",
|
||||||
"port1" => "SMALLINT NOT NULL",
|
"port1" => "SMALLINT NOT NULL",
|
||||||
"enc1" => "ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS'",
|
"enc1" => "ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS'",
|
||||||
"delete2duplicates" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"delete2duplicates" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"delete1" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
"delete1" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||||
"delete2" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
"delete2" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||||
|
"automap" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||||
|
"skipcrossduplicates" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||||
"is_running" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
"is_running" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||||
"returned_text" => "TEXT",
|
"returned_text" => "TEXT",
|
||||||
"last_run" => "TIMESTAMP NULL DEFAULT NULL",
|
"last_run" => "TIMESTAMP NULL DEFAULT NULL",
|
||||||
|
|
|
@ -15,7 +15,7 @@ jQuery(function($){
|
||||||
{"name":"sender","title":lang.sender,"breakpoints":"xs sm"},
|
{"name":"sender","title":lang.sender,"breakpoints":"xs sm"},
|
||||||
{"name":"rcpt","title":lang.rcpt, "type": "text"},
|
{"name":"rcpt","title":lang.rcpt, "type": "text"},
|
||||||
{"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.received,"style":{"width":"170px"}},
|
{"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.received,"style":{"width":"170px"}},
|
||||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"width":"205px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||||
],
|
],
|
||||||
"rows": $.ajax({
|
"rows": $.ajax({
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
|
|
|
@ -101,6 +101,7 @@ $lang['danger']['spam_alias_max_exceeded'] = 'Maximale Anzahl an Spam-Alias-Adre
|
||||||
$lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an';
|
$lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an';
|
||||||
$lang['user']['loading'] = "Lade...";
|
$lang['user']['loading'] = "Lade...";
|
||||||
$lang['user']['active_sieve'] = "Aktiver Filter";
|
$lang['user']['active_sieve'] = "Aktiver Filter";
|
||||||
|
$lang['user']['show_sieve_filters'] = "Zeige aktiven Filter des Benutzers";
|
||||||
$lang['user']['no_active_filter'] = "Kein aktiver Filter vorhanden";
|
$lang['user']['no_active_filter'] = "Kein aktiver Filter vorhanden";
|
||||||
$lang['user']['on'] = 'Ein';
|
$lang['user']['on'] = 'Ein';
|
||||||
$lang['user']['off'] = 'Aus';
|
$lang['user']['off'] = 'Aus';
|
||||||
|
@ -122,7 +123,9 @@ $lang['user']['spam_aliases'] = 'Temporäre E-Mail Aliasse';
|
||||||
$lang['user']['alias'] = 'Alias';
|
$lang['user']['alias'] = 'Alias';
|
||||||
$lang['user']['aliases'] = 'Aliasse';
|
$lang['user']['aliases'] = 'Aliasse';
|
||||||
$lang['user']['shared_aliases'] = 'Geteilte Alias-Adressen';
|
$lang['user']['shared_aliases'] = 'Geteilte Alias-Adressen';
|
||||||
|
$lang['user']['shared_aliases_desc'] = 'Geteilte Alias-Adressen werden nicht bei benutzerdefinierten Einstellungen wie die des Spam-Filters oder der Verschlüsselungsrichtlinie berücksichtigt. Entsprechende Spam-Filter können lediglich von einem Administrator vorgenommen werden.';
|
||||||
$lang['user']['direct_aliases'] = 'Direkte Alias-Adressen';
|
$lang['user']['direct_aliases'] = 'Direkte Alias-Adressen';
|
||||||
|
$lang['user']['direct_aliases_desc'] = 'Nur direkte Alias-Adressen werden für benutzerdefinierte Einstellungen berücksichtigt.';
|
||||||
$lang['user']['domain_aliases'] = 'Domain-Alias Adressen';
|
$lang['user']['domain_aliases'] = 'Domain-Alias Adressen';
|
||||||
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
|
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
|
||||||
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als Benutzer';
|
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als Benutzer';
|
||||||
|
@ -305,6 +308,12 @@ $lang['edit']['encryption'] = 'Verschlüsselung';
|
||||||
$lang['edit']['maxage'] = 'Maximales Alter in Tagen einer Nachricht, die kopiert werden soll</br ><small>(0 = alle Nachrichten kopieren)</small>';
|
$lang['edit']['maxage'] = 'Maximales Alter in Tagen einer Nachricht, die kopiert werden soll</br ><small>(0 = alle Nachrichten kopieren)</small>';
|
||||||
$lang['edit']['subfolder2'] = 'Ziel-Ordner<br><small>(leer = kein Unterordner)</small>';
|
$lang['edit']['subfolder2'] = 'Ziel-Ordner<br><small>(leer = kein Unterordner)</small>';
|
||||||
$lang['edit']['mins_interval'] = 'Intervall (min)';
|
$lang['edit']['mins_interval'] = 'Intervall (min)';
|
||||||
|
$lang['edit']['maxbytespersecond'] = 'Max. Übertragungsrate in Bytes/s (0 für unlimitiert)';
|
||||||
|
$lang['edit']['automap'] = 'Ordner automatisch mappen ("Sent items", "Sent" => "Sent" etc.)';
|
||||||
|
$lang['edit']['skipcrossduplicates'] = 'Duplikate auch über Ordner hinweg überspringen ("first come, first serve")';
|
||||||
|
$lang['add']['maxbytespersecond'] = 'Max. Übertragungsrate in Bytes/s (0 für unlimitiert)';
|
||||||
|
$lang['add']['automap'] = 'Ordner automatisch mappen ("Sent items", "Sent" => "Sent" etc.)';
|
||||||
|
$lang['add']['skipcrossduplicates'] = 'Duplikate auch über Ordner hinweg überspringen ("first come, first serve")';
|
||||||
$lang['edit']['exclude'] = 'Elemente ausschließen (Regex)';
|
$lang['edit']['exclude'] = 'Elemente ausschließen (Regex)';
|
||||||
$lang['edit']['archive'] = 'Archiv-Zugriff';
|
$lang['edit']['archive'] = 'Archiv-Zugriff';
|
||||||
$lang['edit']['max_mailboxes'] = 'Max. Mailboxanzahl:';
|
$lang['edit']['max_mailboxes'] = 'Max. Mailboxanzahl:';
|
||||||
|
@ -463,6 +472,8 @@ $lang['admin']['f2b_parameters'] = 'Fail2ban Parameter';
|
||||||
$lang['admin']['f2b_ban_time'] = 'Banzeit (s)';
|
$lang['admin']['f2b_ban_time'] = 'Banzeit (s)';
|
||||||
$lang['admin']['f2b_max_attempts'] = 'Max. Versuche';
|
$lang['admin']['f2b_max_attempts'] = 'Max. Versuche';
|
||||||
$lang['admin']['f2b_retry_window'] = 'Wiederholungen im Zeitraum von (s)';
|
$lang['admin']['f2b_retry_window'] = 'Wiederholungen im Zeitraum von (s)';
|
||||||
|
$lang['admin']['f2b_netban_ipv4'] = 'Netzbereich für IPv4 Bans (8-32)';
|
||||||
|
$lang['admin']['f2b_netban_ipv6'] = 'Netzbereich für IPv6 Bans (8-128)';
|
||||||
$lang['admin']['f2b_whitelist'] = 'Whitelist für Netzwerke und Hosts';
|
$lang['admin']['f2b_whitelist'] = 'Whitelist für Netzwerke und Hosts';
|
||||||
$lang['admin']['restrictions'] = 'Postfix Restriktionen';
|
$lang['admin']['restrictions'] = 'Postfix Restriktionen';
|
||||||
$lang['admin']['rr'] = 'Postfix Empfänger Restriktionen';
|
$lang['admin']['rr'] = 'Postfix Empfänger Restriktionen';
|
||||||
|
|
|
@ -101,6 +101,7 @@ $lang['danger']['spam_alias_max_exceeded'] = "Max. allowed spam alias addresses
|
||||||
$lang['danger']['validity_missing'] = 'Please assign a period of validity';
|
$lang['danger']['validity_missing'] = 'Please assign a period of validity';
|
||||||
$lang['user']['loading'] = "Loading...";
|
$lang['user']['loading'] = "Loading...";
|
||||||
$lang['user']['active_sieve'] = "Active filter";
|
$lang['user']['active_sieve'] = "Active filter";
|
||||||
|
$lang['user']['show_sieve_filters'] = "Show active user sieve filter";
|
||||||
$lang['user']['no_active_filter'] = "No active filter available";
|
$lang['user']['no_active_filter'] = "No active filter available";
|
||||||
$lang['user']['on'] = "On";
|
$lang['user']['on'] = "On";
|
||||||
$lang['user']['off'] = "Off";
|
$lang['user']['off'] = "Off";
|
||||||
|
@ -122,7 +123,9 @@ $lang['user']['spam_aliases'] = 'Temporary email aliases';
|
||||||
$lang['user']['alias'] = 'Alias';
|
$lang['user']['alias'] = 'Alias';
|
||||||
$lang['user']['aliases'] = 'Aliases';
|
$lang['user']['aliases'] = 'Aliases';
|
||||||
$lang['user']['shared_aliases'] = 'Shared alias addresses';
|
$lang['user']['shared_aliases'] = 'Shared alias addresses';
|
||||||
|
$lang['user']['shared_aliases_desc'] = 'A shared alias address is not affected by any user specific settings. A custom spam filter setting can be archived by a domain-wide policy set by an administrator..';
|
||||||
$lang['user']['direct_aliases'] = 'Direct alias addresses';
|
$lang['user']['direct_aliases'] = 'Direct alias addresses';
|
||||||
|
$lang['user']['direct_aliases_desc'] = 'Direct alias addresses are affected by spam filter and TLS policy settings.';
|
||||||
$lang['user']['domain_aliases'] = 'Domain alias addresses';
|
$lang['user']['domain_aliases'] = 'Domain alias addresses';
|
||||||
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
|
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
|
||||||
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as user';
|
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as user';
|
||||||
|
@ -303,6 +306,12 @@ $lang['edit']['username'] = 'Username';
|
||||||
$lang['edit']['hostname'] = 'Hostname';
|
$lang['edit']['hostname'] = 'Hostname';
|
||||||
$lang['edit']['encryption'] = 'Encryption';
|
$lang['edit']['encryption'] = 'Encryption';
|
||||||
$lang['edit']['maxage'] = 'Maximum age of messages in days that will be polled from remote<br><small>(0 = ignore age)</small>';
|
$lang['edit']['maxage'] = 'Maximum age of messages in days that will be polled from remote<br><small>(0 = ignore age)</small>';
|
||||||
|
$lang['edit']['maxbytespersecond'] = 'Max. bytes per second (0 equals to unlimited)';
|
||||||
|
$lang['edit']['automap'] = 'Try to automap folders ("Sent items", "Sent" => "Sent" etc.)';
|
||||||
|
$lang['edit']['skipcrossduplicates'] = 'Skip duplicate messages across folders (first come, first serve)';
|
||||||
|
$lang['add']['maxbytespersecond'] = 'Max. bytes per second (0 equals to unlimited)';
|
||||||
|
$lang['add']['automap'] = 'Try to automap folders ("Sent items", "Sent" => "Sent" etc.)';
|
||||||
|
$lang['add']['skipcrossduplicates'] = 'Skip duplicate messages across folders (first come, first serve)';
|
||||||
$lang['edit']['subfolder2'] = 'Sync into subfolder on destination<br><small>(empty = do not use subfolder)</small>';
|
$lang['edit']['subfolder2'] = 'Sync into subfolder on destination<br><small>(empty = do not use subfolder)</small>';
|
||||||
$lang['edit']['mins_interval'] = 'Interval (min)';
|
$lang['edit']['mins_interval'] = 'Interval (min)';
|
||||||
$lang['edit']['exclude'] = 'Exclude objects (regex)';
|
$lang['edit']['exclude'] = 'Exclude objects (regex)';
|
||||||
|
@ -463,6 +472,8 @@ $lang['admin']['f2b_parameters'] = 'Fail2ban parameters';
|
||||||
$lang['admin']['f2b_ban_time'] = 'Ban time (s)';
|
$lang['admin']['f2b_ban_time'] = 'Ban time (s)';
|
||||||
$lang['admin']['f2b_max_attempts'] = 'Max. attempts';
|
$lang['admin']['f2b_max_attempts'] = 'Max. attempts';
|
||||||
$lang['admin']['f2b_retry_window'] = 'Retry window (s) for max. attempts';
|
$lang['admin']['f2b_retry_window'] = 'Retry window (s) for max. attempts';
|
||||||
|
$lang['admin']['f2b_netban_ipv4'] = 'IPv4 subnet size to apply ban on (8-32)';
|
||||||
|
$lang['admin']['f2b_netban_ipv6'] = 'IPv6 subnet size to apply ban on (8-128)';
|
||||||
$lang['admin']['f2b_whitelist'] = 'Whitelisted networks/hosts';
|
$lang['admin']['f2b_whitelist'] = 'Whitelisted networks/hosts';
|
||||||
$lang['admin']['search_domain_da'] = 'Search domains';
|
$lang['admin']['search_domain_da'] = 'Search domains';
|
||||||
$lang['admin']['restrictions'] = 'Postfix Restrictions';
|
$lang['admin']['restrictions'] = 'Postfix Restrictions';
|
||||||
|
|
|
@ -391,6 +391,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<small class="help-block">0-32000</small>
|
<small class="help-block">0-32000</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="maxbytespersecond"><?=$lang['edit']['maxbytespersecond'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="number" class="form-control" name="maxbytespersecond" id="maxbytespersecond" min="0" max="125000000" value="0">
|
||||||
|
<small class="help-block">0-125000000</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
|
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -418,6 +425,20 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="automap"> <?=$lang['add']['automap'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="skipcrossduplicates"> <?=$lang['add']['skipcrossduplicates'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
@ -70,6 +70,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<small class="help-block">0-32000</small>
|
<small class="help-block">0-32000</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="maxbytespersecond"><?=$lang['edit']['maxbytespersecond'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="number" class="form-control" name="maxbytespersecond" id="maxbytespersecond" min="0" max="125000000" value="0">
|
||||||
|
<small class="help-block">0-125000000</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
|
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -97,6 +104,20 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="automap"> <?=$lang['add']['automap'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="skipcrossduplicates"> <?=$lang['add']['skipcrossduplicates'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
@ -97,7 +97,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"> <span class="glyphicon glyphicon-filter"></span></div>
|
<div class="col-md-3 col-xs-5 text-right"> <span class="glyphicon glyphicon-filter"></span></div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-md-9 col-xs-7">
|
||||||
<p><a href="#userFilterModal" data-toggle="modal">[Show active user sieve filter]</a></p>
|
<p><a href="#userFilterModal" data-toggle="modal">[<?=$lang['user']['show_sieve_filters'];?>]</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -105,24 +105,22 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
$user_get_alias_details = user_get_alias_details($username);
|
$user_get_alias_details = user_get_alias_details($username);
|
||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>:</div>
|
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>:
|
||||||
|
<p class="small"><?=$lang['user']['direct_aliases_desc'];?></p>
|
||||||
|
</div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-md-9 col-xs-7">
|
||||||
<p><?=$user_get_alias_details['direct_aliases'];?></p>
|
<p><?=$user_get_alias_details['direct_aliases'];?></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['shared_aliases'];?>:</div>
|
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['shared_aliases'];?>:
|
||||||
|
<p class="small"><?=$lang['user']['shared_aliases_desc'];?></p>
|
||||||
|
</div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-md-9 col-xs-7">
|
||||||
<p><?=$user_get_alias_details['shared_aliases'];?></p>
|
<p><?=$user_get_alias_details['shared_aliases'];?></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['domain_aliases'];?>:</div>
|
|
||||||
<div class="col-md-9 col-xs-7">
|
|
||||||
<p><?=$user_get_alias_details['ad_alias'];?></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div>
|
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-md-9 col-xs-7">
|
||||||
|
|
|
@ -12,7 +12,7 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.254
|
ipv4_address: ${IPV4_NETWORK}.254
|
||||||
aliases:
|
aliases:
|
||||||
- unbound
|
- unbound
|
||||||
|
|
||||||
|
@ -29,10 +29,9 @@ services:
|
||||||
- MYSQL_PASSWORD=${DBPASS}
|
- MYSQL_PASSWORD=${DBPASS}
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.250
|
|
||||||
aliases:
|
aliases:
|
||||||
- mysql
|
- mysql
|
||||||
|
|
||||||
|
@ -44,29 +43,31 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.249
|
ipv4_address: ${IPV4_NETWORK}.249
|
||||||
aliases:
|
aliases:
|
||||||
- redis
|
- redis
|
||||||
|
|
||||||
clamd-mailcow:
|
clamd-mailcow:
|
||||||
image: mailcow/clamd:1.6
|
image: mailcow/clamd:1.8
|
||||||
build: ./data/Dockerfiles/clamd
|
build: ./data/Dockerfiles/clamd
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- SKIP_CLAMD=${SKIP_CLAMD:-n}
|
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
|
- SKIP_CLAMD=${SKIP_CLAMD:-n}
|
||||||
|
volumes:
|
||||||
|
- ./data/conf/clamav/:/etc/clamav/
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
- clamd
|
- clamd
|
||||||
|
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: mailcow/rspamd:1.15
|
image: mailcow/rspamd:1.16
|
||||||
build: ./data/Dockerfiles/rspamd
|
build: ./data/Dockerfiles/rspamd
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -82,16 +83,15 @@ services:
|
||||||
- rspamd-vol-1:/var/lib/rspamd
|
- rspamd-vol-1:/var/lib/rspamd
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
hostname: rspamd
|
hostname: rspamd
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.253
|
|
||||||
aliases:
|
aliases:
|
||||||
- rspamd
|
- rspamd
|
||||||
|
|
||||||
php-fpm-mailcow:
|
php-fpm-mailcow:
|
||||||
image: mailcow/phpfpm:1.8
|
image: mailcow/phpfpm:1.9
|
||||||
build: ./data/Dockerfiles/phpfpm
|
build: ./data/Dockerfiles/phpfpm
|
||||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -101,6 +101,9 @@ services:
|
||||||
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
|
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
|
||||||
- dkim-vol-1:/data/dkim
|
- dkim-vol-1:/data/dkim
|
||||||
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
|
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
|
||||||
|
- ./data/conf/phpfpm/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf
|
||||||
|
- ./data/conf/phpfpm/php-fpm.d/system.conf:/usr/local/etc/php-fpm.d/system.conf
|
||||||
|
- ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||||
environment:
|
environment:
|
||||||
- LOG_LINES=${LOG_LINES}
|
- LOG_LINES=${LOG_LINES}
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
|
@ -118,14 +121,14 @@ services:
|
||||||
- SMTP_PORT=${SMTP_PORT:-25}
|
- SMTP_PORT=${SMTP_PORT:-25}
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
- phpfpm
|
- phpfpm
|
||||||
|
|
||||||
sogo-mailcow:
|
sogo-mailcow:
|
||||||
image: mailcow/sogo:1.13
|
image: mailcow/sogo:1.14
|
||||||
build: ./data/Dockerfiles/sogo
|
build: ./data/Dockerfiles/sogo
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
|
@ -138,15 +141,14 @@ services:
|
||||||
- ./data/conf/sogo/:/etc/sogo/
|
- ./data/conf/sogo/:/etc/sogo/
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.252
|
|
||||||
aliases:
|
aliases:
|
||||||
- sogo
|
- sogo
|
||||||
|
|
||||||
dovecot-mailcow:
|
dovecot-mailcow:
|
||||||
image: mailcow/dovecot:1.17
|
image: mailcow/dovecot:1.18
|
||||||
build: ./data/Dockerfiles/dovecot
|
build: ./data/Dockerfiles/dovecot
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_BIND_SERVICE
|
- NET_BIND_SERVICE
|
||||||
|
@ -176,7 +178,7 @@ services:
|
||||||
soft: 20000
|
soft: 20000
|
||||||
hard: 40000
|
hard: 40000
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
hostname: ${MAILCOW_HOSTNAME}
|
hostname: ${MAILCOW_HOSTNAME}
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
@ -197,13 +199,15 @@ services:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
- DBUSER=${DBUSER}
|
- DBUSER=${DBUSER}
|
||||||
- DBPASS=${DBPASS}
|
- DBPASS=${DBPASS}
|
||||||
|
cap_add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
ports:
|
ports:
|
||||||
- "${SMTP_PORT:-25}:25"
|
- "${SMTP_PORT:-25}:25"
|
||||||
- "${SMTPS_PORT:-465}:465"
|
- "${SMTPS_PORT:-465}:465"
|
||||||
- "${SUBMISSION_PORT:-587}:587"
|
- "${SUBMISSION_PORT:-587}:587"
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
hostname: ${MAILCOW_HOSTNAME}
|
hostname: ${MAILCOW_HOSTNAME}
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
@ -214,7 +218,7 @@ services:
|
||||||
image: memcached:alpine
|
image: memcached:alpine
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
|
@ -249,10 +253,9 @@ services:
|
||||||
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
|
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.251
|
|
||||||
aliases:
|
aliases:
|
||||||
- nginx
|
- nginx
|
||||||
|
|
||||||
|
@ -263,7 +266,7 @@ services:
|
||||||
image: mailcow/acme:1.28
|
image: mailcow/acme:1.28
|
||||||
build: ./data/Dockerfiles/acme
|
build: ./data/Dockerfiles/acme
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
environment:
|
environment:
|
||||||
- LOG_LINES=${LOG_LINES}
|
- LOG_LINES=${LOG_LINES}
|
||||||
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
|
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
|
||||||
|
@ -284,7 +287,7 @@ services:
|
||||||
- acme
|
- acme
|
||||||
|
|
||||||
fail2ban-mailcow:
|
fail2ban-mailcow:
|
||||||
image: mailcow/fail2ban:1.10
|
image: mailcow/fail2ban:1.11
|
||||||
build: ./data/Dockerfiles/fail2ban
|
build: ./data/Dockerfiles/fail2ban
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -298,16 +301,17 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-n}
|
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-n}
|
||||||
|
- IPV4_NETWORK=${IPV4_NETWORK}
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- ${IPV4_NETWORK}.254
|
||||||
volumes:
|
volumes:
|
||||||
- /lib/modules:/lib/modules:ro
|
- /lib/modules:/lib/modules:ro
|
||||||
|
|
||||||
watchdog-mailcow:
|
watchdog-mailcow:
|
||||||
image: mailcow/watchdog:1.12
|
image: mailcow/watchdog:1.13
|
||||||
# Debug
|
# Debug
|
||||||
#command: /watchdog.sh
|
command: /watchdog.sh
|
||||||
build: ./data/Dockerfiles/watchdog
|
build: ./data/Dockerfiles/watchdog
|
||||||
volumes:
|
volumes:
|
||||||
- vmail-vol-1:/vmail:ro
|
- vmail-vol-1:/vmail:ro
|
||||||
|
@ -323,7 +327,6 @@ services:
|
||||||
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.248
|
|
||||||
aliases:
|
aliases:
|
||||||
- watchdog
|
- watchdog
|
||||||
|
|
||||||
|
@ -358,8 +361,8 @@ networks:
|
||||||
ipam:
|
ipam:
|
||||||
driver: default
|
driver: default
|
||||||
config:
|
config:
|
||||||
- subnet: 172.22.1.0/24
|
- subnet: ${IPV4_NETWORK}.0/24
|
||||||
- subnet: fd4d:6169:6c63:6f77::/64
|
- subnet: ${IPV6_NETWORK}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
vmail-vol-1:
|
vmail-vol-1:
|
||||||
|
|
|
@ -101,8 +101,16 @@ USE_WATCHDOG=n
|
||||||
# Send notifications by mail (no DKIM signature, sent from watchdog@MAILCOW_HOSTNAME)
|
# Send notifications by mail (no DKIM signature, sent from watchdog@MAILCOW_HOSTNAME)
|
||||||
#WATCHDOG_NOTIFY_EMAIL=
|
#WATCHDOG_NOTIFY_EMAIL=
|
||||||
|
|
||||||
|
# Max log lines per service to keep in Redis logs
|
||||||
LOG_LINES=9999
|
LOG_LINES=9999
|
||||||
|
|
||||||
|
# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)
|
||||||
|
IPV4_NETWORK=172.22.1
|
||||||
|
|
||||||
|
# Internal IPv6 subnet in fd00::/8
|
||||||
|
IPV6_NETWORK=fd4d:6169:6c63:6f77::/64
|
||||||
|
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
mkdir -p data/assets/ssl
|
mkdir -p data/assets/ssl
|
||||||
|
|
|
@ -79,10 +79,12 @@ elif [[ ${NC_INSTALL} == "y" ]]; then
|
||||||
/web/nextcloud/occ config:system:set redis port --value=6379 --type=integer; \
|
/web/nextcloud/occ config:system:set redis port --value=6379 --type=integer; \
|
||||||
/web/nextcloud/occ config:system:set memcache.locking --value='\OC\Memcache\Redis' --type=string; \
|
/web/nextcloud/occ config:system:set memcache.locking --value='\OC\Memcache\Redis' --type=string; \
|
||||||
/web/nextcloud/occ config:system:set memcache.local --value='\OC\Memcache\Redis' --type=string; \
|
/web/nextcloud/occ config:system:set memcache.local --value='\OC\Memcache\Redis' --type=string; \
|
||||||
/web/nextcloud/occ config:system:set trusted_proxies 0 --value=fd4d:6169:6c63:6f77::1; \
|
/web/nextcloud/occ config:system:set trusted_domains 1 --value=${MAILCOW_HOSTNAME}; \
|
||||||
/web/nextcloud/occ config:system:set trusted_proxies 1 --value=172.22.1.0/24; \
|
/web/nextcloud/occ config:system:set trusted_proxies 0 --value=${IPV6_NETWORK}; \
|
||||||
|
/web/nextcloud/occ config:system:set trusted_proxies 1 --value=${IPV4_NETWORK}.0/24; \
|
||||||
/web/nextcloud/occ config:system:set overwritewebroot --value=/nextcloud; \
|
/web/nextcloud/occ config:system:set overwritewebroot --value=/nextcloud; \
|
||||||
/web/nextcloud/occ config:system:set overwritehost --value=${MAILCOW_HOSTNAME}; \
|
/web/nextcloud/occ config:system:set overwritehost --value=${MAILCOW_HOSTNAME}; \
|
||||||
|
/web/nextcloud/occ config:system:set overwriteprotocol --value=https; \
|
||||||
/web/nextcloud/occ config:system:set mail_smtpmode --value=smtp; \
|
/web/nextcloud/occ config:system:set mail_smtpmode --value=smtp; \
|
||||||
/web/nextcloud/occ config:system:set mail_smtpauthtype --value=LOGIN; \
|
/web/nextcloud/occ config:system:set mail_smtpauthtype --value=LOGIN; \
|
||||||
/web/nextcloud/occ config:system:set mail_from_address --value=nextcloud; \
|
/web/nextcloud/occ config:system:set mail_from_address --value=nextcloud; \
|
||||||
|
@ -94,10 +96,11 @@ elif [[ ${NC_INSTALL} == "y" ]]; then
|
||||||
/web/nextcloud/occ config:system:set user_backends 0 class --value=OC_User_IMAP"
|
/web/nextcloud/occ config:system:set user_backends 0 class --value=OC_User_IMAP"
|
||||||
|
|
||||||
if [[ ${NC_TYPE} == "subdomain" ]]; then
|
if [[ ${NC_TYPE} == "subdomain" ]]; then
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set trusted_domains 1 --value=${NC_SUBD}
|
||||||
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritewebroot --value=/
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritewebroot --value=/
|
||||||
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritehost --value=${NC_SUBD}
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritehost --value=${NC_SUBD}
|
||||||
cp ./data/assets/nextcloud/nextcloud.conf ./data/conf/nginx/
|
cp ./data/assets/nextcloud/nextcloud.conf ./data/conf/nginx/
|
||||||
sed -i 's/NC_SUBD/${NC_SUBD}/g' ./data/conf/nginx/nextcloud.conf
|
sed -i "s/NC_SUBD/${NC_SUBD}/g" ./data/conf/nginx/nextcloud.conf
|
||||||
elif [[ ${NC_TYPE} == "subfolder" ]]; then
|
elif [[ ${NC_TYPE} == "subfolder" ]]; then
|
||||||
cp ./data/assets/nextcloud/site.nextcloud.custom ./data/conf/nginx/
|
cp ./data/assets/nextcloud/site.nextcloud.custom ./data/conf/nginx/
|
||||||
fi
|
fi
|
||||||
|
|
38
update.sh
38
update.sh
|
@ -6,7 +6,7 @@ done
|
||||||
|
|
||||||
[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing"; exit 1;}
|
[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing"; exit 1;}
|
||||||
|
|
||||||
CONFIG_ARRAY=("SKIP_LETS_ENCRYPT" "USE_WATCHDOG" "WATCHDOG_NOTIFY_EMAIL" "SKIP_CLAMD" "SKIP_IP_CHECK" "SKIP_FAIL2BAN" "ADDITIONAL_SAN" "DOVEADM_PORT")
|
CONFIG_ARRAY=("SKIP_LETS_ENCRYPT" "USE_WATCHDOG" "WATCHDOG_NOTIFY_EMAIL" "SKIP_CLAMD" "SKIP_IP_CHECK" "SKIP_FAIL2BAN" "ADDITIONAL_SAN" "DOVEADM_PORT" "IPV4_NETWORK" "IPV6_NETWORK" "LOG_LINES")
|
||||||
sed -i '$a\' mailcow.conf
|
sed -i '$a\' mailcow.conf
|
||||||
for option in ${CONFIG_ARRAY[@]}; do
|
for option in ${CONFIG_ARRAY[@]}; do
|
||||||
if [[ ${option} == "ADDITIONAL_SAN" ]]; then
|
if [[ ${option} == "ADDITIONAL_SAN" ]]; then
|
||||||
|
@ -32,8 +32,21 @@ for option in ${CONFIG_ARRAY[@]}; do
|
||||||
elif [[ ${option} == "LOG_LINES" ]]; then
|
elif [[ ${option} == "LOG_LINES" ]]; then
|
||||||
if ! grep -q ${option} mailcow.conf; then
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
|
echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf
|
||||||
echo "LOG_LINES=9999" >> mailcow.conf
|
echo "LOG_LINES=9999" >> mailcow.conf
|
||||||
fi
|
fi
|
||||||
|
elif [[ ${option} == "IPV4_NETWORK" ]]; then
|
||||||
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
|
echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf
|
||||||
|
echo "IPV4_NETWORK=172.22.1" >> mailcow.conf
|
||||||
|
fi
|
||||||
|
elif [[ ${option} == "IPV6_NETWORK" ]]; then
|
||||||
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
|
echo '# Internal IPv6 subnet in fd00::/8' >> mailcow.conf
|
||||||
|
echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf
|
||||||
|
fi
|
||||||
elif ! grep -q ${option} mailcow.conf; then
|
elif ! grep -q ${option} mailcow.conf; then
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo "${option}=n" >> mailcow.conf
|
echo "${option}=n" >> mailcow.conf
|
||||||
|
@ -45,7 +58,7 @@ curl -o /dev/null google.com -sm3
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo -e "\e[31mfailed\e[0m"
|
echo -e "\e[31mfailed\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
echo -e "\e[32mOK\e[0m"
|
echo -e "\e[32mOK\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -53,12 +66,14 @@ set -o pipefail
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
DATE=$(date +%Y-%m-%d_%H_%M_%S)
|
DATE=$(date +%Y-%m-%d_%H_%M_%S)
|
||||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
declare -a DC_PARAMS
|
||||||
|
|
||||||
case "${1}" in
|
while (($#)); do
|
||||||
|
case "${1}" in
|
||||||
--check|-c)
|
--check|-c)
|
||||||
echo "Checking remote code for updates..."
|
echo "Checking remote code for updates..."
|
||||||
git fetch origin ${BRANCH}
|
git fetch origin ${BRANCH}
|
||||||
if ! git diff origin/${BRANCH} --quiet; then
|
if [[ $(git branch ${BRANCH} --contains $(git rev-parse origin/${BRANCH}) > /dev/null 2> /dev/null; echo $?) != 0 ]]; then
|
||||||
echo "Updated code is available."
|
echo "Updated code is available."
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
|
@ -66,7 +81,11 @@ case "${1}" in
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
--no-start)
|
||||||
|
DC_PARAMS=(${DC_PARAMS[@]} "--no-start")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
echo -e "\e[32mChecking for newer update script...\e[0m"
|
echo -e "\e[32mChecking for newer update script...\e[0m"
|
||||||
SHA1_1=$(sha1sum update.sh)
|
SHA1_1=$(sha1sum update.sh)
|
||||||
|
@ -81,7 +100,7 @@ fi
|
||||||
|
|
||||||
if [[ -f mailcow.conf ]]; then
|
if [[ -f mailcow.conf ]]; then
|
||||||
source mailcow.conf
|
source mailcow.conf
|
||||||
else
|
else
|
||||||
echo -e "\e[31mNo mailcow.conf - is mailcow installed?\e[0m"
|
echo -e "\e[31mNo mailcow.conf - is mailcow installed?\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -132,7 +151,7 @@ if [[ $(curl -sL -w "%{http_code}" https://www.servercow.de/docker-compose/lates
|
||||||
LATEST_COMPOSE=$(curl -#L https://www.servercow.de/docker-compose/latest.php)
|
LATEST_COMPOSE=$(curl -#L https://www.servercow.de/docker-compose/latest.php)
|
||||||
curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $(which docker-compose)
|
curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $(which docker-compose)
|
||||||
chmod +x $(which docker-compose)
|
chmod +x $(which docker-compose)
|
||||||
else
|
else
|
||||||
echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m"
|
echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -146,7 +165,7 @@ cp -n data/assets/ssl-example/*.pem data/assets/ssl/
|
||||||
|
|
||||||
echo -e "\e[32mStarting mailcow...\e[0m"
|
echo -e "\e[32mStarting mailcow...\e[0m"
|
||||||
sleep 2
|
sleep 2
|
||||||
docker-compose up -d --remove-orphans
|
docker-compose up -d --remove-orphans ${DC_PARAMS[@]}
|
||||||
|
|
||||||
echo -e "\e[32mCollecting garbage...\e[0m"
|
echo -e "\e[32mCollecting garbage...\e[0m"
|
||||||
IMGS_TO_DELETE=()
|
IMGS_TO_DELETE=()
|
||||||
|
@ -155,12 +174,10 @@ for container in $(grep -oP "image: \Kmailcow.+" docker-compose.yml); do
|
||||||
TAG=${container/*:}
|
TAG=${container/*:}
|
||||||
V_MAIN=${container/*.}
|
V_MAIN=${container/*.}
|
||||||
V_SUB=${container/*.}
|
V_SUB=${container/*.}
|
||||||
|
|
||||||
EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }')
|
EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }')
|
||||||
for existing_tag in ${EXISTING_TAGS[@]}; do
|
for existing_tag in ${EXISTING_TAGS[@]}; do
|
||||||
V_MAIN_EXISTING=${existing_tag/*.}
|
V_MAIN_EXISTING=${existing_tag/*.}
|
||||||
V_SUB_EXISTING=${existing_tag/*.}
|
V_SUB_EXISTING=${existing_tag/*.}
|
||||||
|
|
||||||
# Not an integer
|
# Not an integer
|
||||||
[[ ! $V_MAIN_EXISTING =~ ^[0-9]+$ ]] && continue
|
[[ ! $V_MAIN_EXISTING =~ ^[0-9]+$ ]] && continue
|
||||||
[[ ! $V_SUB_EXISTING =~ ^[0-9]+$ ]] && continue
|
[[ ! $V_SUB_EXISTING =~ ^[0-9]+$ ]] && continue
|
||||||
|
@ -177,6 +194,7 @@ for container in $(grep -oP "image: \Kmailcow.+" docker-compose.yml); do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
|
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
|
||||||
echo "Run the following command to delete unused image tags:"
|
echo "Run the following command to delete unused image tags:"
|
||||||
echo
|
echo
|
||||||
|
|
Loading…
Reference in New Issue