Erverything runs/tests needed/ansible deploy needed

This commit is contained in:
Tobias Gehrke 2018-11-20 18:13:09 +01:00
commit 3a4ecf24f4
23 changed files with 932 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
traefik/acme*

43
README.md Normal file
View file

@ -0,0 +1,43 @@
# General
Postfix mta doesnt provide SNI, so there mailserver and lists must run on the same domain
# Configure
## Postfixadmin
1 - Go to the setup page : https://admin.domain.tld/setup.php
:bulb: Don't forget to add a new A/CNAME record in your DNS zone.
2 - Define the setup password
3 - Set the setup hash
```
docker exec -ti admin setup
> Postfixadmin setup hash : ffdeb741c58db70d060ddb170af4623a:54e0ac9a55d69c5e53d214c7ad7f1e3df40a3caa
Setup done.
```
4 - Create your admin account
5 - Go to the login page : https://admin.your-domain.tld/
6 - You can now create your domains, mailboxes, alias...etc :smiley:
![](http://i.imgur.com/4B7UMKi.png)
![](http://i.imgur.com/Jhoy5On.png)%
## mailman-web
Restore the Password for admin defined in docker-compose.yml via the defined mail address.

237
docker-compose.yml Normal file
View file

@ -0,0 +1,237 @@
version: '3'
services:
smtp:
container_name: smtp
build: ./smtp
restart: always
depends_on:
- imap
- db
ports:
- '25:25'
- '587:587'
links:
- imap:imap
- db:db
- spam:spam
volumes:
- ./smtp/main.cf:/etc/postfix/main.cf:ro
- ./smtp/master.cf:/etc/postfix/master.cf:ro
- /data/mailserver/mailman/data:/mailman
- mails:/home/vmail
- certs:/certs
environment:
- DATABASE_USER=mail
- DATABASE_PASSWORD=db_password
- DATABASE_NAME=postfix
- MYORIGIN=creditcards.bayern
- MYHOSTNAME=mail.creditcards.bayern
labels:
- "traefik.enable=false"
imap:
container_name: imap
build: ./imap
restart: always
depends_on:
- extractor
- db
ports:
- '993:993'
- '4190:4190'
expose:
- '24'
- '8472'
links:
- db
- spam
volumes:
- mails:/home/vmail
- certs:/certs
environment:
- "DATABASE_USER=mail"
- "DATABASE_PASSWORD=db_password"
- "DATABASE_NAME=postfix"
- "MAILDOMAIN=mail.creditcards.bayern"
labels:
- "traefik.enable=false"
spam:
container_name: spam
build: ./spam
restart: always
expose:
- 11334
volumes:
- spam:/data
- /etc/localtime:/etc/localtime:ro
environment:
- PASSWORD=nichtsicher
- PORT=11334
labels:
- "traefik.frontend.rule=Host:spam.creditcards.bayern"
- "traefik.port=11334"
webmail:
container_name: webmail
image: roundcube/roundcubemail:latest-apache
depends_on:
- smtp
- imap
- db
restart: always
links:
- imap:imap
- smtp:smtp
environment:
ROUNDCUBEMAIL_DEFAULT_HOST: imap
ROUNDCUBEMAIL_SMTP_SERVER: smtp
ROUNDCUBEMAIL_PLUGINS: archive,zipdownload,managesieve,password
ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE: 100M
ROUNDCUBEMAIL_DB_TYPE: mysql
ROUNDCUBEMAIL_DB_HOST: db
ROUNDCUBEMAIL_DB_USER: mail
ROUNDCUBEMAIL_DB_PASSWORD: BGun02otSchuj3z
ROUNDCUBEMAIL_DB_NAME: postfix
labels:
- "traefik.frontend.rule=Host:mail.creditcards.bayern"
- "traefik.port=80"
admin:
container_name: admin
links:
- db:db
depends_on:
- db
image: hardware/postfixadmin:latest
expose:
- "8888"
restart: always
environment:
DBTYPPE: mysql
DBHOST: db
DBUSER: mail
DBNAME: postfix
DBPASS: BGun02otSchuj3z
SMTPHOST: smtp
DOMAIN: creditcards.bayern
labels:
- "traefik.frontend.rule=Host:admin.creditcards.bayern"
- "traefik.port=8888"
db:
container_name: mariadb
image: mariadb:10.3
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASES: "postfix mailman"
MYSQL_USER: mail
MYSQL_PASSWORD: db_password
volumes:
- database:/var/lib/mysql
- ./docker-entrypoint.sh:/docker-entrypoint.sh
labels:
- "traefik.enable=false"
mailman-core:
image: maxking/mailman-core:latest
container_name: mailman-core
hostname: mailman-core
volumes:
- /data/mailserver/mailman/core:/opt/mailman/
- ./mailman-extra.cfg:/opt/mailman/core/mailman-extra.cfg
links:
- db
- smtp
- imap
depends_on:
- db
environment:
- DATABASE_URL=mysql://mail:db_password@db/mailman
- DATABASE_TYPE=mysql
- DATABASE_CLASS=mailman.database.mysql.MySQLDatabase
- HYPERKITTY_API_KEY=someapikey
labels:
- "traefik.enable=false"
mailman-web:
image: maxking/mailman-web:latest
container_name: mailman-web
hostname: mailman-web
expose:
- 8000
- 8080
depends_on:
- db
links:
- mailman-core:mailman-core
- db:db
volumes:
- /data/mailserver/mailman/web:/opt/mailman-web-data
environment:
- DATABASE_URL=mysql://mail:db_password@db/mailman
- DATABASE_TYPE=mysql
- HYPERKITTY_API_KEY=someapikey
- SECRET_KEY=thisisaverysecretkey
- DYLD_LIBRARY_PATH=/usr/local/mysql/lib/
- SERVE_FROM_DOMAIN=lists.creditcards.bayern
- DJANGO_ALLOWED_HOSTS=mailman.creditcards.bayern
- MAILMAN_ADMIN_USER=admin
- MAILMAN_ADMIN_EMAIL=a3x@eris.cc
- UWSGI_STATIC_MAP=/static=/opt/mailman-web-data/static
labels:
#- "traefik.frontend.rule=Host:mailman.creditcards.bayern"
#- "traefik.port=8000"
- "traefik.enable=false"
nginx:
container_name: nginx
image: nginx:mainline
restart: always
expose:
- 80
links:
- mailman-web:mailman-web
volumes:
- ./nginx/:/etc/nginx/conf.d/
- /data/mailserver/mailman/web:/opt/mailman/
labels:
- "traefik.frontend.rule=Host:mailman.creditcards.bayern"
- "traefik.port=80"
traefik:
container_name: traefik
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
restart: always
ports:
- "80:80" # The HTTP port
- "443:443"
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
- ./traefik/:/etc/traefik
labels:
- "traefik.frontend.rule=Host:traefik.creditcards.bayern"
extractor:
container_name: extractor
image: danielhuisman/traefik-certificate-extractor
volumes:
- /data/mailserver/traefik:/app/data
- certs:/app/certs_flat
labels:
- "traefik.enable=false"
volumes:
database:
mails:
certs:
spam:

206
docker-entrypoint.sh Executable file
View file

@ -0,0 +1,206 @@
#!/bin/bash
set -eo pipefail
shopt -s nullglob
# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
set -- mysqld "$@"
fi
# skip setup if they want an option that stops mysqld
wantHelp=
for arg; do
case "$arg" in
-'?'|--help|--print-defaults|-V|--version)
wantHelp=1
break
;;
esac
done
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}
_check_config() {
toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" )
if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
cat >&2 <<-EOM
ERROR: mysqld failed while attempting to check config
command was: "${toRun[*]}"
$errors
EOM
exit 1
fi
}
# Fetch value from server config
# We use mysqld --verbose --help instead of my_print_defaults because the
# latter only show values present in config files, and not server defaults
_get_config() {
local conf="$1"; shift
"$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null \
| awk '$1 == "'"$conf"'" && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }'
# match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)"
}
# allow the container to be started with `--user`
if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
_check_config "$@"
DATADIR="$(_get_config 'datadir' "$@")"
mkdir -p "$DATADIR"
find "$DATADIR" \! -user mysql -exec chown mysql '{}' +
exec gosu mysql "$BASH_SOURCE" "$@"
fi
if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
# still need to check config, container may have started with --user
_check_config "$@"
# Get config
DATADIR="$(_get_config 'datadir' "$@")"
if [ ! -d "$DATADIR/mysql" ]; then
file_env 'MYSQL_ROOT_PASSWORD'
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
echo >&2 'error: database is uninitialized and password option is not specified '
echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
exit 1
fi
mkdir -p "$DATADIR"
echo 'Initializing database'
# "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here)
mysql_install_db --datadir="$DATADIR" --rpm "${@:2}"
echo 'Database initialized'
SOCKET="$(_get_config 'socket' "$@")"
"$@" --skip-networking --socket="${SOCKET}" &
pid="$!"
mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
for i in {30..0}; do
if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
break
fi
echo 'MySQL init process in progress...'
sleep 1
done
if [ "$i" = 0 ]; then
echo >&2 'MySQL init process failed.'
exit 1
fi
if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
# sed is for https://bugs.mysql.com/bug.php?id=20545
mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql
fi
if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
fi
rootCreate=
# default root to listen for connections from anywhere
file_env 'MYSQL_ROOT_HOST' '%'
if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
# no, we don't care if read finds a terminating character in this heredoc
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
read -r -d '' rootCreate <<-EOSQL || true
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
EOSQL
fi
"${mysql[@]}" <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
${rootCreate}
DROP DATABASE IF EXISTS test ;
FLUSH PRIVILEGES ;
EOSQL
if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
mysql+=( -p"${MYSQL_ROOT_PASSWORD}" )
fi
file_env 'MYSQL_DATABASE'
if [ "$MYSQL_DATABASE" ]; then
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
mysql+=( "$MYSQL_DATABASE" )
fi
# create several databases using the MYSQL DATABASES env
#example: export MYSQL_DATABASES = "one two three"
file_env 'MYSQL_DATABASES'
if [ "$MYSQL_DATABASES" ]; then
for databaseName in $MYSQL_DATABASES; do
echo "CREATE DATABASE IF NOT EXISTS \`$databaseName\` ;" | "${mysql[@]}"
done
fi
file_env 'MYSQL_USER'
file_env 'MYSQL_PASSWORD'
if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
if [ "$MYSQL_DATABASE" ]; then
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
fi
#create the permissions for the different databases created with the db user
if [ "$MYSQL_DATABASES" ]; then
for databaseName in $MYSQL_DATABASES; do
echo "GRANT ALL ON \`$databaseName\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
done
fi
fi
echo
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sh) echo "$0: running $f"; . "$f" ;;
*.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
*) echo "$0: ignoring $f" ;;
esac
echo
done
if ! kill -s TERM "$pid" || ! wait "$pid"; then
echo >&2 'MySQL init process failed.'
exit 1
fi
echo
echo 'MySQL init process done. Ready for start up.'
echo
fi
fi
exec "$@"

