Compare commits

77 Commits
master ... 1.5

Author SHA1 Message Date
70251ea215 Downgrade postfix back to 1.4 configuration 2021-04-26 21:52:18 +02:00
87ac211e03 Fixes 2021-04-26 20:23:45 +02:00
eb8380fa5b Fix python3 compatibility 2021-04-26 18:31:20 +02:00
a6491fd87f Fix build.sh 2021-04-26 18:25:46 +02:00
4ab9ba97ca Update to alpine 3.13 2021-04-26 18:24:31 +02:00
e2aa247c2d Fix rspamd 2021-04-26 18:20:48 +02:00
Tim Möhlmann
f75b2fb631 Disable healthcheck, like on master 2018-12-17 00:30:26 +02:00
Tim Möhlmann
0739224fc4 Add dockerfile and enable Docs build 2018-12-17 00:19:44 +02:00
Tim Möhlmann
fc83a7d829 Merge pull request #749 from usrpro/1.5-autobuild
1.5 autobuild
2018-12-16 23:43:56 +02:00
mergify-bot
2b1ed25148 Merge branch '1.5' into '1.5-autobuild' 2018-12-16 22:36:47 +01:00
kaiyou
a4551870aa Backport documentation build from master 2018-12-16 22:31:28 +01:00
Tim Möhlmann
6869b3096b Use MAILU_VERSION from Travis for Docs build 2018-12-15 21:46:30 +02:00
Tim Möhlmann
1c39af464d Move radicale to edge in able to build 2018-12-15 21:00:58 +02:00
Tim Möhlmann
f02a183694 Enable Travis autobuilds for 1.5
This is a simplified backport from master, whitout any testing.
2018-12-15 20:52:57 +02:00
Tim Möhlmann
cd80fda12e Merge pull request #735 from HorayNarea/fix-dhparam
fix dhparam.pem shadowing in 1.5
2018-12-08 11:58:15 +02:00
kaiyou
8c7138d69b Move dhparam to /conf 2018-12-08 09:02:26 +01:00
kaiyou
28f8e69ebb Merge pull request #709 from rbarazzutti/1.5-htaccess-php7
1.5 htaccess php7
2018-12-06 10:01:57 +01:00
kaiyou
09934c460c Merge pull request #706 from usrpro/backport-incl-dhparam
Use a predefined dhparam.pem (Backport)
2018-12-06 10:00:40 +01:00
Raphaël P. Barazzutti
18f4f0bed8 adapt the .htaccess file for PHP7 as required 2018-11-18 10:27:08 +01:00
Greg Fitzgerald
e2ce62cbd0 Use a predefined dhparam.pem, This fixes issue #322 2018-11-09 13:34:28 +02:00
kaiyou
a36fc369f9 Merge pull request #658 from bluedynamics/backport/309-Announces-fail
Only check login mismatch for authenticated users, fixes #309
2018-10-16 19:49:25 +02:00
Pierre Jaury
c91953b5df Only check login mismatch for authenticated users, fixes #309 2018-10-15 16:05:55 +02:00
kaiyou
790e32cfb8 Merge pull request #572 from ofthesun9/1.5-alpine_3.8
alpine 3.8 for nginx front container
2018-10-07 11:56:23 +02:00
kaiyou
bbcf3edb10 Merge branch '1.5' into 1.5-alpine_3.8 2018-10-07 11:56:13 +02:00
kaiyou
e4b63cb043 Merge pull request #617 from HorayNarea/patch-3
backport fix for #474 to 1.5
2018-10-06 19:08:50 +02:00
kaiyou
a7a27625cc Merge pull request #621 from usrpro/fix-1.5-no-travis
1.5: Travis to always succeed
2018-10-06 17:14:47 +02:00
Tim Möhlmann
57188345f0 Travis to always succeed 2018-10-01 00:44:37 +03:00
Thomas Sänger
4dd66e4964 backport fix for #474 to 1.5 2018-09-29 15:59:36 +02:00
kaiyou
cfff8953e5 Merge pull request #556 from usrpro/patch-1
Libpng12-dev is now called libpng-dev
2018-09-16 19:56:09 +02:00
kaiyou
9bf6f84c05 Merge pull request #557 from usrpro/1.5
Pin Alpine 3.7
2018-09-16 19:55:16 +02:00
kaiyou
cd0bc5562a Merge pull request #587 from nasa9084/patch-1
fix typo
2018-09-16 19:47:53 +02:00
nasa9084
eb4e65be64 fix typo 2018-09-14 15:59:19 +09:00
Hypriot Pirate
5d26c9a097 fix for #522 2018-08-18 13:08:36 +00:00
Tim Möhlmann
f0e56bb80e Libpng12-dev is now called libpng-dev
Like PR #514, this prevents re-building the image in the 1.5 branch.
2018-08-07 19:13:17 +03:00
Tim Möhlmann
465ccda95f Pin Alpine 3.7 to preserve the Postfix version 2018-08-07 18:38:22 +03:00
kaiyou
e14fcd1b8a Merge pull request #549 from muhlemmer/1.5
Use alpine:3.7 tag to prevent postix upgrade
2018-08-03 08:19:53 +02:00
kaiyou
4d62861b78 Pin alpine 3.7 2018-08-03 07:25:36 +02:00
kaiyou
550470d604 Pin alpine 3.7 in order to preserve Postfix version 2018-08-03 07:24:20 +02:00
Tim Möhlmann
43b64229d1 Use alpine:3.7 tag to prevent postix upgrade 2018-08-03 00:31:28 +03:00
kaiyou
ad6bc4060d Merge pull request #536 from WBasson/patch-1
Update index.rst
2018-08-01 21:08:20 +02:00
WBasson
53da190863 Update index.rst
administration was mis-spelled
2018-07-26 11:00:10 +02:00
ofthesun9
6674af8881 Switching to alpine:3.8 2018-07-21 15:19:43 +00:00
kaiyou
c24cabc305 Merge pull request #488 from ofthesun9/1.5
Fix rspamd behavior, currently failing due to worker-fuzzy for 1.5
2018-06-03 17:06:53 +02:00
ofthesun9
ce4db065c6 Fix rspamd behavior, currently failing due to worker-fuzzy for 1.5 2018-06-03 11:35:53 +00:00
kaiyou
3e6f0d7842 Merge pull request #486 from ofthesun9/1.5
Do not remove openssl when purging build deps, fixes #481
2018-06-03 11:48:57 +02:00
Pierre Jaury
11f145da8c Do not remove openssl when purging build deps, fixes #481 2018-06-03 09:51:49 +02:00
Pierre Jaury
6a3236200d Fix the path of the nginx pid in startup scripts, fixes #483
(cherry picked from commit 6828231c28)
2018-06-02 10:23:58 +02:00
kaiyou
e17c587b78 Remove a reference to 1.5.1 2018-04-21 12:29:55 +02:00
kaiyou
9caab592ed Switch to edge for clamav 2018-03-21 21:25:22 +01:00
AdrienM
6afde67525 Add explicit ssl_protocols in conf 2018-03-21 08:20:24 +01:00
kaiyou
564f5ad070 Merge pull request #397 from pbinks/patch-2
Update setup.rst
2018-03-05 21:21:35 +01:00
kaiyou
fb74adf1dc Remove the reference to stable in the setup docs, fixes #393
(cherry picked from commit a0d7b987ca)
2018-03-05 21:19:29 +01:00
kaiyou
91bb76ecd3 Merge pull request #402 from pbinks/patch-7
Update cli.rst
2018-03-05 20:46:47 +01:00
kaiyou
f7dfee4c60 Merge pull request #401 from pbinks/patch-6
Update maintain.rst
2018-03-05 20:46:28 +01:00
kaiyou
dbe0cfe129 Merge pull request #400 from pbinks/patch-5
Update reverse.rst
2018-03-05 20:45:45 +01:00
kaiyou
fdeb302eff Merge pull request #399 from pbinks/patch-4
Update dns.rst
2018-03-05 20:45:28 +01:00
kaiyou
8eeb9b22b4 Merge pull request #398 from pbinks/patch-3
Update index.rst
2018-03-05 20:45:12 +01:00
kaiyou
b362940388 Merge pull request #396 from pbinks/patch-1
Update requirements.rst
2018-03-05 20:41:58 +01:00
Paul Binks
ce01389669 Update cli.rst 2018-03-01 16:49:30 +00:00
Paul Binks
37ba915e7b Update maintain.rst 2018-03-01 16:46:21 +00:00
Paul Binks
6c47dfb997 Update reverse.rst 2018-03-01 16:41:17 +00:00
Paul Binks
4b6e48d826 Update dns.rst 2018-03-01 16:36:43 +00:00
Paul Binks
2f7dbe92bf Update index.rst 2018-03-01 16:33:13 +00:00
Paul Binks
0ff9d3c953 Update setup.rst 2018-03-01 16:30:13 +00:00
Paul Binks
cce0de24e9 Update requirements.rst 2018-03-01 16:20:43 +00:00
kaiyou
2b144bc574 Specify the client max body size in the front, related to #371
(cherry picked from commit 6c56c8e298)
2018-02-19 14:18:35 +01:00
kaiyou
449af8eb0b Make sure stale pid files are dealt with, fix #341
(cherry picked from commit 4761646616)
2018-02-08 21:09:32 +01:00
Rafael Cossovan
e03097b505 Update configuration.rst
Fix env variable.

