You've already forked Mailu
mirror of
https://github.com/Mailu/Mailu.git
synced 2025-06-15 00:05:11 +02:00
Merge branch 'master' into feat-abstract-db
This commit is contained in:
10
.mergify.yml
Normal file
10
.mergify.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
rules:
|
||||||
|
default: null
|
||||||
|
branches:
|
||||||
|
master:
|
||||||
|
protection:
|
||||||
|
required_status_checks:
|
||||||
|
contexts:
|
||||||
|
- continuous-integration/travis-ci
|
||||||
|
required_pull_request_reviews:
|
||||||
|
required_approving_review_count: 2
|
13
.travis.yml
13
.travis.yml
@ -8,4 +8,15 @@ env:
|
|||||||
- VERSION=$TRAVIS_BRANCH
|
- VERSION=$TRAVIS_BRANCH
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- docker-compose -f tests/build.yml -p Mailu build
|
# Default to mailu for DOCKER_ORG
|
||||||
|
- if [ -z "$DOCKER_ORG" ]; then export DOCKER_ORG="mailu"; fi
|
||||||
|
- docker-compose -f tests/build.yml build
|
||||||
|
- tests/compose/test-script.sh
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: script
|
||||||
|
script: bash tests/deploy.sh
|
||||||
|
on:
|
||||||
|
all_branches: true
|
||||||
|
condition: -n $DOCKER_UN
|
||||||
|
|
||||||
|
@ -17,5 +17,6 @@ COPY start.sh /start.sh
|
|||||||
RUN pybabel compile -d mailu/translations
|
RUN pybabel compile -d mailu/translations
|
||||||
|
|
||||||
EXPOSE 80/tcp
|
EXPOSE 80/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD ["/start.sh"]
|
CMD ["/start.sh"]
|
||||||
|
@ -3,11 +3,13 @@ FROM alpine:3.8
|
|||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
dovecot dovecot-pigeonhole-plugin dovecot-fts-lucene rspamd-client \
|
dovecot dovecot-pigeonhole-plugin dovecot-fts-lucene rspamd-client \
|
||||||
python3 py3-pip \
|
python3 py3-pip \
|
||||||
&& pip3 install jinja2 podop
|
&& pip3 install --upgrade pip \
|
||||||
|
&& pip3 install jinja2 podop tenacity
|
||||||
|
|
||||||
COPY conf /conf
|
COPY conf /conf
|
||||||
COPY start.py /start.py
|
COPY start.py /start.py
|
||||||
|
|
||||||
EXPOSE 110/tcp 143/tcp 993/tcp 4190/tcp 2525/tcp
|
EXPOSE 110/tcp 143/tcp 993/tcp 4190/tcp 2525/tcp
|
||||||
|
VOLUME ["/data", "/mail"]
|
||||||
|
|
||||||
CMD /start.py
|
CMD /start.py
|
||||||
|
@ -5,7 +5,9 @@ import os
|
|||||||
import socket
|
import socket
|
||||||
import glob
|
import glob
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
import tenacity
|
||||||
|
|
||||||
|
from tenacity import retry
|
||||||
from podop import run_server
|
from podop import run_server
|
||||||
|
|
||||||
|
|
||||||
@ -19,8 +21,15 @@ def start_podop():
|
|||||||
|
|
||||||
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||||
|
|
||||||
|
@retry(stop=tenacity.stop_after_attempt(100), wait=tenacity.wait_random(min=2, max=5))
|
||||||
|
def resolve():
|
||||||
|
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
||||||
|
os.environ["REDIS_ADDRESS"] = socket.gethostbyname(os.environ.get("REDIS_ADDRESS", "redis"))
|
||||||
|
if os.environ["WEBMAIL"] != "none":
|
||||||
|
os.environ["WEBMAIL_ADDRESS"] = socket.gethostbyname(os.environ.get("WEBMAIL_ADDRESS", "webmail"))
|
||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
resolve()
|
||||||
|
|
||||||
for dovecot_file in glob.glob("/conf/*.conf"):
|
for dovecot_file in glob.glob("/conf/*.conf"):
|
||||||
convert(dovecot_file, os.path.join("/etc/dovecot", os.path.basename(dovecot_file)))
|
convert(dovecot_file, os.path.join("/etc/dovecot", os.path.basename(dovecot_file)))
|
||||||
|
@ -6,5 +6,6 @@ COPY conf /conf
|
|||||||
COPY *.py /
|
COPY *.py /
|
||||||
|
|
||||||
EXPOSE 80/tcp 443/tcp 110/tcp 143/tcp 465/tcp 587/tcp 993/tcp 995/tcp 25/tcp 10025/tcp 10143/tcp
|
EXPOSE 80/tcp 443/tcp 110/tcp 143/tcp 465/tcp 587/tcp 993/tcp 995/tcp 25/tcp 10025/tcp 10143/tcp
|
||||||
|
VOLUME ["/certs"]
|
||||||
|
|
||||||
CMD /start.py
|
CMD /start.py
|
||||||
|
@ -2,11 +2,13 @@ FROM alpine:3.8
|
|||||||
|
|
||||||
RUN apk add --no-cache postfix postfix-pcre rsyslog \
|
RUN apk add --no-cache postfix postfix-pcre rsyslog \
|
||||||
python3 py3-pip \
|
python3 py3-pip \
|
||||||
&& pip3 install jinja2 podop
|
&& pip3 install --upgrade pip
|
||||||
|
&& pip3 install jinja2 podop tenacity
|
||||||
|
|
||||||
COPY conf /conf
|
COPY conf /conf
|
||||||
COPY start.py /start.py
|
COPY start.py /start.py
|
||||||
|
|
||||||
EXPOSE 25/tcp 10025/tcp
|
EXPOSE 25/tcp 10025/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD /start.py
|
CMD /start.py
|
||||||
|
@ -8,6 +8,7 @@ smtp inet n - n - - smtpd
|
|||||||
10025 inet n - n - - smtpd
|
10025 inet n - n - - smtpd
|
||||||
-o smtpd_sasl_auth_enable=yes
|
-o smtpd_sasl_auth_enable=yes
|
||||||
-o smtpd_client_restrictions=reject_unlisted_sender,reject_authenticated_sender_login_mismatch,permit
|
-o smtpd_client_restrictions=reject_unlisted_sender,reject_authenticated_sender_login_mismatch,permit
|
||||||
|
-o smtpd_reject_unlisted_recipient={% if REJECT_UNLISTED_RECIPIENT %}{{ REJECT_UNLISTED_RECIPIENT }}{% else %}no{% endif %}
|
||||||
-o cleanup_service_name=outclean
|
-o cleanup_service_name=outclean
|
||||||
outclean unix n - n - 0 cleanup
|
outclean unix n - n - 0 cleanup
|
||||||
-o header_checks=pcre:/etc/postfix/outclean_header_filter.cf
|
-o header_checks=pcre:/etc/postfix/outclean_header_filter.cf
|
||||||
|
@ -5,8 +5,10 @@ import os
|
|||||||
import socket
|
import socket
|
||||||
import glob
|
import glob
|
||||||
import shutil
|
import shutil
|
||||||
|
import tenacity
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
|
from tenacity import retry
|
||||||
from podop import run_server
|
from podop import run_server
|
||||||
|
|
||||||
|
|
||||||
@ -22,8 +24,12 @@ def start_podop():
|
|||||||
|
|
||||||
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||||
|
|
||||||
|
@retry(stop=tenacity.stop_after_attempt(100), wait=tenacity.wait_random(min=2, max=5))
|
||||||
|
def resolve():
|
||||||
|
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
resolve()
|
||||||
os.environ["HOST_ANTISPAM"] = os.environ.get("HOST_ANTISPAM", "antispam:11332")
|
os.environ["HOST_ANTISPAM"] = os.environ.get("HOST_ANTISPAM", "antispam:11332")
|
||||||
os.environ["HOST_LMTP"] = os.environ.get("HOST_LMTP", "imap:2525")
|
os.environ["HOST_LMTP"] = os.environ.get("HOST_LMTP", "imap:2525")
|
||||||
|
|
||||||
|
14
docs/Dockerfile
Normal file
14
docs/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3-alpine
|
||||||
|
|
||||||
|
COPY requirements.txt /requirements.txt
|
||||||
|
|
||||||
|
RUN pip install -r /requirements.txt \
|
||||||
|
&& apk add --no-cache nginx \
|
||||||
|
&& mkdir /run/nginx
|
||||||
|
|
||||||
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY . /docs
|
||||||
|
|
||||||
|
RUN sphinx-build /docs /build
|
||||||
|
|
||||||
|
CMD nginx -g "daemon off;"
|
@ -132,3 +132,6 @@ REAL_IP_HEADER=
|
|||||||
|
|
||||||
# IPs for nginx set_real_ip_from (CIDR list separated by commas)
|
# IPs for nginx set_real_ip_from (CIDR list separated by commas)
|
||||||
REAL_IP_FROM=
|
REAL_IP_FROM=
|
||||||
|
|
||||||
|
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
|
||||||
|
REJECT_UNLISTED_RECIPIENT=
|
||||||
|
25
docs/conf.py
25
docs/conf.py
@ -7,7 +7,7 @@ templates_path = ['_templates']
|
|||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
project = 'Mailu'
|
project = 'Mailu'
|
||||||
copyright = '2017, Mailu authors'
|
copyright = '2018, Mailu authors'
|
||||||
author = 'Mailu authors'
|
author = 'Mailu authors'
|
||||||
version = release = 'latest'
|
version = release = 'latest'
|
||||||
language = None
|
language = None
|
||||||
@ -23,7 +23,7 @@ htmlhelp_basename = 'Mailudoc'
|
|||||||
# to template names.
|
# to template names.
|
||||||
html_sidebars = {
|
html_sidebars = {
|
||||||
'**': [
|
'**': [
|
||||||
'relations.html', # needs 'show_related': True theme option to display
|
'relations.html',
|
||||||
'searchbox.html',
|
'searchbox.html',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -36,24 +36,3 @@ html_context = {
|
|||||||
'github_version': 'master',
|
'github_version': 'master',
|
||||||
'conf_py_path': '/docs/'
|
'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)
|
|
||||||
)
|
|
||||||
|
@ -89,3 +89,20 @@ Any change to the files will automatically restart the Web server and reload the
|
|||||||
|
|
||||||
When using the development environment, a debugging toolbar is displayed on the right side
|
When using the development environment, a debugging toolbar is displayed on the right side
|
||||||
of the screen, that you can open to access query details, internal variables, etc.
|
of the screen, that you can open to access query details, internal variables, etc.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Documentation is maintained in the ``docs`` directory and are maintained as `reStructuredText`_ files. It is possible to run a local documentation server for reviewing purposes, using Docker:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd <Mailu repo>
|
||||||
|
docker build -t docs docs
|
||||||
|
docker run -p 127.0.0.1:8080:80 docs
|
||||||
|
|
||||||
|
You can now read the local documentation by navigating to http://localhost:8080.
|
||||||
|
|
||||||
|
.. note:: After modifying the documentation, the image needs to be rebuild and the container restarted for the changes to become visible.
|
||||||
|
|
||||||
|
.. _`reStructuredText`: http://docutils.sourceforge.net/rst.html
|
||||||
|
5
docs/nginx.conf
Normal file
5
docs/nginx.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
root /build;
|
||||||
|
}
|
@ -2,5 +2,3 @@ recommonmark
|
|||||||
Sphinx
|
Sphinx
|
||||||
sphinx-autobuild
|
sphinx-autobuild
|
||||||
sphinx-rtd-theme
|
sphinx-rtd-theme
|
||||||
sphinxcontrib-versioning
|
|
||||||
paramiko
|
|
||||||
|
@ -6,5 +6,6 @@ COPY conf /etc/clamav
|
|||||||
COPY start.sh /start.sh
|
COPY start.sh /start.sh
|
||||||
|
|
||||||
EXPOSE 3310/tcp
|
EXPOSE 3310/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD ["/start.sh"]
|
CMD ["/start.sh"]
|
||||||
|
@ -6,5 +6,6 @@ RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/re
|
|||||||
COPY radicale.conf /radicale.conf
|
COPY radicale.conf /radicale.conf
|
||||||
|
|
||||||
EXPOSE 5232/tcp
|
EXPOSE 5232/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD radicale -f -S -C /radicale.conf
|
CMD radicale -f -S -C /radicale.conf
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
FROM alpine:edge
|
FROM alpine:edge
|
||||||
|
|
||||||
RUN apk add --no-cache python py-jinja2 rspamd rspamd-controller rspamd-proxy ca-certificates
|
RUN apk add --no-cache python py-jinja2 rspamd rspamd-controller rspamd-proxy ca-certificates py-pip \
|
||||||
|
&& pip install --upgrade pip \
|
||||||
|
&& pip install tenacity
|
||||||
|
|
||||||
RUN mkdir /run/rspamd
|
RUN mkdir /run/rspamd
|
||||||
|
|
||||||
@ -12,4 +14,6 @@ RUN sed -i '/fuzzy/,$d' /etc/rspamd/rspamd.conf
|
|||||||
|
|
||||||
EXPOSE 11332/tcp 11334/tcp
|
EXPOSE 11332/tcp 11334/tcp
|
||||||
|
|
||||||
|
VOLUME ["/var/lib/rspamd"]
|
||||||
|
|
||||||
CMD /start.py
|
CMD /start.py
|
||||||
|
4
services/rspamd/conf/arc.conf
Normal file
4
services/rspamd/conf/arc.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
try_fallback = true;
|
||||||
|
path = "/dkim/$domain.$selector.key";
|
||||||
|
selector = "dkim"
|
||||||
|
use_esld = false;
|
@ -4,11 +4,17 @@ import jinja2
|
|||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import glob
|
import glob
|
||||||
|
import tenacity
|
||||||
|
from tenacity import retry
|
||||||
|
|
||||||
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||||
|
|
||||||
|
@retry(stop=tenacity.stop_after_attempt(100), wait=tenacity.wait_random(min=2, max=5))
|
||||||
|
def resolve():
|
||||||
|
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
os.environ["FRONT_ADDRESS"] = socket.gethostbyname(os.environ.get("FRONT_ADDRESS", "front"))
|
resolve()
|
||||||
if "HOST_REDIS" not in os.environ: os.environ["HOST_REDIS"] = "redis"
|
if "HOST_REDIS" not in os.environ: os.environ["HOST_REDIS"] = "redis"
|
||||||
|
|
||||||
for rspamd_file in glob.glob("/conf/*"):
|
for rspamd_file in glob.glob("/conf/*"):
|
||||||
|
@ -3,45 +3,54 @@ version: '3'
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
front:
|
front:
|
||||||
image: mailu/nginx:$VERSION
|
image: $DOCKER_ORG/nginx:$VERSION
|
||||||
build: ../core/nginx
|
build: ../core/nginx
|
||||||
|
|
||||||
imap:
|
imap:
|
||||||
image: mailu/dovecot:$VERSION
|
image: $DOCKER_ORG/dovecot:$VERSION
|
||||||
build: ../core/dovecot
|
build: ../core/dovecot
|
||||||
|
|
||||||
smtp:
|
smtp:
|
||||||
image: mailu/postfix:$VERSION
|
image: $DOCKER_ORG/postfix:$VERSION
|
||||||
build: ../core/postfix
|
build: ../core/postfix
|
||||||
|
|
||||||
antispam:
|
antispam:
|
||||||
image: mailu/rspamd:$VERSION
|
image: $DOCKER_ORG/rspamd:$VERSION
|
||||||
build: ../services/rspamd
|
build: ../services/rspamd
|
||||||
|
|
||||||
antivirus:
|
antivirus:
|
||||||
image: mailu/clamav:$VERSION
|
image: $DOCKER_ORG/clamav:$VERSION
|
||||||
build: ../optional/clamav
|
build: ../optional/clamav
|
||||||
|
|
||||||
webdav:
|
webdav:
|
||||||
image: mailu/radicale:$VERSION
|
image: $DOCKER_ORG/radicale:$VERSION
|
||||||
build: ../optional/radicale
|
build: ../optional/radicale
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
image: mailu/admin:$VERSION
|
image: $DOCKER_ORG/admin:$VERSION
|
||||||
build: ../core/admin
|
build: ../core/admin
|
||||||
|
|
||||||
roundcube:
|
roundcube:
|
||||||
image: mailu/roundcube:$VERSION
|
image: $DOCKER_ORG/roundcube:$VERSION
|
||||||
build: ../webmails/roundcube
|
build: ../webmails/roundcube
|
||||||
|
|
||||||
rainloop:
|
rainloop:
|
||||||
image: mailu/rainloop:$VERSION
|
image: $DOCKER_ORG/rainloop:$VERSION
|
||||||
build: ../webmails/rainloop
|
build: ../webmails/rainloop
|
||||||
|
|
||||||
fetchmail:
|
fetchmail:
|
||||||
image: mailu/fetchmail:$VERSION
|
image: $DOCKER_ORG/fetchmail:$VERSION
|
||||||
build: ../services/fetchmail
|
build: ../services/fetchmail
|
||||||
|
|
||||||
none:
|
none:
|
||||||
image: mailu/none:$VERSION
|
image: $DOCKER_ORG/none:$VERSION
|
||||||
build: ../core/none
|
build: ../core/none
|
||||||
|
|
||||||
|
docs:
|
||||||
|
image: $DOCKER_ORG/docs:$VERSION
|
||||||
|
build: ../docs
|
||||||
|
|
||||||
|
setup:
|
||||||
|
image: $DOCKER_ORG/setup:$VERSION
|
||||||
|
build: ../setup
|
||||||
|
|
||||||
|
134
tests/compose/core.env
Normal file
134
tests/compose/core.env
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# Mailu main configuration file
|
||||||
|
#
|
||||||
|
# Most configuration variables can be modified through the Web interface,
|
||||||
|
# these few settings must however be configured before starting the mail
|
||||||
|
# server and require a restart upon change.
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# Common configuration variables
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Set this to the path where Mailu data and configuration is stored
|
||||||
|
ROOT=/mailu
|
||||||
|
|
||||||
|
# Mailu version to run (1.0, 1.1, etc. or master)
|
||||||
|
#VERSION=master
|
||||||
|
|
||||||
|
# Set to a randomly generated 16 bytes string
|
||||||
|
SECRET_KEY=ChangeMeChangeMe
|
||||||
|
|
||||||
|
# Address where listening ports should bind
|
||||||
|
BIND_ADDRESS4=127.0.0.1
|
||||||
|
#BIND_ADDRESS6=::1
|
||||||
|
|
||||||
|
# Main mail domain
|
||||||
|
DOMAIN=mailu.io
|
||||||
|
|
||||||
|
# Hostnames for this server, separated with comas
|
||||||
|
HOSTNAMES=mail.mailu.io,alternative.mailu.io,yetanother.mailu.io
|
||||||
|
|
||||||
|
# Postmaster local part (will append the main mail domain)
|
||||||
|
POSTMASTER=admin
|
||||||
|
|
||||||
|
# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
|
||||||
|
TLS_FLAVOR=cert
|
||||||
|
|
||||||
|
# Authentication rate limit (per source IP address)
|
||||||
|
AUTH_RATELIMIT=10/minute;1000/hour
|
||||||
|
|
||||||
|
# Opt-out of statistics, replace with "True" to opt out
|
||||||
|
DISABLE_STATISTICS=False
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# Optional features
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Expose the admin interface (value: true, false)
|
||||||
|
ADMIN=false
|
||||||
|
|
||||||
|
# Choose which webmail to run if any (values: roundcube, rainloop, none)
|
||||||
|
WEBMAIL=none
|
||||||
|
|
||||||
|
# Dav server implementation (value: radicale, none)
|
||||||
|
WEBDAV=none
|
||||||
|
|
||||||
|
# Antivirus solution (value: clamav, none)
|
||||||
|
ANTIVIRUS=none
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# Mail settings
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Message size limit in bytes
|
||||||
|
# Default: accept messages up to 50MB
|
||||||
|
MESSAGE_SIZE_LIMIT=50000000
|
||||||
|
|
||||||
|
# Networks granted relay permissions, make sure that you include your Docker
|
||||||
|
# internal network (default to 172.17.0.0/16)
|
||||||
|
RELAYNETS=172.16.0.0/12
|
||||||
|
|
||||||
|
# Will relay all outgoing mails if configured
|
||||||
|
RELAYHOST=
|
||||||
|
|
||||||
|
# Fetchmail delay
|
||||||
|
FETCHMAIL_DELAY=600
|
||||||
|
|
||||||
|
# Recipient delimiter, character used to delimiter localpart from custom address part
|
||||||
|
# e.g. localpart+custom@domain;tld
|
||||||
|
RECIPIENT_DELIMITER=+
|
||||||
|
|
||||||
|
# DMARC rua and ruf email
|
||||||
|
DMARC_RUA=admin
|
||||||
|
DMARC_RUF=admin
|
||||||
|
|
||||||
|
# Welcome email, enable and set a topic and body if you wish to send welcome
|
||||||
|
# emails to all users.
|
||||||
|
WELCOME=false
|
||||||
|
WELCOME_SUBJECT=Welcome to your new email account
|
||||||
|
WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
|
||||||
|
|
||||||
|
# Maildir Compression
|
||||||
|
# choose compression-method, default: none (value: bz2, gz)
|
||||||
|
COMPRESSION=
|
||||||
|
# change compression-level, default: 6 (value: 1-9)
|
||||||
|
COMPRESSION_LEVEL=
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# Web settings
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Path to the admin interface if enabled
|
||||||
|
WEB_ADMIN=/admin
|
||||||
|
|
||||||
|
# Path to the webmail if enabled
|
||||||
|
WEB_WEBMAIL=/webmail
|
||||||
|
|
||||||
|
# Website name
|
||||||
|
SITENAME=Mailu
|
||||||
|
|
||||||
|
# Linked Website URL
|
||||||
|
WEBSITE=https://mailu.io
|
||||||
|
|
||||||
|
# Registration reCaptcha settings (warning, this has some privacy impact)
|
||||||
|
# RECAPTCHA_PUBLIC_KEY=
|
||||||
|
# RECAPTCHA_PRIVATE_KEY=
|
||||||
|
|
||||||
|
# Domain registration, uncomment to enable
|
||||||
|
# DOMAIN_REGISTRATION=true
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# Advanced settings
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Docker-compose project name, this will prepended to containers names.
|
||||||
|
#COMPOSE_PROJECT_NAME=mailu
|
||||||
|
|
||||||
|
# Default password scheme used for newly created accounts and changed passwords
|
||||||
|
# (value: SHA512-CRYPT, SHA256-CRYPT, MD5-CRYPT, CRYPT)
|
||||||
|
PASSWORD_SCHEME=SHA512-CRYPT
|
||||||
|
|
||||||
|
# Header to take the real ip from
|
||||||
|
REAL_IP_HEADER=
|
||||||
|
|
||||||
|
# IPs for nginx set_real_ip_from (CIDR list separated by commas)
|
||||||
|
REAL_IP_FROM=
|
99
tests/compose/run.yml
Normal file
99
tests/compose/run.yml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
front:
|
||||||
|
image: $DOCKER_ORG/nginx:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
ports:
|
||||||
|
- "$BIND_ADDRESS4:80:80"
|
||||||
|
- "$BIND_ADDRESS4:443:443"
|
||||||
|
- "$BIND_ADDRESS4:110:110"
|
||||||
|
- "$BIND_ADDRESS4:143:143"
|
||||||
|
- "$BIND_ADDRESS4:993:993"
|
||||||
|
- "$BIND_ADDRESS4:995:995"
|
||||||
|
- "$BIND_ADDRESS4:25:25"
|
||||||
|
- "$BIND_ADDRESS4:465:465"
|
||||||
|
- "$BIND_ADDRESS4:587:587"
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/certs:/certs"
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
restart: 'no'
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/redis:/data"
|
||||||
|
|
||||||
|
imap:
|
||||||
|
image: $DOCKER_ORG/dovecot:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/data:/data"
|
||||||
|
- "$ROOT/mail:/mail"
|
||||||
|
- "$ROOT/overrides:/overrides"
|
||||||
|
depends_on:
|
||||||
|
- front
|
||||||
|
|
||||||
|
smtp:
|
||||||
|
image: $DOCKER_ORG/postfix:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/data:/data"
|
||||||
|
- "$ROOT/overrides:/overrides"
|
||||||
|
depends_on:
|
||||||
|
- front
|
||||||
|
|
||||||
|
antispam:
|
||||||
|
image: $DOCKER_ORG/rspamd:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/filter:/var/lib/rspamd"
|
||||||
|
- "$ROOT/dkim:/dkim"
|
||||||
|
- "$ROOT/overrides/rspamd:/etc/rspamd/override.d"
|
||||||
|
depends_on:
|
||||||
|
- front
|
||||||
|
|
||||||
|
antivirus:
|
||||||
|
image: $DOCKER_ORG/$ANTIVIRUS:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/filter:/data"
|
||||||
|
|
||||||
|
webdav:
|
||||||
|
image: $DOCKER_ORG/$WEBDAV:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/dav:/data"
|
||||||
|
|
||||||
|
admin:
|
||||||
|
image: $DOCKER_ORG/admin:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/data:/data"
|
||||||
|
- "$ROOT/dkim:/dkim"
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
|
||||||
|
webmail:
|
||||||
|
image: "$DOCKER_ORG/$WEBMAIL:$VERSION"
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/webmail:/data"
|
||||||
|
depends_on:
|
||||||
|
- imap
|
||||||
|
|
||||||
|
fetchmail:
|
||||||
|
image: $DOCKER_ORG/fetchmail:$VERSION
|
||||||
|
restart: 'no'
|
||||||
|
env_file: $PWD/.env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/data:/data"
|
57
tests/compose/test-script.sh
Executable file
57
tests/compose/test-script.sh
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
containers=(
|
||||||
|
webmail
|
||||||
|
imap
|
||||||
|
smtp
|
||||||
|
antispam
|
||||||
|
admin
|
||||||
|
redis
|
||||||
|
antivirus
|
||||||
|
webdav
|
||||||
|
# fetchmail
|
||||||
|
front
|
||||||
|
)
|
||||||
|
|
||||||
|
# Time to sleep in minutes after starting the containers
|
||||||
|
WAIT=1
|
||||||
|
|
||||||
|
containers_check() {
|
||||||
|
status=0
|
||||||
|
for container in "${containers[@]}"; do
|
||||||
|
name="${DOCKER_ORG}_${container}_1"
|
||||||
|
echo "Checking $name"
|
||||||
|
docker inspect "$name" | grep '"Status": "running"' || status=1
|
||||||
|
done
|
||||||
|
docker ps -a
|
||||||
|
return $status
|
||||||
|
}
|
||||||
|
|
||||||
|
container_logs() {
|
||||||
|
for container in "${containers[@]}"; do
|
||||||
|
name="${DOCKER_ORG}_${container}_1"
|
||||||
|
echo "Showing logs for $name"
|
||||||
|
docker container logs "$name"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
clean() {
|
||||||
|
docker-compose -f tests/compose/run.yml -p $DOCKER_ORG down || exit 1
|
||||||
|
rm -fv .env
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup before callig exit
|
||||||
|
die() {
|
||||||
|
clean
|
||||||
|
exit $1
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in tests/compose/*.env ; do
|
||||||
|
cp $file .env
|
||||||
|
docker-compose -f tests/compose/run.yml -p $DOCKER_ORG up -d
|
||||||
|
echo -e "\nSleeping for ${WAIT} minutes" # Clean terminal distortion from docker-compose in travis
|
||||||
|
travis_wait sleep ${WAIT}m || sleep ${WAIT}m #Fallback sleep for local run
|
||||||
|
container_logs
|
||||||
|
containers_check || die 1
|
||||||
|
clean
|
||||||
|
done
|
||||||
|
|
4
tests/deploy.sh
Executable file
4
tests/deploy.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
docker login -u $DOCKER_UN -p $DOCKER_PW
|
||||||
|
docker-compose -f tests/build.yml push
|
@ -24,4 +24,7 @@ COPY default.ini /default.ini
|
|||||||
|
|
||||||
COPY start.py /start.py
|
COPY start.py /start.py
|
||||||
|
|
||||||
|
EXPOSE 80/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD /start.py
|
CMD /start.py
|
||||||
|
@ -18,4 +18,7 @@ os.makedirs(base + "configs", exist_ok=True)
|
|||||||
convert("/default.ini", "/data/_data_/_default_/domains/default.ini")
|
convert("/default.ini", "/data/_data_/_default_/domains/default.ini")
|
||||||
convert("/config.ini", "/data/_data_/_default_/configs/config.ini")
|
convert("/config.ini", "/data/_data_/_default_/configs/config.ini")
|
||||||
|
|
||||||
|
os.system("chown -R www-data:www-data /data")
|
||||||
|
|
||||||
os.execv("/usr/local/bin/apache2-foreground", ["apache2-foreground"])
|
os.execv("/usr/local/bin/apache2-foreground", ["apache2-foreground"])
|
||||||
|
|
||||||
|
@ -25,4 +25,7 @@ COPY config.inc.php /var/www/html/config/
|
|||||||
|
|
||||||
COPY start.sh /start.sh
|
COPY start.sh /start.sh
|
||||||
|
|
||||||
|
EXPOSE 80/tcp
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
CMD ["/start.sh"]
|
CMD ["/start.sh"]
|
||||||
|
Reference in New Issue
Block a user