12
imap/10-auth.conf Normal file
View file

@ -0,0 +1,12 @@
disable_plaintext_auth = yes
auth_mechanisms = plain login
passdb {
driver = sql
args = /etc/dovecot/sql.conf.ext
}
userdb {
driver = static
args = uid=vmail gid=vmail mail_home=/home/vmail/%d/%n mail_location=mbox:~/mail:INBOX=/home/vmail/%u
}

59
imap/10-master.conf Normal file
View file

@ -0,0 +1,59 @@
service imap-login {
inet_listener imap {
#port = 143
}
inet_listener imaps {
#port = 993
#ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
#port = 110
}
inet_listener pop3s {
#port = 995
#ssl = yes
}
}
service imap {
}
service pop3 {
}
service auth {
inet_listener {
address = * ::
port = 8472
}
unix_listener auth-userdb {
mode = 0600
user = vmail
}
user = dovecot
}
service auth-worker {
user = vmail
}
service dict {
unix_listener dict {
}
}
service lmtp {
inet_listener lmtp {
address = * ::
port = 24
}
}
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
}

3
imap/20-lmtp.conf Normal file
View file

@ -0,0 +1,3 @@
protocol lmtp {
mail_plugins = $mail_plugins sieve
}

8
imap/20-managesieve.conf Normal file
View file