(cherry picked from commit 23f392efb2)
2018-02-01 00:41:46 +01:00
kaiyou
c157088385 Set the temp directory for Roundcube, related to #365
(cherry picked from commit 34d88144b2)
2017-12-19 22:19:38 +01:00
kaiyou
4ce3a04287 Use relative redirect for / to the webmail
(cherry picked from commit acb5d7da38)
2017-12-05 20:08:36 +01:00
kaiyou
8854d76bcc Use a map for passing x-forwarded-proto along
(cherry picked from commit 2dfc91ac4d)
2017-12-05 20:08:29 +01:00
kaiyou
13ffb85912 Remove a remaining rebug print() statement
(cherry picked from commit 42314d3d75)
2017-12-05 20:08:19 +01:00
kaiyou
f5b78ffff0 Properly use x-forwarded-proto with redirects in the webui, related to #347
(cherry picked from commit a4f46ced49)
2017-12-05 20:08:11 +01:00
kaiyou
46dc9b0b16 Fix the Webdav behavior with Radicale, related to #334 2017-11-30 22:03:22 +01:00
kaiyou
820f6dee82 Merge branch '1.5' into 1.5.1 2017-11-26 22:10:36 +01:00
kaiyou
92c21613ff Set the title of web pages in the docs
(cherry picked from commit 03d3351496)
2017-11-21 22:44:11 +01:00
kaiyou
017a2611cc Release version 1.5.1 2017-11-21 22:05:23 +01:00
55 changed files with 353 additions and 191 deletions

