From 8c6e0c56fb02712f6890e88d3e8446fc29eb619e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Wed, 19 Dec 2018 15:02:00 +0200
Subject: [PATCH 01/33] Fix redis connection errors
---
setup/docker-compose.yml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/setup/docker-compose.yml b/setup/docker-compose.yml
index 7c31d2cd..6d14153a 100644
--- a/setup/docker-compose.yml
+++ b/setup/docker-compose.yml
@@ -5,17 +5,21 @@ version: '3.6'
services:
redis:
image: redis:alpine
+ networks:
+ - default
setup_master:
image: mailu/setup:master
networks:
- web
+ - default
env_file: .env
environment:
this_version: "master"
labels:
- traefik.enable=true
- traefik.port=80
+ - traefik.docker.network=web
- traefik.main.frontend.rule=Host:${ADDRESS};PathPrefix:/master/
depends_on:
- redis
@@ -24,12 +28,14 @@ services:
image: mailu/setup:${RELEASE}
networks:
- web
+ - default
env_file: .env
environment:
this_version: ${RELEASE}
labels:
- traefik.enable=true
- traefik.port=80
+ - traefik.docker.network=web
- traefik.root.frontend.redirect.regex=.*
- traefik.root.frontend.redirect.replacement=/${RELEASE}/
- traefik.root.frontend.rule=Host:${ADDRESS};PathPrefix:/
@@ -40,3 +46,5 @@ services:
networks:
web:
external: true
+ default:
+ external: false
From 1b64c80612109d4f97b5336e257df93c8e846cf6 Mon Sep 17 00:00:00 2001
From: Ionut Filip
Date: Wed, 19 Dec 2018 17:15:45 +0200
Subject: [PATCH 02/33] Managing different blueprint prefixes
---
setup/server.py | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/setup/server.py b/setup/server.py
index 456cb539..2b27cb3b 100644
--- a/setup/server.py
+++ b/setup/server.py
@@ -42,27 +42,37 @@ def build_app(path):
version = os.getenv("this_version")
- bp = flask.Blueprint(version, __name__)
- bp.jinja_loader = jinja2.ChoiceLoader([
+ prefix_bp = flask.Blueprint(version, __name__)
+ prefix_bp.jinja_loader = jinja2.ChoiceLoader([
jinja2.FileSystemLoader(os.path.join(path, "templates")),
jinja2.FileSystemLoader(os.path.join(path, "flavors"))
])
- @bp.context_processor
+ root_bp = flask.Blueprint("root", __name__)
+ root_bp.jinja_loader = jinja2.ChoiceLoader([
+ jinja2.FileSystemLoader(os.path.join(path, "templates")),
+ jinja2.FileSystemLoader(os.path.join(path, "flavors"))
+ ])
+
+ @prefix_bp.context_processor
+ @root_bp.context_processor
def bp_context(version=version):
return dict(version=version)
- @bp.route("/")
+ @prefix_bp.route("/")
+ @root_bp.route("/")
def wizard():
return flask.render_template('wizard.html')
- @bp.route("/submit_flavor", methods=["POST"])
+ @prefix_bp.route("/submit_flavor", methods=["POST"])
+ @root_bp.route("/submit_flavor", methods=["POST"])
def submit_flavor():
data = flask.request.form.copy()
steps = sorted(os.listdir(os.path.join(path, "templates", "steps", data["flavor"])))
return flask.render_template('wizard.html', flavor=data["flavor"], steps=steps)
- @bp.route("/submit", methods=["POST"])
+ @prefix_bp.route("/submit", methods=["POST"])
+ @root_bp.route("/submit", methods=["POST"])
def submit():
data = flask.request.form.copy()
data['uid'] = str(uuid.uuid4())
@@ -70,14 +80,16 @@ def build_app(path):
db.set(data['uid'], json.dumps(data))
return flask.redirect(flask.url_for('.setup', uid=data['uid']))
- @bp.route("/setup/", methods=["GET"])
+ @prefix_bp.route("/setup/", methods=["GET"])
+ @root_bp.route("/setup/", methods=["GET"])
def setup(uid):
data = json.loads(db.get(uid))
flavor = data.get("flavor", "compose")
rendered = render_flavor(flavor, "setup.html", data)
return flask.render_template("setup.html", contents=rendered)
- @bp.route("/file//", methods=["GET"])
+ @prefix_bp.route("/file//", methods=["GET"])
+ @root_bp.route("/file//", methods=["GET"])
def file(uid, filepath):
data = json.loads(db.get(uid))
flavor = data.get("flavor", "compose")
@@ -86,7 +98,8 @@ def build_app(path):
mimetype="application/text"
)
- app.register_blueprint(bp, url_prefix="/{}".format(version))
+ app.register_blueprint(prefix_bp, url_prefix="/{}".format(version))
+ app.register_blueprint(root_bp)
if __name__ == "__main__":
From fa5161b044cdc5b867b5b0b728a9901545754ae0 Mon Sep 17 00:00:00 2001
From: Daniel Huber
Date: Fri, 21 Dec 2018 18:00:01 +0100
Subject: [PATCH 03/33] Disable ServerSignature of apache2 servers in rainloop
and roundcube
---
webmails/rainloop/Dockerfile | 3 ++-
webmails/roundcube/Dockerfile | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/webmails/rainloop/Dockerfile b/webmails/rainloop/Dockerfile
index 92479489..224fe457 100644
--- a/webmails/rainloop/Dockerfile
+++ b/webmails/rainloop/Dockerfile
@@ -2,7 +2,8 @@ FROM php:7.2-apache
#Shared layer between rainloop and roundcube
RUN apt-get update && apt-get install -y \
python3 curl \
- && rm -rf /var/lib/apt/lists
+ && rm -rf /var/lib/apt/lists \
+ && echo "ServerSignature Off" >> /etc/apache2/apache2.conf
ENV RAINLOOP_URL https://github.com/RainLoop/rainloop-webmail/releases/download/v1.12.1/rainloop-community-1.12.1.zip
diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile
index 00b843b2..1c5d82c4 100644
--- a/webmails/roundcube/Dockerfile
+++ b/webmails/roundcube/Dockerfile
@@ -2,7 +2,8 @@ FROM php:7.2-apache
#Shared layer between rainloop and roundcube
RUN apt-get update && apt-get install -y \
python3 curl \
- && rm -rf /var/lib/apt/lists
+ && rm -rf /var/lib/apt/lists \
+ && echo "ServerSignature Off" >> /etc/apache2/apache2.conf
ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.3.8/roundcubemail-1.3.8-complete.tar.gz
From 598ad4fc7ad296eef65d038aa01db8f2ef09ba7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Sun, 30 Dec 2018 20:52:34 +0200
Subject: [PATCH 04/33] Prefix static path with version for Traefik
---
setup/server.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/setup/server.py b/setup/server.py
index 2b27cb3b..3c950b0a 100644
--- a/setup/server.py
+++ b/setup/server.py
@@ -10,7 +10,9 @@ import random
import ipaddress
-app = flask.Flask(__name__)
+version = os.getenv("this_version")
+static_url_path = "/" + version + "/static"
+app = flask.Flask(__name__,static_url_path=static_url_path)
flask_bootstrap.Bootstrap(app)
db = redis.StrictRedis(host='redis', port=6379, db=0)
@@ -40,8 +42,6 @@ def build_app(path):
def app_context():
return dict(versions=os.getenv("VERSIONS","master").split(','))
- version = os.getenv("this_version")
-
prefix_bp = flask.Blueprint(version, __name__)
prefix_bp.jinja_loader = jinja2.ChoiceLoader([
jinja2.FileSystemLoader(os.path.join(path, "templates")),
From 56f4d4c89456e13e8d9558dcb7b679dab7e02c5e Mon Sep 17 00:00:00 2001
From: TheLegend875
Date: Fri, 28 Dec 2018 21:03:57 +0100
Subject: [PATCH 05/33] fixed auto-forward
---
core/admin/mailu/models.py | 2 +-
core/admin/mailu/ui/forms.py | 12 +++++++++---
core/admin/mailu/ui/views/users.py | 8 +++++++-
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py
index a3fc15a4..30a2ed64 100644
--- a/core/admin/mailu/models.py
+++ b/core/admin/mailu/models.py
@@ -72,7 +72,7 @@ class CommaSeparatedList(db.TypeDecorator):
return ",".join(value)
def process_result_value(self, value, dialect):
- return filter(bool, value.split(",")) if value else []
+ return list(filter(bool, value.split(","))) if value else []
class JSONEncoded(db.TypeDecorator):
diff --git a/core/admin/mailu/ui/forms.py b/core/admin/mailu/ui/forms.py
index 40a56a82..ac4f0e19 100644
--- a/core/admin/mailu/ui/forms.py
+++ b/core/admin/mailu/ui/forms.py
@@ -32,6 +32,14 @@ class DestinationField(fields.SelectMultipleField):
if not self.validator.match(item):
raise validators.ValidationError(_('Invalid email address.'))
+class MultipleEmailAddressesVerify(object):
+ def __init__(self,message=_('Invalid email address.')):
+ self.message = message
+
+ def __call__(self, form, field):
+ pattern = re.compile(r'^([_a-z0-9\-]+)(\.[_a-z0-9\-]+)*@([a-z0-9\-]{2,}\.)*([a-z]{2,4})(,([_a-z0-9\-]+)(\.[_a-z0-9\-]+)*@([a-z0-9\-]{2,}\.)*([a-z]{2,4}))*$')
+ if not pattern.match(field.data.replace(" ", "")):
+ raise validators.ValidationError(self.message)
class ConfirmationForm(flask_wtf.FlaskForm):
submit = fields.SubmitField(_('Confirm'))
@@ -101,9 +109,7 @@ class UserSettingsForm(flask_wtf.FlaskForm):
spam_threshold = fields_.IntegerSliderField(_('Spam filter tolerance'))
forward_enabled = fields.BooleanField(_('Enable forwarding'))
forward_keep = fields.BooleanField(_('Keep a copy of the emails'))
- forward_destination = fields.StringField(
- _('Destination'), [validators.Optional(), validators.Email()]
- )
+ forward_destination = fields.StringField(_('Destination'), [validators.Optional(), MultipleEmailAddressesVerify()])
submit = fields.SubmitField(_('Save settings'))
diff --git a/core/admin/mailu/ui/views/users.py b/core/admin/mailu/ui/views/users.py
index 51dfdc13..4cbe7a97 100644
--- a/core/admin/mailu/ui/views/users.py
+++ b/core/admin/mailu/ui/views/users.py
@@ -7,7 +7,6 @@ import flask_login
import wtforms
import wtforms_components
-
@ui.route('/user/list/', methods=['GET'])
@access.domain_admin(models.Domain, 'domain_name')
def user_list(domain_name):
@@ -92,9 +91,16 @@ def user_settings(user_email):
user_email_or_current = user_email or flask_login.current_user.email
user = models.User.query.get(user_email_or_current) or flask.abort(404)
form = forms.UserSettingsForm(obj=user)
+ if isinstance(form.forward_destination.data,str):
+ data = form.forward_destination.data.replace(" ","").split(",")
+ else:
+ data = form.forward_destination.data
+ form.forward_destination.data = ", ".join(data)
if form.validate_on_submit():
+ form.forward_destination.data = form.forward_destination.data.replace(" ","").split(",")
form.populate_obj(user)
models.db.session.commit()
+ form.forward_destination.data = ", ".join(form.forward_destination.data)
flask.flash('Settings updated for %s' % user)
if user_email:
return flask.redirect(
From 2954d8479008e2205cf59958ae073b05051180cc Mon Sep 17 00:00:00 2001
From: TheLegend875
Date: Sun, 30 Dec 2018 20:29:41 +0100
Subject: [PATCH 06/33] added necessary ui elements
---
core/admin/mailu/ui/forms.py | 1 +
core/admin/mailu/ui/templates/user/create.html | 1 +
core/admin/mailu/ui/templates/user/settings.html | 4 ++++
3 files changed, 6 insertions(+)
diff --git a/core/admin/mailu/ui/forms.py b/core/admin/mailu/ui/forms.py
index 40a56a82..e021cd60 100644
--- a/core/admin/mailu/ui/forms.py
+++ b/core/admin/mailu/ui/forms.py
@@ -81,6 +81,7 @@ class UserForm(flask_wtf.FlaskForm):
quota_bytes = fields_.IntegerSliderField(_('Quota'), default=1000000000)
enable_imap = fields.BooleanField(_('Allow IMAP access'), default=True)
enable_pop = fields.BooleanField(_('Allow POP3 access'), default=True)
+ displayed_name = fields.StringField(_('Displayed name'))
comment = fields.StringField(_('Comment'))
enabled = fields.BooleanField(_('Enabled'), default=True)
submit = fields.SubmitField(_('Save'))
diff --git a/core/admin/mailu/ui/templates/user/create.html b/core/admin/mailu/ui/templates/user/create.html
index 09e83155..ed7b9884 100644
--- a/core/admin/mailu/ui/templates/user/create.html
+++ b/core/admin/mailu/ui/templates/user/create.html
@@ -15,6 +15,7 @@
{% call macros.box(_("General")) %}
{{ macros.form_field(form.localpart, append='@'+domain.name+' ') }}
{{ macros.form_fields((form.pw, form.pw2)) }}
+ {{ macros.form_field(form.displayed_name) }}
{{ macros.form_field(form.comment) }}
{{ macros.form_field(form.enabled) }}
{% endcall %}
diff --git a/core/admin/mailu/ui/templates/user/settings.html b/core/admin/mailu/ui/templates/user/settings.html
index e14d2d70..b6ade695 100644
--- a/core/admin/mailu/ui/templates/user/settings.html
+++ b/core/admin/mailu/ui/templates/user/settings.html
@@ -11,6 +11,10 @@
{% block content %}
to read and check the configuration variables generated by the wizard.
cd {{ root }}
-curl {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }} > docker-compose.yml
-curl {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }} > mailu.env
+wget {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }}
+wget {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }}
{% endcall %}
diff --git a/setup/flavors/stack/setup.html b/setup/flavors/stack/setup.html
index d68a6422..d214e3c5 100644
--- a/setup/flavors/stack/setup.html
+++ b/setup/flavors/stack/setup.html
@@ -11,8 +11,8 @@ in a project directory. First create your project directory.
to read and check the configuration variables generated by the wizard.
cd {{ root }}
-curl {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }} > docker-compose.yml
-curl {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }} > mailu.env
+wget {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }}
+wget {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }}
{% endcall %}
From 4c7cdeb43bfede6d296c9de6132771e647bf0214 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 04:13:25 +0200
Subject: [PATCH 09/33] FAQ: Difference between DOMAINS and HOSTNAMES - Closes
#742 - Closes #747
---
docs/faq.rst | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/docs/faq.rst b/docs/faq.rst
index 395b739c..7849d7c5 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -89,6 +89,51 @@ our ongoing `project management`_ discussion issue.
Deployment related
------------------
+What is the difference between DOMAIN and HOSTNAMES?
+````````````````````````````````````````````````````
+
+Similair questions:
+
+- Changing domain doesn't work
+- Do I need a certificate for ``DOMAIN``?
+
+``DOMAIN`` is the main mail domain. Aka, server identification for outgoing mail. DMARC reports point to ``POSTMASTER`` @ ``DOMAIN``.
+These are really the only things it is used for. You don't need a cert for ``DOMAIN``, as it is a mail domain only and not used as host in any sense.
+However, it is usual that ``DOMAIN`` gets setup as one of the many mail domains. None of the mail domains ever need a certificate.
+TLS certificates work on host connection level only.
+
+``HOSTNAMES`` however, can be used to connect to the server. All host names supplied in this variable will need a certificate. When ``TLS_FLAVOR=letsencrypt`` is set,
+a certificate is requested automatically for all those domains.
+
+So when you have something like this:
+
+.. code-block:: bash
+
+ DOMAIN=example.com
+ POSTMASTER=me
+ HOSTNAMES=mail.example.com,mail.foo.com,bar.com
+ TLS_FLAVOR=letsencrypt
+
+- You'll end up with a DMARC address to ``me@example.com``.
+- Server identifies itself as the SMTP server of ``@example.com`` when sending mail. Make sure your reverse DNS hostname is part of that domain!
+- Your server will have certificates for the 3 hostnames. You will need to create ``A`` and ``AAAA`` records for those names,
+ pointing to the IP addresses of your server.
+- The admin interface generates ``MX`` and ``SPF`` examples which point to the first entry of ``HOSTNAMES`` but these are only examples.
+ You can modify them to use any other ``HOSTNAMES`` entry.
+
+You're mail service will be reachable for IMAP, POP3, SMTP and Webmail at the addresses:
+
+- mail.example.com
+- mail.foo.com
+- bar.com
+
+.. note::
+
+ In this case ``example.com`` is not reachable as a host and will not have a certificate.
+ It can be used as a mail domain if MX is setup to point to one of the ``HOSTNAMES``. However, it is possible to include ``example.com`` in ``HOSTNAMES``.
+
+*Issue reference:* `742`_, `747`_.
+
How does Mailu scale up?
````````````````````````
@@ -154,6 +199,8 @@ correct syntax. The following file names will be taken as override configuration
.. _`165`: https://github.com/Mailu/Mailu/issues/165
.. _`177`: https://github.com/Mailu/Mailu/issues/177
.. _`332`: https://github.com/Mailu/Mailu/issues/332
+.. _`742`: https://github.com/Mailu/Mailu/issues/742
+.. _`747`: https://github.com/Mailu/Mailu/issues/747
.. _`520`: https://github.com/Mailu/Mailu/issues/520
.. _`591`: https://github.com/Mailu/Mailu/issues/591
From dc238bb2b33f72db32c8bc6c2908e9ee79f9f9a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 04:33:37 +0200
Subject: [PATCH 10/33] FAQ: Unbound DNS - Closes #554
---
docs/faq.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/docs/faq.rst b/docs/faq.rst
index 7849d7c5..8c1b0685 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -312,12 +312,30 @@ spam filter weight settings.
*Issue reference:* `503`_.
+rspamd: DNS query blocked on multi.uribl.com
+````````````````````````````````````````````
+
+This usually relates to the DNS server you are using. Most of the public servers block this query or there is a rate limit.
+In order to solve this, you most probably are better off using a root DNS resolver, such as `unbound`_. This can be done in multiple ways:
+
+- Use the *Mailu/unbound* container. This is an optional include when generating the ``docker-compose.yml`` file with the setup utility.
+- Setup unbound on the host and make sure the host's ``/etc/resolve.conf`` points to local host.
+ Docker will then forward all external DNS requests to the local server.
+- Set up an external DNS server with root resolving capabilities.
+
+In any case, using a dedicated DNS server will improve the performance of your mail server.
+
+*Issue reference:* `554`_, `681`_.
+
.. _`troubleshooting tag`: https://github.com/Mailu/Mailu/issues?utf8=%E2%9C%93&q=label%3Afaq%2Ftroubleshooting
.. _`85`: https://github.com/Mailu/Mailu/issues/85
.. _`116`: https://github.com/Mailu/Mailu/issues/116
.. _`171`: https://github.com/Mailu/Mailu/issues/171
.. _`426`: https://github.com/Mailu/Mailu/issues/426
.. _`503`: https://github.com/Mailu/Mailu/issues/503
+.. _`554`: https://github.com/Mailu/Mailu/issues/554
.. _`584`: https://github.com/Mailu/Mailu/issues/584
.. _`592`: https://github.com/Mailu/Mailu/issues/592
.. _`615`: https://github.com/Mailu/Mailu/issues/615
+.. _`681`: https://github.com/Mailu/Mailu/pull/681
+.. _`unbound`: https://nlnetlabs.nl/projects/unbound/about/
From df55b2e9d6f6865a7a59ec8ba338ef234852d9d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 04:38:59 +0200
Subject: [PATCH 11/33] Reference and close #206
---
docs/faq.rst | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docs/faq.rst b/docs/faq.rst
index 8c1b0685..768bed83 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -191,6 +191,8 @@ correct syntax. The following file names will be taken as override configuration
- `Dovecot`_ - ``dovecot.conf``;
- `Rspamd`_ - All files in the ``rspamd`` sub-directory.
+*Issue reference:* `206`_.
+
.. _`Postfix`: http://www.postfix.org/postconf.5.html
.. _`Dovecot`: https://wiki.dovecot.org/ConfigFile
.. _`Rspamd`: https://www.rspamd.com/doc/configuration/index.html
@@ -325,12 +327,13 @@ In order to solve this, you most probably are better off using a root DNS resolv
In any case, using a dedicated DNS server will improve the performance of your mail server.
-*Issue reference:* `554`_, `681`_.
+*Issue reference:* `206`_, `554`_, `681`_.
.. _`troubleshooting tag`: https://github.com/Mailu/Mailu/issues?utf8=%E2%9C%93&q=label%3Afaq%2Ftroubleshooting
.. _`85`: https://github.com/Mailu/Mailu/issues/85
.. _`116`: https://github.com/Mailu/Mailu/issues/116
.. _`171`: https://github.com/Mailu/Mailu/issues/171
+.. _`206`: https://github.com/Mailu/Mailu/issues/206
.. _`426`: https://github.com/Mailu/Mailu/issues/426
.. _`503`: https://github.com/Mailu/Mailu/issues/503
.. _`554`: https://github.com/Mailu/Mailu/issues/554
From 8dd30a698b56aa4a69c64d00e6155c0dfa8946f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 04:51:12 +0200
Subject: [PATCH 12/33] FAQ: Rancher - Closes #125
---
docs/faq.rst | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/docs/faq.rst b/docs/faq.rst
index 768bed83..6ee1871e 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -168,6 +168,16 @@ For **service** HA, please see: `How does Mailu scale up?`_
.. _`spam magnet`: https://blog.zensoftware.co.uk/2012/07/02/why-we-tend-to-recommend-not-having-a-secondary-mx-these-days/
+Does Mailu run on Rancher?
+``````````````````````````
+
+There is a rancher catalog for Mailu in the `Mailu/Rancher`_ repository. The user group for Rancher is small,
+so we cannot promise any support on this when you're heading into trouble. See the repository README for more details.
+
+*Issue reference:* `125`_.
+
+.. _`Mailu/Rancher`: https://github.com/Mailu/Rancher
+
Can I run Mailu without host iptables?
``````````````````````````````````````
@@ -198,6 +208,7 @@ correct syntax. The following file names will be taken as override configuration
.. _`Rspamd`: https://www.rspamd.com/doc/configuration/index.html
.. _`Docker swarm howto`: https://github.com/Mailu/Mailu/tree/master/docs/swarm/master
+.. _`125`: https://github.com/Mailu/Mailu/issues/125
.. _`165`: https://github.com/Mailu/Mailu/issues/165
.. _`177`: https://github.com/Mailu/Mailu/issues/177
.. _`332`: https://github.com/Mailu/Mailu/issues/332
From 4c78785da32f3f7ea31d41b43815004be3e46ead Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 04:57:17 +0200
Subject: [PATCH 13/33] FAQ: DKIM and DMARC generation - Closes #102
---
docs/faq.rst | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/docs/faq.rst b/docs/faq.rst
index 6ee1871e..ef4103c2 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -301,8 +301,18 @@ See also :ref:`external_certs`.
*Issue reference:* `426`_, `615`_.
+How do I activate DKIM and DMARC?
+```````````````````````
+Go into the Domain Panel and choose the Domain you want to enable DKIM for.
+Click the first icon on the left side (domain details).
+Now click on the top right on the *"Regenerate Keys"* Button.
+This will generate the DKIM and DMARC entries for you.
+
+*Issue reference:* `102`_.
+
Do you support Fail2Ban?
````````````````````````
+
Fail2Ban is not included in Mailu. Fail2Ban needs to modify the host's IP tables in order to
ban the addresses. We consider such a program should be run on the host system and not
inside a container. The ``front`` container does use authentication rate limiting to slow
@@ -342,6 +352,7 @@ In any case, using a dedicated DNS server will improve the performance of your m
.. _`troubleshooting tag`: https://github.com/Mailu/Mailu/issues?utf8=%E2%9C%93&q=label%3Afaq%2Ftroubleshooting
.. _`85`: https://github.com/Mailu/Mailu/issues/85
+.. _`102`: https://github.com/Mailu/Mailu/issues/102
.. _`116`: https://github.com/Mailu/Mailu/issues/116
.. _`171`: https://github.com/Mailu/Mailu/issues/171
.. _`206`: https://github.com/Mailu/Mailu/issues/206
From f91b80503e132c1b34ddf3759e08f501204a3bb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 31 Dec 2018 05:11:56 +0200
Subject: [PATCH 14/33] FAQ: Older ciphers - Closes #698
---
docs/faq.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/docs/faq.rst b/docs/faq.rst
index ef4103c2..545e0427 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -350,12 +350,29 @@ In any case, using a dedicated DNS server will improve the performance of your m
*Issue reference:* `206`_, `554`_, `681`_.
+Is there a way to support more (older) ciphers?
+```````````````````````````````````````````````
+
+See `How can I override settings?`_ .
+You will need to add the protocols you wish to support in an override for the ``front`` container (Nginx).
+
+.. code-block:: bash
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers ;
+
+We **strongly** advice against downgrading the TLS version and ciphers!
+
+*Issue reference:* `363`_, `698`_.
+
+
.. _`troubleshooting tag`: https://github.com/Mailu/Mailu/issues?utf8=%E2%9C%93&q=label%3Afaq%2Ftroubleshooting
.. _`85`: https://github.com/Mailu/Mailu/issues/85
.. _`102`: https://github.com/Mailu/Mailu/issues/102
.. _`116`: https://github.com/Mailu/Mailu/issues/116
.. _`171`: https://github.com/Mailu/Mailu/issues/171
.. _`206`: https://github.com/Mailu/Mailu/issues/206
+.. _`363`: https://github.com/Mailu/Mailu/issues/363
.. _`426`: https://github.com/Mailu/Mailu/issues/426
.. _`503`: https://github.com/Mailu/Mailu/issues/503
.. _`554`: https://github.com/Mailu/Mailu/issues/554
@@ -363,4 +380,5 @@ In any case, using a dedicated DNS server will improve the performance of your m
.. _`592`: https://github.com/Mailu/Mailu/issues/592
.. _`615`: https://github.com/Mailu/Mailu/issues/615
.. _`681`: https://github.com/Mailu/Mailu/pull/681
+.. _`698`: https://github.com/Mailu/Mailu/issues/698
.. _`unbound`: https://nlnetlabs.nl/projects/unbound/about/
From 4a072992dbf0c2bac96b01d8ffbaca3c6785317d Mon Sep 17 00:00:00 2001
From: Dennis Neufeld
Date: Tue, 1 Jan 2019 18:48:09 +0100
Subject: [PATCH 15/33] Fix typo in demo.rst
---
docs/demo.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/demo.rst b/docs/demo.rst
index 9415e670..fb66f2ff 100644
--- a/docs/demo.rst
+++ b/docs/demo.rst
@@ -18,7 +18,7 @@ Functionality
- The server is reset every day at 3am, UTC.
- You can send mail from any client to the server.
- However, the stmp server is made incapable of relaying the e-mail to the destination server.
+ However, the SMTP server is made incapable of relaying the e-mail to the destination server.
As such, the mail will never arrive. This is to prevent abuse of the server.
- The server is capable of receiving mail for any configured domains.
- The server exposes IMAP, POP3 and SMTP as usual for connection with mail clients such as Thunderbird.
From f2e3d755a620dded0e0fb5980810b09a3a458a3c Mon Sep 17 00:00:00 2001
From: hoellen
Date: Wed, 2 Jan 2019 10:59:19 +0100
Subject: [PATCH 16/33] add nginx conf override to faq
---
docs/faq.rst | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/docs/faq.rst b/docs/faq.rst
index 395b739c..4d134edd 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -138,17 +138,19 @@ For that reason we do **not** support deployment on Docker hosts without iptable
How can I override settings?
````````````````````````````
-Postfix, dovecot and Rspamd support overriding configuration files. Override files belong in
+Postfix, Dovecot, Nginx and Rspamd support overriding configuration files. Override files belong in
``$ROOT/overrides``. Please refer to the official documentation of those programs for the
correct syntax. The following file names will be taken as override configuration:
- `Postfix`_ - ``postfix.cf``;
- `Dovecot`_ - ``dovecot.conf``;
+- `Nginx`_ - All ``*.conf`` files in the ``nginx`` sub-directory.
- `Rspamd`_ - All files in the ``rspamd`` sub-directory.
.. _`Postfix`: http://www.postfix.org/postconf.5.html
.. _`Dovecot`: https://wiki.dovecot.org/ConfigFile
-.. _`Rspamd`: https://www.rspamd.com/doc/configuration/index.html
+.. _`NGINX`: https://nginx.org/en/docs/
+.. _`Rspamd`: https://www.rspamd.com/doc/configuration/index.html
.. _`Docker swarm howto`: https://github.com/Mailu/Mailu/tree/master/docs/swarm/master
.. _`165`: https://github.com/Mailu/Mailu/issues/165
From f617e82c069ed5e4b5b959ff693ea6fcce238a07 Mon Sep 17 00:00:00 2001
From: hoellen
Date: Wed, 2 Jan 2019 14:08:03 +0100
Subject: [PATCH 17/33] fix broken webmail and logo url in admin
---
core/admin/mailu/ui/templates/base.html | 2 +-
core/admin/mailu/ui/templates/sidebar.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/admin/mailu/ui/templates/base.html b/core/admin/mailu/ui/templates/base.html
index 08488560..73fa7aa7 100644
--- a/core/admin/mailu/ui/templates/base.html
+++ b/core/admin/mailu/ui/templates/base.html
@@ -28,7 +28,7 @@ class="hold-transition skin-blue sidebar-mini"
{% block navbar %}
diff --git a/core/admin/mailu/ui/templates/sidebar.html b/core/admin/mailu/ui/templates/sidebar.html
index c3a2ced6..3d945380 100644
--- a/core/admin/mailu/ui/templates/sidebar.html
+++ b/core/admin/mailu/ui/templates/sidebar.html
@@ -69,7 +69,7 @@
{% if config["WEBMAIL"] != "none" %}
-
+
{% trans %}Webmail{% endtrans %}
From 8c8e06de4864c4a044fc79f25494870ff4023ca3 Mon Sep 17 00:00:00 2001
From: hoellen
Date: Wed, 2 Jan 2019 14:19:55 +0100
Subject: [PATCH 18/33] add #792 to changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f3bcce93..93b51220 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -107,6 +107,7 @@ v1.6.0 - unreleased
- Bug: Hostname resolving in start.py should retry on failure [docker swarm] ([#555](https://github.com/Mailu/Mailu/issues/555))
- Bug: Error when trying to log in with an account without domain ([#585](https://github.com/Mailu/Mailu/issues/585))
- Bug: Fix rainloop permissions ([#637](https://github.com/Mailu/Mailu/issues/637))
+- Bug: Fix broken webmail and logo url in admin ([#792](https://github.com/Mailu/Mailu/issues/792))
v1.5.1 - 2017-11-21
-------------------
From 47234786ea9e3c56eb97ed37aaaf7146b92fb4df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Wed, 2 Jan 2019 19:12:46 +0200
Subject: [PATCH 19/33] Disable mergify strict mode
---
.mergify.yml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.mergify.yml b/.mergify.yml
index a950b0ca..927bfc3e 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -7,7 +7,6 @@ pull_request_rules:
actions:
merge:
method: merge
- strict: true
dismiss_reviews:
approved: true
@@ -20,6 +19,5 @@ pull_request_rules:
actions:
merge:
method: merge
- strict: true
dismiss_reviews:
approved: true
From cd85b4497269596341eb707ae5e3a1dff2e78a58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Wed, 2 Jan 2019 19:15:56 +0200
Subject: [PATCH 20/33] Fix typo
---
docs/faq.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/faq.rst b/docs/faq.rst
index 545e0427..8bd82d95 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -92,7 +92,7 @@ Deployment related
What is the difference between DOMAIN and HOSTNAMES?
````````````````````````````````````````````````````
-Similair questions:
+Similar questions:
- Changing domain doesn't work
- Do I need a certificate for ``DOMAIN``?
From 738d98e5abd040355f851fd829f455235ec30a04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Wed, 2 Jan 2019 20:11:12 +0200
Subject: [PATCH 21/33] Fix code formatting
---
setup/server.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup/server.py b/setup/server.py
index 3c950b0a..4474cd6c 100644
--- a/setup/server.py
+++ b/setup/server.py
@@ -12,7 +12,7 @@ import ipaddress
version = os.getenv("this_version")
static_url_path = "/" + version + "/static"
-app = flask.Flask(__name__,static_url_path=static_url_path)
+app = flask.Flask(__name__, static_url_path=static_url_path)
flask_bootstrap.Bootstrap(app)
db = redis.StrictRedis(host='redis', port=6379, db=0)
From ce7105c3ad70e7fad5c7b0354301e359eb4dc632 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Wed, 2 Jan 2019 20:33:42 +0200
Subject: [PATCH 22/33] Create PULL_REQUEST_TEMPLATE.md
---
PULL_REQUEST_TEMPLATE.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 PULL_REQUEST_TEMPLATE.md
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..84a5cb8f
--- /dev/null
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,14 @@
+## What type of PR?
+
+(Feature, enhancement, bug-fix, documentation)
+
+## What does this PR do?
+
+
+
+## Prerequistes
+Before we can consider review and merge, please make sure the following list is done and checked.
+If an entry in not applicable, you can check it or remove it from the list.
+
+- [ ] In case of feature or enhancement: documentation updated accordingly
+- [ ] Unless it's docs or a minor change: place entry in the [changelog](CHANGELOG.md), under the latest un-released version.
From 4e8f899b28e2152843f00eae12bd73da1eb20fc5 Mon Sep 17 00:00:00 2001
From: Ionut Filip
Date: Fri, 4 Jan 2019 11:19:43 +0200
Subject: [PATCH 23/33] Updated faq with nextcloud integration
---
docs/faq.rst | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/docs/faq.rst b/docs/faq.rst
index cf1895ea..a48c14c4 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -204,6 +204,41 @@ correct syntax. The following file names will be taken as override configuration
*Issue reference:* `206`_.
+I want to integrate Nextcloud with Mailu
+````````````````````````````````````````
+
+First of all you have to to install next dependencies in Nextcloud
+
+.. code-block:: bash
+
+ apt-get update \
+ && apt-get install -y libc-client-dev libkrb5-dev \
+ && rm -rf /var/lib/apt/lists/* \
+ && docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
+ && docker-php-ext-install imap
+
+Next, you have to enable External user support from Nextcloud Apps interface
+
+In the end you need to configure additional user backends in Nextcloud’s configuration config/config.php using the following syntax:
+
+.. code-block:: bash
+
+ array(
+ array(
+ 'class' => 'OC_User_IMAP',
+ 'arguments' => array(
+ '{imap.example.com:993/imap/ssl}', 'example.com'
+ ),
+ ),
+ ),
+
+If a domain name (e.g. example.com) is specified, then this makes sure that only users from this domain will be allowed to login.
+After successfull login the domain part will be striped and the rest used as username in NextCloud. e.g. 'username@example.com' will be 'username' in NextCloud.
+
+*Issue reference:* `575`_.
+
.. _`Postfix`: http://www.postfix.org/postconf.5.html
.. _`Dovecot`: https://wiki.dovecot.org/ConfigFile
.. _`NGINX`: https://nginx.org/en/docs/
@@ -218,6 +253,7 @@ correct syntax. The following file names will be taken as override configuration
.. _`747`: https://github.com/Mailu/Mailu/issues/747
.. _`520`: https://github.com/Mailu/Mailu/issues/520
.. _`591`: https://github.com/Mailu/Mailu/issues/591
+.. _`575`: https://github.com/Mailu/Mailu/issues/575
Technical issues
----------------
@@ -304,7 +340,7 @@ See also :ref:`external_certs`.
*Issue reference:* `426`_, `615`_.
How do I activate DKIM and DMARC?
-```````````````````````
+`````````````````````````````````
Go into the Domain Panel and choose the Domain you want to enable DKIM for.
Click the first icon on the left side (domain details).
Now click on the top right on the *"Regenerate Keys"* Button.
@@ -367,7 +403,6 @@ We **strongly** advice against downgrading the TLS version and ciphers!
*Issue reference:* `363`_, `698`_.
-
.. _`troubleshooting tag`: https://github.com/Mailu/Mailu/issues?utf8=%E2%9C%93&q=label%3Afaq%2Ftroubleshooting
.. _`85`: https://github.com/Mailu/Mailu/issues/85
.. _`102`: https://github.com/Mailu/Mailu/issues/102
From 0764c81a575154dd4ad97dbebaef840418ff5286 Mon Sep 17 00:00:00 2001
From: Ionut Filip
Date: Fri, 4 Jan 2019 12:40:02 +0200
Subject: [PATCH 24/33] Fixed typo
---
docs/faq.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/faq.rst b/docs/faq.rst
index a48c14c4..2669d9d1 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -207,7 +207,7 @@ correct syntax. The following file names will be taken as override configuration
I want to integrate Nextcloud with Mailu
````````````````````````````````````````
-First of all you have to to install next dependencies in Nextcloud
+First of all you have to install dependencies required to authenticate users via imap in Nextcloud
.. code-block:: bash
From d5d4d6c33711ad81c91b923ebdf8e755e70ab4f8 Mon Sep 17 00:00:00 2001
From: hoellen
Date: Fri, 4 Jan 2019 18:01:46 +0100
Subject: [PATCH 25/33] harden email address validation and fix routes with
user_email
---
core/admin/mailu/internal/views/dovecot.py | 10 +++++-----
core/admin/mailu/ui/forms.py | 2 +-
core/admin/mailu/ui/views/fetches.py | 4 ++--
core/admin/mailu/ui/views/managers.py | 2 +-
core/admin/mailu/ui/views/tokens.py | 4 ++--
core/admin/mailu/ui/views/users.py | 12 ++++++------
6 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/core/admin/mailu/internal/views/dovecot.py b/core/admin/mailu/internal/views/dovecot.py
index 463ecc20..f44f59bc 100644
--- a/core/admin/mailu/internal/views/dovecot.py
+++ b/core/admin/mailu/internal/views/dovecot.py
@@ -6,7 +6,7 @@ import flask
import socket
import os
-@internal.route("/dovecot/passdb/")
+@internal.route("/dovecot/passdb/")
def dovecot_passdb_dict(user_email):
user = models.User.query.get(user_email) or flask.abort(404)
allow_nets = []
@@ -20,7 +20,7 @@ def dovecot_passdb_dict(user_email):
})
-@internal.route("/dovecot/userdb/")
+@internal.route("/dovecot/userdb/")
def dovecot_userdb_dict(user_email):
user = models.User.query.get(user_email) or flask.abort(404)
return flask.jsonify({
@@ -28,7 +28,7 @@ def dovecot_userdb_dict(user_email):
})
-@internal.route("/dovecot/quota//", methods=["POST"])
+@internal.route("/dovecot/quota//", methods=["POST"])
def dovecot_quota(ns, user_email):
user = models.User.query.get(user_email) or flask.abort(404)
if ns == "storage":
@@ -37,12 +37,12 @@ def dovecot_quota(ns, user_email):
return flask.jsonify(None)
-@internal.route("/dovecot/sieve/name/
diff --git a/core/nginx/Dockerfile b/core/nginx/Dockerfile
index 8b1a2bae..6afa8301 100644
--- a/core/nginx/Dockerfile
+++ b/core/nginx/Dockerfile
@@ -10,6 +10,7 @@ RUN apk add --no-cache certbot nginx nginx-mod-mail openssl curl \
&& pip3 install idna requests watchdog
COPY conf /conf
+COPY static /static
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
diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf
index c90f7806..1733f8c4 100644
--- a/core/nginx/conf/nginx.conf
+++ b/core/nginx/conf/nginx.conf
@@ -38,6 +38,8 @@ http {
{% if KUBERNETES_INGRESS != 'true' %}
# Main HTTP server
server {
+ # Favicon stuff
+ root /static;
# Variables for proxifying
set $admin {{ HOST_ADMIN }};
set $antispam {{ HOST_ANTISPAM }};
@@ -90,9 +92,9 @@ http {
{% if WEB_WEBMAIL != '/' %}
location / {
{% if WEBROOT_REDIRECT %}
- return 301 {{ WEBROOT_REDIRECT }};
+ try_files $uri $uri/ {{ WEBROOT_REDIRECT }};
{% else %}
- return 404;
+ try_files $uri $uri/ =404;
{% endif %}
}
{% endif %}
diff --git a/core/nginx/static/android-chrome-192x192.png b/core/nginx/static/android-chrome-192x192.png
new file mode 100644
index 0000000000000000000000000000000000000000..86231db9042b8cf7191d469d5c1c39c164ba9514
GIT binary patch
literal 6274
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
literal 0
HcmV?d00001
diff --git a/core/nginx/static/browserconfig.xml b/core/nginx/static/browserconfig.xml
new file mode 100644
index 00000000..5aecc916
--- /dev/null
+++ b/core/nginx/static/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #00aba9
+
+
+
diff --git a/core/nginx/static/favicon-16x16.png b/core/nginx/static/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff35d4b0a7618b3b4df63d27c6d0793ced5735d1
GIT binary patch
literal 978
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F
z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>tE{G
zuNM10z5e;H_|i9{y&w5Ey+82!ch!||46EPi?f&R_^t1k+k9WWPee&(^oiBg&_IzYs
z_fCAv2cS2#c74>{{ZVt*N1qO(-@s5cED7=hMiHyig1g`5i*~I_cV4F0NO=9DQ$?w^{RzCgXS-e!`F;FvOlDE5ywI$z|93Y3i#M9T6
z{V^jOpNQC$*T3EYh3C<#g|S12gTPs_|nRVb+}NL9!zC`o2usF?Hk6AwpWn1;qF|I=qYp9V27
zD|725a|bP0l+XkK6l2B>
literal 0
HcmV?d00001
diff --git a/core/nginx/static/favicon-32x32.png b/core/nginx/static/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b6b749b92a5d0f19c470f28ae0cc8eb70efec23
GIT binary patch
literal 1523
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
biIpnwO^_#O%S1baVFIu;vo$4~T)X!l@xsf9
literal 0
HcmV?d00001
diff --git a/core/nginx/static/safari-pinned-tab.svg b/core/nginx/static/safari-pinned-tab.svg
new file mode 100644
index 00000000..43cea812
--- /dev/null
+++ b/core/nginx/static/safari-pinned-tab.svg
@@ -0,0 +1,25 @@
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+
+
+
diff --git a/core/nginx/static/site.webmanifest b/core/nginx/static/site.webmanifest
new file mode 100644
index 00000000..b20abb7c
--- /dev/null
+++ b/core/nginx/static/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
From 5bdeee7b49ba32f808a380185ed109b503ad8790 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Sun, 6 Jan 2019 16:02:26 +0200
Subject: [PATCH 30/33] Example for related and autoclose issues
---
PULL_REQUEST_TEMPLATE.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
index 84a5cb8f..856fa5a0 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -4,7 +4,9 @@
## What does this PR do?
-
+### Related issue(s)
+- Mention an issue like: #001
+- Auto close an issue like: closes #001
## Prerequistes
Before we can consider review and merge, please make sure the following list is done and checked.
From 5df63c6d7f79a60a2dd0d4b79f2a0c78c2ef1ead Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Sun, 6 Jan 2019 16:16:06 +0200
Subject: [PATCH 31/33] Favicon changelog entry
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93b51220..8277743d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -76,6 +76,7 @@ v1.6.0 - unreleased
- Enhancement: Move Mailu Docker network to a fixed subnet ([#727](https://github.com/Mailu/Mailu/issues/727))
- Enhancement: Added regex validation for alias username ([#764](https://github.com/Mailu/Mailu/issues/764))
- Enhancement: Update documentation
+- Enhancement: Include favicon package ([#801](https://github.com/Mailu/Mailu/issues/801), ([#802](https://github.com/Mailu/Mailu/issues/802))
- Upstream: Update Roundcube
- Upstream: Update Rainloop
- Bug: Rainloop fails with "domain not allowed" ([#93](https://github.com/Mailu/Mailu/issues/93))
From 4b0601cb64fd715860f35878e2e0bd588dd14104 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 7 Jan 2019 12:23:18 +0200
Subject: [PATCH 32/33] Add WEBROOT_REDIRECT documentation Closes #802
---
docs/configuration.rst | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 2f44b293..b8f2a90c 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -71,6 +71,14 @@ Web settings
The ``WEB_ADMIN`` contains the path to the main admin interface, while
``WEB_WEBMAIL`` contains the path to the Web email client.
+The ``WEBROOT_REDIRECT`` redirects all non-found queries to the set path.
+An empty ``WEBROOT_REDIRECT`` value disables redirecting and enables classic
+behavior of a 404 result when not found.
+All three options need a leading slash (``/``) to work.
+
+ .. note:: ``WEBROOT_REDIRECT`` has to point to a valid path on the webserver.
+ This means it cannot point to any services which are not enabled.
+ For example, don't point it to ``/webmail`` when ``WEBMAIL=none``
Both ``SITENAME`` and ``WEBSITE`` are customization options for the panel menu
in the admin interface, while ``SITENAME`` is a customization option for
From 5636e7f5a772b09b50e35e69327129384a15175d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20M=C3=B6hlmann?=
Date: Mon, 7 Jan 2019 14:08:00 +0200
Subject: [PATCH 33/33] Remove to avoid matching webroot
---
core/nginx/conf/nginx.conf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf
index 1733f8c4..7107a351 100644
--- a/core/nginx/conf/nginx.conf
+++ b/core/nginx/conf/nginx.conf
@@ -92,9 +92,9 @@ http {
{% if WEB_WEBMAIL != '/' %}
location / {
{% if WEBROOT_REDIRECT %}
- try_files $uri $uri/ {{ WEBROOT_REDIRECT }};
+ try_files $uri {{ WEBROOT_REDIRECT }};
{% else %}
- try_files $uri $uri/ =404;
+ try_files $uri =404;
{% endif %}
}
{% endif %}