@ -0,0 +1,8 @@
service managesieve-login {
}
service managesieve {
}
protocol sieve {
}

10
imap/90-sieve.conf Normal file
View file

@ -0,0 +1,10 @@
plugin {
sieve_extensions = +spamtest +spamtestplus
sieve_spamtest_status_type = score
sieve_spamtest_status_header = \
X-Spam-Score: (-?[[:digit:]]+\.[[:digit:]]).*
sieve_spamtest_max_value = 5.0
sieve_before = /var/lib/dovecot/sieve/global_sieves/move_to_spam_folder.sieve
}

26
imap/Dockerfile Normal file
View file

@ -0,0 +1,26 @@
FROM alpine:latest
RUN apk add --no-cache dovecot dovecot-pigeonhole-plugin
RUN adduser -u 5000 -g vmail -s /usr/bin/nologin -h /home/vmail -S vmail
RUN mkdir /etc/dovecot/sieve-filter
RUN ln -s /usr/bin/vendor_perl/spamc /etc/dovecot/sieve-filter/spamc
ADD dovecot.conf /etc/dovecot/dovecot.conf
ADD 10-auth.conf /etc/dovecot/conf.d/10-auth.conf
ADD 10-master.conf /etc/dovecot/conf.d/10-master.conf
ADD 20-lmtp.conf /etc/dovecot/conf.d/20-lmtp.conf
ADD 90-sieve.conf /etc/dovecot/conf.d/90-sieve.conf
ADD move_to_spam_folder.sieve /var/lib/dovecot/sieve/global_sieves/move_to_spam_folder.sieve
ADD ./start.sh /start.sh
RUN sievec /var/lib/dovecot/sieve/global_sieves
EXPOSE 993
ENTRYPOINT ["/start.sh"]