View File

@@ -1,8 +1,29 @@
sudo: required
services: docker
addons:
apt:
packages:
- docker-ce
env:
- MAILU_VERSION=$TRAVIS_BRANCH
language: python
python:
- "3.6"
install:
- pip install -r docs/requirements.txt
- sudo curl -L https://github.com/docker/compose/releases/download/1.23.0-rc3/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
- sudo chmod +x /usr/local/bin/docker-compose
before_script:
- docker-compose -v
- docker-compose -f tests/build.yml build
script:
- sphinx-versioning build -b -B 1.5 -r 1.5 -w '^[0-9.]*$' -w master -W '^$' docs/ build/
- python docs/conf.py build $DEPLOY_HOST $DEPLOY_USERNAME $DEPLOY_PASSWORD $DEPLOY_REMOTEDIR
- /bin/true
deploy:
provider: script
script: bash tests/deploy.sh
on:
all_branches: true
condition: -n $DOCKER_UN

26
build.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash -e
TAG="1.5-$(date +%Y%m%d)"
build() {
image=$1
echo "[INFO] Building ${image}"
docker build -t ${image} .
docker push ${image}
}
if [ -z "$1" ]; then
find . -name Dockerfile | while read i; do
dir=$(dirname $i)
pushd ${dir} >/dev/null
image="genunix/mailu-$(basename $dir):${TAG}"
build ${image}
popd >/dev/null
done
else
dir=$(basename $1)
image="genunix/mailu-$(basename $dir):${TAG}"
pushd "$1" >/dev/null
build "$image"
popd >/dev/null
fi

View File

@@ -1,10 +1,11 @@
FROM python:3-alpine
FROM python:3-alpine3.13
RUN mkdir -p /app
WORKDIR /app
COPY requirements-prod.txt requirements.txt
RUN apk --update add --virtual build-dep openssl-dev libffi-dev python-dev build-base \
RUN apk add --no-cache openssl \
&& apk add --no-cache --virtual build-dep openssl-dev libffi-dev python3-dev build-base \
&& pip install -r requirements.txt \
&& apk del build-dep

View File

@@ -12,6 +12,8 @@ import docker
import socket
import uuid
from werkzeug.contrib import fixers
# Create application
app = flask.Flask(__name__)
@@ -115,4 +117,4 @@ class PrefixMiddleware(object):
environ['SCRIPT_NAME'] = prefix
return self.app(environ, start_response)
app.wsgi_app = PrefixMiddleware(app.wsgi_app)
app.wsgi_app = PrefixMiddleware(fixers.ProxyFix(app.wsgi_app))

View File

@@ -1,9 +1,9 @@
FROM alpine:edge
FROM alpine:3.13
RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
&& apk add --no-cache \
dovecot dovecot-sqlite dovecot-pigeonhole-plugin dovecot-pigeonhole-plugin-extdata \
rspamd-client@testing python py-jinja2
dovecot dovecot-sqlite dovecot-pigeonhole-plugin \
rspamd-client python3 py3-jinja2
COPY conf /conf
COPY sieve /var/lib/dovecot

View File

@@ -57,6 +57,7 @@ namespace inbox {
###############
auth_mechanisms = plain login
disable_plaintext_auth = no
ssl_protocols = !SSLv3
passdb {
driver = sql

View File

@@ -1,3 +1,11 @@
require "vnd.dovecot.execute";
require ["vnd.dovecot.execute", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string "${mailbox}" "Trash" {
stop;
}
execute :pipe "mailtrain" "ham";

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import jinja2
import os

View File

@@ -1,6 +1,9 @@
FROM alpine:edge
FROM alpine:3.13
RUN apk add --no-cache nginx nginx-mod-mail python py-jinja2 certbot openssl
RUN apk add --no-cache nginx nginx-mod-mail python3 py3-jinja2 certbot openssl
# added to fix #522
RUN apk add --no-cache py-requests-toolbelt py-pip
RUN pip install "idna<2.7"
COPY conf /conf
COPY *.py /

View File

@@ -0,0 +1,13 @@
-----BEGIN DH PARAMETERS-----
MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=
-----END DH PARAMETERS-----

View File

@@ -20,6 +20,12 @@ http {
absolute_redirect off;
resolver {{ RESOLVER }} valid=30s;
# Header maps
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
default $http_x_forwarded_proto;
'' $scheme;
}
# Main HTTP server
server {
# Variables for proxifying
@@ -65,13 +71,14 @@ http {
# Actual logic
{% if WEBMAIL != 'none' %}
location / {
return 301 $scheme://$host/webmail/;
return 301 {{ WEB_WEBMAIL }};
}
location {{ WEB_WEBMAIL }} {
rewrite ^({{ WEB_WEBMAIL }})$ $1/ permanent;
rewrite ^{{ WEB_WEBMAIL }}/(.*) /$1 break;
proxy_set_header Host $host;
include /etc/nginx/proxy.conf;
client_max_body_size 30M;
proxy_pass http://$webmail;
}
{% endif %}
@@ -83,8 +90,8 @@ http {
location ~ {{ WEB_ADMIN }}/(ui|static) {
rewrite ^{{ WEB_ADMIN }}/(.*) /$1 break;
include /etc/nginx/proxy.conf;
proxy_set_header X-Forwarded-Prefix {{ WEB_ADMIN }};
proxy_set_header Host $host;
proxy_pass http://$admin;
}
@@ -102,9 +109,15 @@ http {
rewrite ^/webdav/(.*) /$1 break;
auth_request /internal/auth/basic;
auth_request_set $user $upstream_http_x_user;
include /etc/nginx/proxy.conf;
proxy_set_header X-Remote-User $user;
proxy_set_header X-Script-Name /webdav;
proxy_pass http://$webdav;
}
location ~ ^/.well-known/(carddav|caldav) {
return 301 /webdav/;
}
{% endif %}
{% endif %}

View File

@@ -0,0 +1,5 @@
# Default proxy setup
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;

View File

@@ -4,4 +4,4 @@ ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_certificate {{ TLS[0] }};
ssl_certificate_key {{ TLS[1] }};
ssl_dhparam /certs/dhparam.pem;
ssl_dhparam /conf/dhparam.pem;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import jinja2
import os
@@ -29,5 +29,7 @@ if args["TLS"] and not all(os.path.exists(file_path) for file_path in args["TLS"
# Build final configuration paths
convert("/conf/tls.conf", "/etc/nginx/tls.conf", args)
convert("/conf/proxy.conf", "/etc/nginx/proxy.conf", args)
convert("/conf/nginx.conf", "/etc/nginx/nginx.conf", args)
os.system("nginx -s reload")
if os.path.exists("/var/run/nginx.pid"):
os.system("nginx -s reload")

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import os
import time

View File

@@ -1,12 +1,11 @@
#!/usr/bin/python
#!/usr/bin/python3
import os
import subprocess
# Actual startup script
if not os.path.exists("/certs/dhparam.pem") and os.environ["TLS_FLAVOR"] != "notls":
os.system("openssl dhparam -out /certs/dhparam.pem 4096")
# Check if a stale pid file exists
if os.path.exists("/var/run/nginx.pid"):
os.remove("/var/run/nginx.pid")
if os.environ["TLS_FLAVOR"] == "letsencrypt":
subprocess.Popen(["/letsencrypt.py"])

View File

@@ -1,5 +1,5 @@
# This is an idle image to dynamically replace any component if disabled.
FROM alpine
FROM alpine:3.13
CMD sleep 1000000d

View File

@@ -1,8 +1,10 @@
FROM alpine
FROM alpine:3.13
RUN apk add --no-cache postfix postfix-sqlite postfix-pcre rsyslog python py-jinja2
RUN apk add --no-cache bash postfix postfix-sqlite postfix-pcre rsyslog
COPY conf /conf
COPY start.py /start.py
COPY conf /etc/postfix
COPY rsyslog.conf /etc/rsyslog.conf
CMD /start.py
COPY start.sh /start.sh
CMD ["/start.sh"]

View File

@@ -4,12 +4,9 @@
# Main domain and hostname
mydomain = {{ DOMAIN }}
myhostname = {{ HOSTNAMES.split(",")[0] }}
myhostname = {{ HOSTNAME }}
myorigin = $mydomain
# Queue location
queue_directory = /queue
# Message size limit
message_size_limit = {{ MESSAGE_SIZE_LIMIT }}
@@ -28,12 +25,6 @@ mydestination =
# Relayhost if any is configured
relayhost = {{ RELAYHOST }}
# Recipient delimiter for extended addresses
recipient_delimiter = {{ RECIPIENT_DELIMITER }}
# Only the front server is allowed to perform xclient
smtpd_authorized_xclient_hosts={{ FRONT_ADDRESS }}
###############
# TLS
###############
@@ -41,14 +32,47 @@ smtpd_authorized_xclient_hosts={{ FRONT_ADDRESS }}
# General TLS configuration
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
tls_preempt_cipherlist = yes
tls_ssl_options = NO_COMPRESSION
# Only one key/certificate pair is used, SNI not being supported by all
# services and not a strong requirement. Also, TLS is enforced for submission
# and smtps in master.cf.
smtpd_tls_security_level = may
smtpd_tls_cert_file=/certs/cert.pem
smtpd_tls_key_file=/certs/key.pem
smtpd_tls_session_cache_database = lmdb:${data_directory}/smtpd_scache
# Server-side TLS is hardened, it should be up to the client to update his or
# her TLS stack in order to connect to the mail server. Hardening is based on
# https://bettercrypto.org/static/applied-crypto-hardening.pdf
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
# Outgoing TLS is more flexible because 1. not all receiving servers will
# support TLS, 2. not all will have and up-to-date TLS stack.
smtp_tls_security_level = may
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
smtp_tls_protocols =!SSLv2,!SSLv3
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_session_cache_database = lmdb:${data_directory}/smtp_scache
# General TLS hardening
tls_ssl_options = NO_COMPRESSION
tls_preempt_cipherlist = yes
###############
# SASL
###############
smtpd_sasl_local_domain = $myhostname
# Authentication is done against dovecot, which acts as the main authention
# source
smtpd_sasl_type = dovecot
smtpd_sasl_path = inet:imap:2102
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
###############
# Virtual
@@ -60,8 +84,7 @@ virtual_alias_maps = ${sql}sqlite-virtual_alias_maps.cf
virtual_mailbox_domains = ${sql}sqlite-virtual_mailbox_domains.cf
virtual_mailbox_maps = $virtual_alias_maps
# Mails are transported if required, then forwarded to Dovecot for delivery
transport_maps = ${sql}sqlite-transport.cf
# Mails are forwarded to Dovecot for delivery
virtual_transport = lmtp:inet:imap:2525
# In order to prevent Postfix from running DNS query, enforce the use of the
@@ -78,22 +101,31 @@ smtpd_delay_reject = yes
# Allowed senders are: the user or one of the alias destinations
smtpd_sender_login_maps = $virtual_alias_maps
# Restrictions for incoming SMTP, other restrictions are applied in master.cf
# Helo restrictions are specified for smtp only in master.cf
smtpd_helo_required = yes
# Sender restrictions
smtpd_sender_restrictions =
permit_mynetworks,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
reject_unlisted_sender,
reject_sender_login_mismatch,
permit
# Recipient restrictions:
smtpd_recipient_restrictions =
permit_mynetworks,
check_sender_access ${sql}sqlite-reject-spoofed.cf,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit
reject_unauth_pipelining,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
permit_mynetworks,
permit
###############
# Milter
###############
smtpd_milters = inet:antispam:11332
smtpd_milters = inet:milter:9900
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_default_action = tempfail

View File

@@ -1,16 +1,24 @@
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# Exposed SMTP service
# Exposed SMTP services
smtp inet n - n - - smtpd
# Internal SMTP service
10025 inet n - n - - smtpd
-o smtpd_helo_restrictions=permit_mynetworks,permit
submission inet n - n - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=reject_unlisted_sender,reject_sender_login_mismatch,permit
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o cleanup_service_name=outclean
outclean unix n - n - 0 cleanup
-o header_checks=pcre:/etc/postfix/outclean_header_filter.cf
smtps inet n - n - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_wrappermode=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o cleanup_service_name=outclean
# Additional services
outclean unix n - n - 0 cleanup
-o header_checks=pcre:/etc/postfix/outclean_header_filter
# Internal postfix services
pickup unix n - n 60 1 pickup

View File

@@ -1,17 +0,0 @@
# This configuration was copied from Mailinabox. The original version is available at:
# https://raw.githubusercontent.com/mail-in-a-box/mailinabox/master/conf/postfix_outgoing_mail_header_filters
# Remove the first line of the Received: header. Note that we cannot fully remove the Received: header
# because OpenDKIM requires that a header be present when signing outbound mail. The first line is
# where the user's home IP address would be.
/^\s*Received:[^\n]*(.*)/ REPLACE Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP])$1
# Remove other typically private information.
/^\s*User-Agent:/ IGNORE
/^\s*X-Enigmail:/ IGNORE
/^\s*X-Mailer:/ IGNORE
/^\s*X-Originating-IP:/ IGNORE
/^\s*X-Pgp-Agent:/ IGNORE
# The Mime-Version header can leak the user agent too, e.g. in Mime-Version: 1.0 (Mac OS X Mail 8.1 \(2010.6\)).
/^\s*(Mime-Version:\s*[0-9\.]+)\s.+/ REPLACE $1

View File

@@ -1,4 +0,0 @@
$ModLoad imuxsock
$template noTimestampFormat,"%syslogtag%%msg%\n"
$ActionFileDefaultTemplate noTimestampFormat
*.*;auth,authpriv.none /dev/stdout

View File

@@ -1,5 +0,0 @@
dbpath = /data/main.db
query =
SELECT 'REJECT' FROM domain WHERE name='%s'
UNION
SELECT 'REJECT' FROM alternative WHERE name='%s'

View File

@@ -1,3 +0,0 @@
dbpath = /data/main.db
query =
SELECT 'smtp:['||smtp||']' FROM relay WHERE name='%s'

View File

@@ -4,9 +4,7 @@ query =
FROM
(SELECT destination, email, wildcard, localpart FROM alias
UNION
SELECT (CASE WHEN forward_enabled=1 THEN (CASE WHEN forward_keep=1 THEN email||',' ELSE '' END)||forward_destination ELSE email END) AS destination, email, 0 as wildcard, localpart FROM user
UNION
SELECT '@'||domain_name as destination, '@'||name as email, 0 as wildcard, '' as localpart FROM alternative)
SELECT email||(CASE WHEN forward_enabled=1 THEN ','||forward_destination ELSE '' END) AS destination, email, 0 as wildcard, localpart FROM user)
WHERE
(
wildcard = 0

View File

@@ -1,5 +1,2 @@
dbpath = /data/main.db
query =
SELECT name FROM domain WHERE name='%s'
UNION
SELECT name FROM alternative WHERE name='%s'
query = SELECT name FROM domain WHERE name='%s'

View File

@@ -1,38 +0,0 @@
#!/usr/bin/python
import jinja2
import os
import socket
import glob
import shutil
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
# Actual startup script
os.environ["FRONT_ADDRESS"] = socket.gethostbyname("front")
for postfix_file in glob.glob("/conf/*.cf"):
convert(postfix_file, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
if os.path.exists("/overrides/postfix.cf"):
for line in open("/overrides/postfix.cf").read().strip().split("\n"):
os.system('postconf -e "{}"'.format(line))
if os.path.exists("/overrides/postfix.master"):
for line in open("/overrides/postfix.master").read().strip().split("\n"):
os.system('postconf -Me "{}"'.format(line))
for map_file in glob.glob("/overrides/*.map"):
destination = os.path.join("/etc/postfix", os.path.basename(map_file))
shutil.copyfile(map_file, destination)
os.system("postmap {}".format(destination))
os.remove(destination)
convert("/conf/rsyslog.conf", "/etc/rsyslog.conf")
# Run postfix
if os.path.exists("/var/run/rsyslogd.pid"):
os.remove("/var/run/rsyslogd.pid")
os.system("/usr/lib/postfix/post-install meta_directory=/etc/postfix create-missing")
os.system("/usr/lib/postfix/master &")
os.execv("/usr/sbin/rsyslogd", ["rsyslogd", "-n"])

20
docs/Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM python:3-alpine
COPY requirements.txt /requirements.txt
ARG version=master
ENV VERSION=$version
RUN pip install -r /requirements.txt \
&& apk add --no-cache nginx curl \
&& mkdir /run/nginx
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY . /docs
RUN mkdir -p /build/$VERSION \
&& sphinx-build /docs /build/$VERSION
EXPOSE 80/tcp
CMD nginx -g "daemon off;"

View File

@@ -1,2 +1,9 @@
{% set version=github_version %}
{% extends "!layout.html" %}
{% block document %}
{% if version != stable_version %}
<div class="wy-alert info">
<p>You are currently browsing documentation for the <b>{{ version }}</b> branch. Documentation for the stable <b>{{ stable_version }}</b> branch can be found <a href="/{{ stable_version }}/">here</a>.</p>
</div>
{% endif %}
{{ super() }}
{% endblock %}

16
docs/_templates/versions.html vendored Normal file
View File

@@ -0,0 +1,16 @@
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span class="fa fa-book"> Versions</span>
v: {{ version }}
<span class="fa fa-caret-down"></span>
</span>
<div class="rst-other-versions">
<dl>
<dt>{{ _('Versions') }}</dt>
{% for slug, url in versions %}
<dd><a href="{{ url }}">{{ slug }}</a></dd>
{% endfor %}
</dl>
</div>
</div>

View File

@@ -51,7 +51,7 @@ user_delete
config_update
-------------
This command sole purpose is for importing users/aliases in bulk and synchronizing DB entries with external YAML template:
The sole purpose of this command is for importing users/aliases in bulk and synchronizing DB entries with external YAML template:
.. code-block:: bash

View File

@@ -12,7 +12,7 @@
ROOT=/mailu
# Mailu version to run (1.0, 1.1, etc. or master)
VERSION=master
VERSION=1.5
# Set to a randomly generated 16 bytes string
SECRET_KEY=ChangeMeChangeMe

View File

@@ -37,7 +37,7 @@ make sure that you either:
If you chose to create a dedicated partition, simply mount it to
``/var/lib/docker``. You could also create a separate partition (*ext4* is a
sane default) ans mount it to ``/mailu`` for storing e-mail data.
sane default) and mount it to ``/mailu`` for storing e-mail data.
Docker supports *AUFS* over *ext4* and *btrfs* as stable storage drivers.
Other filesystems are supported such as *OverlayFS*. If you know what you are

View File

@@ -29,7 +29,7 @@ for the ``VERSION_TAG`` branch, use:
Then open the ``.env`` file to setup the mail server. Modify the ``ROOT`` setting
to match your setup directory if different from ``/mailu``.
Mdify the ``VERSION`` configuration in the ``.env`` file to reflect the version you picked.
Modify the ``VERSION`` configuration in the ``.env`` file to reflect the version you picked.
Set the common configuration values
-----------------------------------
@@ -63,11 +63,11 @@ default configuration.
A Webmail is a Web interface exposing an email client. Mailu webmails are
bound to the internal IMAP and SMTP server for users to access their mailbox through
the Web. By exposing a complex application such as a Webmail, you should be aware of
the security implications such an increase of attack surface. The ``WEBMAIL``
the security implications caused by such an increase of attack surface. The ``WEBMAIL``
configuration option must be one of the following:
- ``none`` is the default value, no Webmail service will be exposed;
- ``roundcube`` will run the popular Roundcube Webmail ;
- ``roundcube`` will run the popular Roundcube Webmail;
- ``rainloop`` will run the popular Rainloop Webmail.
The administration interface is not exposed on the public address by default,
@@ -90,7 +90,7 @@ setting. The configuration option must be one of the following:
- ``none`` disables antivirus checks;
- ``clamav`` is the default values, the popular ClamAV antivirus is enabled.
Make sure that you have at least 1GB or memory for ClamAV to load its signature
Make sure that you have at least 1GB of memory for ClamAV to load its signature
database.
Finish setting up TLS

View File

@@ -2,19 +2,22 @@
# -*- coding: utf-8 -*-
#
import os
extensions = ['sphinx.ext.imgmath', 'sphinx.ext.viewcode']
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
project = 'Mailu'
copyright = '2017, Mailu authors'
copyright = '2018, Mailu authors'
author = 'Mailu authors'
version = release = 'latest'
version = release = os.environ.get('VERSION', 'master')
language = None
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'Dockerfile', 'docker-compose.yml']
pygments_style = 'sphinx'
todo_include_todos = False
html_theme = 'sphinx_rtd_theme'
html_title = 'Mailu, Docker based mail server'
html_static_path = []
htmlhelp_basename = 'Mailudoc'
@@ -22,7 +25,7 @@ htmlhelp_basename = 'Mailudoc'
# to template names.
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'relations.html',
'searchbox.html',
]
}
@@ -32,27 +35,11 @@ html_context = {
'display_github': True,
'github_user': 'mailu',
'github_repo': 'mailu',
'github_version': 'master',
'github_version': version,
'stable_version': '1.5',
'versions': [
('1.5', '/1.5/'),
('master', '/master/')
],
'conf_py_path': '/docs/'
}
# Upload function when the script is called directly
if __name__ == "__main__":
import os, sys, paramiko
build_dir, hostname, username, password, dest_dir = sys.argv[1:]
transport = paramiko.Transport((hostname, 22))
transport.connect(username=username, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)
os.chdir(build_dir)
for dirpath, dirnames, filenames in os.walk("."):
remote_path = os.path.join(dest_dir, dirpath)
try:
sftp.mkdir(remote_path)
except:
pass
for filename in filenames:
sftp.put(
os.path.join(dirpath, filename),
os.path.join(remote_path, filename)
)

View File

@@ -50,7 +50,7 @@ like ``localpart+custom@domain.tld`` to deliver mail to ``localpart@domain.tld``
This is useful to provide external parties with different email addresses and
later classify incoming mail based on the custom part.
The ``DMAR_RUA`` and ``DMARC_RUF`` are DMARC protocol specific values. They hold
The ``DMARC_RUA`` and ``DMARC_RUF`` are DMARC protocol specific values. They hold
the localpart for DMARC rua and ruf email addresses.
Web settings

View File

@@ -22,7 +22,7 @@ Set that name in the ``HOSTNAME`` configuration entry. Then depending on your do
Also, ``a.b.c.d`` should be set in your ``BIND_INTERFACE`` configuration unless your server is in a DMZ and you are using port forwards to expose the services.
Finally, make sure that you have a proper TLS certificate for you mail server hostname and install it according to the instructions in the [[Setup Guide]].
Finally, make sure that you have a proper TLS certificate for your mail server hostname and install it according to the instructions in the [[Setup Guide]].
MX entries
----------

View File

@@ -25,7 +25,7 @@ Main features include:
- **Standard email server**, IMAP and IMAP+, SMTP and Submission
- **Advanced email features**, aliases, domain aliases, custom routing
- **Web access**, multiple Webmails and adminitration interface
- **Web access**, multiple Webmails and administration interface
- **User features**, aliases, auto-reply, auto-forward, fetched accounts
- **Admin features**, global admins, announcements, per-domain delegation, quotas
- **Security**, enforced TLS, Letsencrypt!, outgoing DKIM, anti-virus scanner

View File

@@ -23,4 +23,4 @@ Using the resource configurations is simple:
1. ``kubectl apply -f kubernetes-nginx-ingress-controller.yaml`` to configure an ingress controller with the proper settings. (If you have one set up already you may need to port the configuration to your own ingress).
2. ``kubectl apply -f kubernetes-mailu.yaml`` to create the resources required to run Mailu.
Based on the configuration, your Mailu instance should be available at ``mail.<hostname>.tld/admin`` (note that visiting just ``mail.<hostname>.tld`` will likely result in a 404.
Based on the configuration, your Mailu instance should be available at ``mail.<hostname>.tld/admin`` (note that visiting just ``mail.<hostname>.tld`` will likely result in a 404 error).

View File

@@ -20,25 +20,25 @@ simply pull the latest images and recreate the containers :
Monitoring the mail server
--------------------------
Logs are managed by Docker directly. You can easily read your logs using :
Logs are managed by Docker directly. You can easily read your logs using:
.. code-block:: bash
docker-compose logs
Docker is able to forward logs to multiple log engines. Read the following documentation or details: https://docs.docker.com/engine/admin/logging/overview/.
Docker is able to forward logs to multiple log engines. Read the following documentation for details: https://docs.docker.com/engine/admin/logging/overview/.
Migrating an instance
---------------------
The SMTP protocol has an embedded retry mechanism and multiple MX that can serve a single domain, so that most migration process or maintenance process do not require any specific care.
The SMTP protocol has an embedded retry mechanism and multiple MX that can serve a single domain, so that most migration processes or maintenance processes do not require any specific care.
Mailu relys heavily on files for storing everything, which helps the migration process, that can be performed based on file synchronization.
Mailu relies heavily on files for storing everything, which helps the migration process, that can be performed based on file synchronization.
The suggested migration process consists in setting up a new backup server that drops incoming emails (Mailu not started), synchronizing both servers, stopping the main server and launching the backup server. Then, the backup server is switched as a main MX and the old server is deleted.
The suggested migration process consists of setting up a new backup server that drops incoming emails (Mailu not started), synchronizing both servers, stopping the main server and launching the backup server. Then, the backup server is switched as a main MX and the old server is deleted.
1. Prepare your new server, copy your ``docker-compose.yml``, ``.env`` and basic configuration files to the server, so that it is ready to start configuration Mailu, *do not start Mailu*
2. Setup your DNS so that the backup server is an additional, deprioritized MX for the domain; this can be complex if you serve many domains, in which case you can simply accept that some remote MX will retry for a couple minutes, skip this step
2. Setup your DNS so that the backup server is an additional, deprioritized MX for the domain; this can be complex if you serve many domains, in which case you can simply accept that some remote MX will retry for a couple of minutes, skip this step
3. While your DNS TTL expires and your modification propagates, start *rsyncing* your Mailu directory (``data``, ``dkim``, ``mail``, etc.) to the new server, repeat until there are only a couple files synchronized
4. Stop Mailu on the old server and run a final ``rsync`` while no process is writing to the files
5. Start Mailu on the new server, and production should be back to normal

5
docs/nginx.conf Normal file
View File

@@ -0,0 +1,5 @@
server {
listen 80;
listen [::]:80;
root /build;
}

View File

@@ -2,5 +2,3 @@ recommonmark
Sphinx
sphinx-autobuild
sphinx-rtd-theme
sphinxcontrib-versioning
paramiko

View File

@@ -141,4 +141,4 @@ Disable completely Mailu reverse proxy
You can simply disable Mailu reverse proxy by removing the ``front`` section from the ``docker-compose.yml`` and use your own means to reverse proxy requests to the proper containers.
Be careful with this method as resolving container addresses outside the Docker Compose structure is a tricky task: there is no guaranty that addresses will remain after a restart and you are almost certain that addresses will change after every upgrade (and whenever containers are recreated).
Be careful with this method as resolving container addresses outside the Docker Compose structure is a tricky task: there is no guarantee that addresses will remain after a restart and you are almost certain that addresses will change after every upgrade (and whenever containers are recreated).

View File

@@ -33,9 +33,8 @@ Pick a Mailu version
Mailu is shipped in multiple versions.
- ``stable`` is the default version and features a stable server, it gets bugfixes
and patches but features are included every month or so after a couple weeks of
testing. This is the default setting and should match most requirements.
- ``1.5`` features the most recent stable version for Mailu. This is the
recommended build for new setups, old setups should migrate when possible.
- ``1.0``, ``1.1``, and other version branches feature old versions of Mailu
they will not receive any more patches (except for the stable one) and you should

View File

@@ -1,4 +1,4 @@
FROM alpine
FROM alpine:3.13
RUN apk add --no-cache clamav rsyslog wget clamav-libunrar

View File

@@ -1,4 +1,4 @@
FROM python:alpine
FROM python:alpine3.13
RUN apk add --no-cache fetchmail ca-certificates

View File

@@ -1,10 +1,13 @@
FROM alpine:edge
FROM alpine:3.13
RUN apk add --no-cache python py-jinja2 rspamd rspamd-controller rspamd-proxy ca-certificates
RUN apk add --no-cache python3 py3-jinja2 rspamd rspamd-controller rspamd-proxy ca-certificates
RUN mkdir /run/rspamd
COPY conf/ /conf
COPY start.py /start.py
# Temporary fix to remove references to rspamd-fuzzy for now
RUN sed -i '/fuzzy/,$d' /etc/rspamd/rspamd.conf
CMD /start.py

View File

@@ -1,3 +1,4 @@
type = "controller";
bind_socket = "*:11334";
password = "mailu";
secure_ip = "{{ FRONT_ADDRESS }}";

View File

@@ -1 +1,2 @@
type = "normal";
enabled = false;

View File

@@ -1,3 +1,4 @@
type = "proxy";
bind_socket = "*:11332";
upstream "local" {
default = yes;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import jinja2
import os

54
tests/build.yml Normal file
View File

@@ -0,0 +1,54 @@
version: '3'
services:
front:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}nginx:${MAILU_VERSION:-local}
build: ../core/nginx
imap:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}dovecot:${MAILU_VERSION:-local}
build: ../core/dovecot
smtp:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}postfix:${MAILU_VERSION:-local}
build: ../core/postfix
antispam:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}rspamd:${MAILU_VERSION:-local}
build: ../services/rspamd
antivirus:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}clamav:${MAILU_VERSION:-local}
build: ../optional/clamav
webdav:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}radicale:${MAILU_VERSION:-local}
build: ../optional/radicale
admin:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}admin:${MAILU_VERSION:-local}
build: ../core/admin
roundcube:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}roundcube:${MAILU_VERSION:-local}
build: ../webmails/roundcube
rainloop:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}rainloop:${MAILU_VERSION:-local}
build: ../webmails/rainloop
fetchmail:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}fetchmail:${MAILU_VERSION:-local}
build: ../services/fetchmail
none:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}none:${MAILU_VERSION:-local}
build: ../core/none
docs:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}docs:${MAILU_VERSION:-local}
build:
context: ../docs
args:
version: ${MAILU_VERSION:-local}

4
tests/deploy.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
docker login -u $DOCKER_UN -p $DOCKER_PW
docker-compose -f tests/build.yml push

View File

@@ -4,7 +4,7 @@ RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng12-dev \
libpng-dev \
&& docker-php-ext-install pdo_mysql mcrypt
ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.3.3/roundcubemail-1.3.3-complete.tar.gz
@@ -19,7 +19,8 @@ RUN rm -rf /var/www/html/ \
&& mv roundcubemail-* html \
&& cd html \
&& rm -rf CHANGELOG INSTALL LICENSE README.md UPGRADING composer.json-dist installer \
&& chown -R www-data: logs
&& chown -R www-data: logs \
&& sed -i 's/mod_php5.c/mod_php7.c/g' /var/www/html/.htaccess
COPY config.inc.php /var/www/html/config/

View File

@@ -4,6 +4,7 @@ $config = array();
// Generals
$config['db_dsnw'] = 'sqlite:////data/roundcube.db';
$config['temp_dir'] = '/tmp/';
$config['des_key'] = getenv('SECRET_KEY');
$config['identities_level'] = 3;
$config['reply_all_mode'] = 1;