12
imap/dovecot.conf Normal file
View file

@ -0,0 +1,12 @@
#auth_verbose = yes
#auth_debug = yes
#auth_debug_passwords = yes
#auth_verbose_passwords = yes
#mail_debug = yes
log_path = /dev/stdout
!include_try /usr/share/dovecot/protocols.d/*.protocol
!include conf.d/*.conf
protocols = imap lmtp sieve

View file

@ -0,0 +1,8 @@
require "spamtestplus";
require "fileinto";
require "relational";
require "comparator-i;ascii-numeric";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
}

4
imap/sql.conf.ext Normal file
View file

@ -0,0 +1,4 @@
driver = mysql
connect = host=db dbname=postfix user=mail password=BGun02otSchuj3z
default_pass_scheme = SHA512-CRYPT
password_query = SELECT username as user, password FROM mailbox WHERE username='%u';

16
imap/start.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/sh
#if [ -n "${DATABASE_NAME}" -a -n "${DATABASE_USER}" -a -n "${DATABASE_PASSWORD}" ] ; then
echo -e "driver = mysql\n \
connect = host=db dbname=${DATABASE_NAME} user=${DATABASE_USER} password=${DATABASE_PASSWORD}\n \
default_pass_scheme = SHA512-CRYPT\n \
password_query = SELECT username as user, password FROM mailbox WHERE username='%u';" > /etc/dovecot/sql.conf.ext
#fi
#if [ -n "${MAILDOMAIN}" ]; then
echo -e "ssl = yes\n \
ssl_cert = </certs/${MAILDOMAIN}.crt\n \
ssl_key = </certs/${MAILDOMAIN}.key" > /etc/dovecot/conf.d/10-ssl.conf
#fi
dovecot -F

10
mailman-extra.cfg Normal file
View file

@ -0,0 +1,10 @@
# mailman-extra.cfg
[mta]
incoming: mailman.mta.postfix.LMTP
outgoing: mailman.mta.deliver.deliver
lmtp_host: imap
lmtp_port: 8472
smtp_host: smtp
smtp_port: 25
configuration: /etc/postfix-mailman.cfg

15
nginx/mailman-web.conf Normal file
View file

@ -0,0 +1,15 @@
server {
listen 80;
server_name mailman.creditcards.bayern;
location / {
# First attempt to serve request as file, then
uwsgi_pass mailman-web:8080;
include uwsgi_params;
uwsgi_read_timeout 300;
}
}

11
smtp/Dockerfile Normal file
View file

@ -0,0 +1,11 @@
FROM alpine:latest
RUN adduser -u 5000 -g vmail -s /usr/bin/nologin -h /home/vmail -S vmail
RUN apk add --no-cache postfix ca-certificates
ADD ./main.cf /etc/postfix/main.cf
ADD ./master.cf /etc/postfix/master.cf
ADD ./start.sh /start.sh
ENTRYPOINT ["/start.sh"]

90
smtp/main.cf Normal file
View file

@ -0,0 +1,90 @@
compatibility_level = 2
smtpd_banner = $myhostname ESMTP $mail_name (Hail Eris!)
biff = no
append_dot_mydomain = no
readme_directory = no
smtpd_helo_required = yes
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
unknown_address_reject_code = 554
unknown_hostname_reject_code = 554
unknown_client_reject_code = 554
#smtpd_tls_key_file=/certs/privkey.pem
#smtpd_tls_cert_file=/certs/cert.pem
smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtp_tls_security_level = may
smtpd_sasl_path = inet:imap:8472
smtpd_sasl_type = dovecot
smtpd_sasl_auth_enable = yes
smtputf8_enable = no
smtputf8_autodetect_classes = bounce
#smtpd_recipient_restrictions =
# permit_sasl_authenticated,
# permit_mynetworks,
# reject_unauth_destination
# Let's try ze new config stuff!
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_rbl_client ix.dnsbl.manitu.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client multi.surbl.org,
reject_rbl_client dnsbl-1.uceprotect.net,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client combined.rbl.msrbl.net,
reject_rbl_client b.barracudacentral.org,
reject_invalid_hostname,
reject_non_fqdn_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
reject_unauth_pipelining,
reject_unauth_destination,
reject_unlisted_recipient
smtpd_sender_restrictions =
# reject_sender_login_mismatch #too harsh
permit_sasl_authenticated
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.16.0.0/12
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
virtual_transport = lmtp:inet:imap:24
virtual_mailbox_domains = mysql:/etc/postfix/virtual_mailbox_domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/virtual_mailbox_maps.cf
virtual_alias_maps = mysql:/etc/postfix/virtual_alias_maps.cf
message_size_limit = 20480000
# Milter setup
smtpd_milters = inet:spam:11332
milter_default_action = accept
milter_protocol = 6
unknown_local_recipient_reject_code = 550
owner_request_special = no
transport_maps = hash:/mailman/var/data/postfix_lmtp
local_recipient_maps = hash:/mailman/var/data/postfix_lmtp
relay_domains = hash:/mailman/var/data/postfix_domains

55
smtp/master.cf Normal file
View file

@ -0,0 +1,55 @@
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - - - - smtpd
-o content_filter=spamassassin
submission inet n - - - - smtpd
-o syslog_name=postfix/submission
-o smtpd_sasl_auth_enable=yes
pickup unix n - - 60 1 pickup
cleanup unix n - - - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - - 1000? 1 tlsmgr
rewrite unix - - - - - trivial-rewrite
bounce unix - - - - 0 bounce
defer unix - - - - 0 bounce
trace unix - - - - 0 bounce
verify unix - - - - 1 verify
flush unix n - - 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - - - - smtp
relay unix - - - - - smtp
showq unix n - - - - showq
error unix - - - - - error
retry unix - - - - - error
discard unix - - - - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - - - - lmtp
anvil unix - - - - 1 anvil
scache unix - - - - 1 scache
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}

36
smtp/start.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/sh
#if [ -n "${MYORIGIN}" -a -n "${MYHOSTNAME}" ]; then
echo -e "myorigin = ${MYORIGIN}\n \
myhostname = ${MYHOSTNAME} \
smtpd_tls_key_file = /certs/${MYHOSTNAME}.key \
smtpd_tls_cert_file=/certs/${MYHOSTNAME}.crt" >> /etc/postfix/main_addendum.cf
#fi
#if [ -n "${DATABASE_USER}" -a -n "${DATBASE_PASSWORD}" -a -n "${DATABASE_NAME}" ]; then
echo -e "user = ${DATABASE_USER}\n \
password = ${DATABASE_PASSWORD}\n \
hosts = db\n \
dbname = ${DATABASE_NAME}\n \
table = alias\n \
select_field = goto\n \
where_field = address" > /etc/postfix/virtual_alias_maps.cf;
echo -e "user = ${DATABASE_USER}\n \
password = ${DATABASE_PASSWORD}\n \
hosts = db\n \
dbname = ${DATABASE_NAME}\n \
table = domain\n \
select_field = domain\n \
where_field = domain" > /etc/postfix/virtual_mailbox_domains.cf;
echo -e "user = ${DATABASE_USER}\n \
password = ${DATABASE_PASSWORD}\n \
hosts = db\n \
dbname = ${DATABASE_NAME}\n \
table = mailbox\n \
select_field = maildir\n \
where_field = username" > /etc/postfix/virtual_mailbox_maps.cf;
#fi
postfix start-fg

15
spam/Dockerfile Normal file
View file

@ -0,0 +1,15 @@
FROM alpine:edge
# We have to upgrade musl, or rspamd will not work.
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
&& apk add --no-cache rspamd rspamd-controller rsyslog ca-certificates
RUN mkdir /run/rspamd
RUN echo 'type = "console";' > /etc/rspamd/override.d/logging.inc \
&& echo 'pidfile = false;' > /etc/rspamd/override.d/options.inc
COPY start.sh /start.sh
CMD ["/start.sh"]

14
spam/start.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
SECURE_IP=${SECURE_IP:-"127.0.0.1"}
PASSWORD=${PASSWORD:-"mailu"}
ENABLE_PASSWORD=${ENABLE_PASSWORD:-$PASSWORD}
cat << EOF > /etc/rspamd/override.d/worker-controller.inc
bind_socket = "0.0.0.0:${PORT}";
secure_ip = "${SECURE_IP}";
password = "${PASSWORD}";
enable_password = "${PASSWORD}";
EOF
/usr/sbin/rspamd -f --insecure

41
traefik/traefik.toml Normal file
View file

@ -0,0 +1,41 @@
debug = false
logLevel = "ERROR"
defaultEntryPoints = ["https","http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
minVersion = "VersionTLS11"
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
]
[api]
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "creditcards.bayern"
watch = true
exposedByDefault = false
[acme]
email = "noc@creditcards.bayern"
storage = "/etc/traefik/acme.json"
entryPoint = "https"
onHostRule = true
KeyType = "EC256"
keyType = "EC256"
[acme.httpChallenge]
entryPoint = "http"