mirror of
https://github.com/Mailu/Mailu.git
synced 2025-03-17 20:57:54 +02:00
Merge #886
886: Ipv6 support r=mergify[bot] a=muhlemmer ## What type of PR? (Feature, enhancement, bug-fix, documentation) -> A bit of everything ## What does this PR do? Document how to use ipv6nat. This, however triggers some kind of flaky behavior with the Docker DNS resolver, resulting in lookup failures between containers. So all resolving needs to be done during container startup/configuration. In order not to pollute every single start.py file, we've created a small library called [Mailu/MailuStart](https://github.com/Mailu/MailuStart). As an addition, this library also defines the template generation function, including its logging facility. Note: `docker-compose.yml` downgrade is necessary, as IPv6 settings are not supported by the Docker Compose file format 3 😞 ### Related issue(s) Supersedes PR #844 - Fixes #827 - Hopefully helps with #829 and #834 ## No backport yet This PR directly imports MailuStart from git. This makes it a bit more simple to implement on the short term an do some testing and probably some future improvements. When everything is proved stable, we will create a proper PyPi package with versioning and consider back porting. ## 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. - [x] In case of feature or enhancement: documentation updated accordingly - [x] Unless it's docs or a minor change: place entry in the [changelog](CHANGELOG.md), under the latest un-released version. Co-authored-by: Ionut Filip <ionut.philip@gmail.com> Co-authored-by: Tim Möhlmann <muhlemmer@gmail.com>
This commit is contained in:
commit
86b4242f82
@ -36,7 +36,6 @@ v1.6.0 - 2019-01-18
|
||||
- Feature: Automated Releases ([#487](https://github.com/Mailu/Mailu/issues/487))
|
||||
- Feature: Support for ARC ([#495](https://github.com/Mailu/Mailu/issues/495))
|
||||
- Feature: Add posibilty to run webmail on root ([#501](https://github.com/Mailu/Mailu/issues/501))
|
||||
- Feature: Upgrade docker-compose.yml to version 3 ([#539](https://github.com/Mailu/Mailu/issues/539))
|
||||
- Feature: Documentation to deploy mailu on a docker swarm ([#551](https://github.com/Mailu/Mailu/issues/551))
|
||||
- Feature: Add optional Maildir-Compression ([#553](https://github.com/Mailu/Mailu/issues/553))
|
||||
- Feature: Preserve rspamd history on container restart ([#561](https://github.com/Mailu/Mailu/issues/561))
|
||||
@ -87,6 +86,7 @@ v1.6.0 - 2019-01-18
|
||||
- Enhancement: Include favicon package ([#801](https://github.com/Mailu/Mailu/issues/801), ([#802](https://github.com/Mailu/Mailu/issues/802))
|
||||
- Enhancement: Add logging at critical places in python start.py scripts. Implement LOG_LEVEL to control verbosity ([#588](https://github.com/Mailu/Mailu/issues/588))
|
||||
- Enhancement: Mark message as seen when reporting as spam
|
||||
- Enhancement: Better support and document IPv6 ([#827](https://github.com/Mailu/Mailu/issues/827))
|
||||
- Upstream: Update Roundcube
|
||||
- Upstream: Update Rainloop
|
||||
- Bug: Rainloop fails with "domain not allowed" ([#93](https://github.com/Mailu/Mailu/issues/93))
|
||||
|
@ -1,8 +1,9 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
|
||||
from mailustart import resolve
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
# Specific to the admin UI
|
||||
@ -61,7 +61,6 @@ DEFAULT_CONFIG = {
|
||||
'POD_ADDRESS_RANGE': None
|
||||
}
|
||||
|
||||
|
||||
class ConfigManager(dict):
|
||||
""" Naive configuration manager that uses environment only
|
||||
"""
|
||||
@ -75,6 +74,12 @@ class ConfigManager(dict):
|
||||
def __init__(self):
|
||||
self.config = dict()
|
||||
|
||||
def resolve_host(self):
|
||||
self.config['HOST_IMAP'] = resolve(self.config['HOST_IMAP'])
|
||||
self.config['HOST_POP3'] = resolve(self.config['HOST_POP3'])
|
||||
self.config['HOST_AUTHSMTP'] = resolve(self.config['HOST_AUTHSMTP'])
|
||||
self.config['HOST_SMTP'] = resolve(self.config['HOST_SMTP'])
|
||||
|
||||
def __coerce_value(self, value):
|
||||
if isinstance(value, str) and value.lower() in ('true','yes'):
|
||||
return True
|
||||
@ -89,6 +94,7 @@ class ConfigManager(dict):
|
||||
key: self.__coerce_value(os.environ.get(key, value))
|
||||
for key, value in DEFAULT_CONFIG.items()
|
||||
})
|
||||
self.resolve_host()
|
||||
|
||||
# automatically set the sqlalchemy string
|
||||
if self.config['DB_FLAVOR']:
|
||||
|
@ -2,7 +2,6 @@ from mailu import models
|
||||
from flask import current_app as app
|
||||
|
||||
import re
|
||||
import socket
|
||||
import urllib
|
||||
|
||||
|
||||
@ -89,5 +88,4 @@ def get_server(protocol, authenticated=False):
|
||||
hostname, port = extract_host_port(app.config['HOST_AUTHSMTP'], 10025)
|
||||
else:
|
||||
hostname, port = extract_host_port(app.config['HOST_SMTP'], 25)
|
||||
address = socket.gethostbyname(hostname)
|
||||
return address, port
|
||||
return hostname, port
|
||||
|
@ -1,12 +1,10 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
# Shared layer between rspamd, postfix, dovecot, unbound and nginx
|
||||
RUN pip3 install jinja2
|
||||
# Shared layer between rspamd, postfix, dovecot
|
||||
RUN pip3 install tenacity
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
RUN apk add --no-cache \
|
||||
dovecot dovecot-pigeonhole-plugin rspamd-client bash \
|
||||
|
@ -1,47 +1,29 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import socket
|
||||
import glob
|
||||
import multiprocessing
|
||||
import tenacity
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import resolve, convert
|
||||
|
||||
from tenacity import retry
|
||||
from podop import run_server
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def start_podop():
|
||||
os.setuid(8)
|
||||
url = "http://" + os.environ["ADMIN_ADDRESS"] + "/internal/dovecot/§"
|
||||
run_server(0, "dovecot", "/tmp/podop.socket", [
|
||||
("quota", "url", "http://admin/internal/dovecot/§"),
|
||||
("auth", "url", "http://admin/internal/dovecot/§"),
|
||||
("sieve", "url", "http://admin/internal/dovecot/§"),
|
||||
("quota", "url", url ),
|
||||
("auth", "url", url),
|
||||
("sieve", "url", url),
|
||||
])
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", 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),
|
||||
before=tenacity.before_log(log.getLogger("tenacity.retry"), log.DEBUG),
|
||||
before_sleep=tenacity.before_sleep_log(log.getLogger("tenacity.retry"), log.INFO),
|
||||
after=tenacity.after_log(log.getLogger("tenacity.retry"), log.DEBUG)
|
||||
)
|
||||
def resolve(hostname):
|
||||
logger = log.getLogger("resolve()")
|
||||
logger.info(hostname)
|
||||
return socket.gethostbyname(hostname)
|
||||
|
||||
# Actual startup script
|
||||
os.environ["FRONT_ADDRESS"] = resolve(os.environ.get("FRONT_ADDRESS", "front"))
|
||||
os.environ["REDIS_ADDRESS"] = resolve(os.environ.get("REDIS_ADDRESS", "redis"))
|
||||
os.environ["ADMIN_ADDRESS"] = resolve(os.environ.get("ADMIN_ADDRESS", "admin"))
|
||||
if os.environ["WEBMAIL"] != "none":
|
||||
os.environ["WEBMAIL_ADDRESS"] = resolve(os.environ.get("WEBMAIL_ADDRESS", "webmail"))
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
# Shared layer between rspamd, postfix, dovecot, unbound and nginx
|
||||
RUN pip3 install jinja2
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
RUN apk add --no-cache certbot nginx nginx-mod-mail openssl curl \
|
||||
&& pip3 install idna requests watchdog
|
||||
|
@ -1,32 +1,27 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import resolve, convert
|
||||
|
||||
args = os.environ.copy()
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def convert(src, dst, args):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", src, dst)
|
||||
open(dst, "w").write(jinja2.Template(open(src).read()).render(**args))
|
||||
|
||||
# Get the first DNS server
|
||||
with open("/etc/resolv.conf") as handle:
|
||||
content = handle.read().split()
|
||||
args["RESOLVER"] = content[content.index("nameserver") + 1]
|
||||
|
||||
if "HOST_WEBMAIL" not in args:
|
||||
args["HOST_WEBMAIL"] = "webmail"
|
||||
if "HOST_ADMIN" not in args:
|
||||
args["HOST_ADMIN"] = "admin"
|
||||
if "HOST_WEBDAV" not in args:
|
||||
args["HOST_WEBDAV"] = "webdav:5232"
|
||||
if "HOST_ANTISPAM" not in args:
|
||||
args["HOST_ANTISPAM"] = "antispam:11334"
|
||||
args["HOST_ADMIN"] = resolve(args.get("HOST_ADMIN", "admin"))
|
||||
args["HOST_ANTISPAM"] = resolve(args.get("HOST_ANTISPAM", "antispam:11334"))
|
||||
args["HOST_WEBMAIL"] = args.get("HOST_WEBMAIL", "webmail")
|
||||
if args["WEBMAIL"] != "none":
|
||||
args["HOST_WEBMAIL"] = resolve(args.get("HOST_WEBMAIL"))
|
||||
args["HOST_WEBDAV"] = args.get("HOST_WEBDAV", "webdav:5232")
|
||||
if args["WEBDAV"] != "none":
|
||||
args["HOST_WEBDAV"] = resolve(args.get("HOST_WEBDAV"))
|
||||
|
||||
# TLS configuration
|
||||
cert_name = os.getenv("TLS_CERT_FILENAME", default="cert.pem")
|
||||
|
@ -1,12 +1,10 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
# Shared layer between rspamd, postfix, dovecot, unbound and nginx
|
||||
RUN pip3 install jinja2
|
||||
# Shared layer between rspamd, postfix, dovecot
|
||||
RUN pip3 install tenacity
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
|
||||
RUN apk add --no-cache postfix postfix-pcre rsyslog \
|
||||
|
@ -1,53 +1,35 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import socket
|
||||
import glob
|
||||
import shutil
|
||||
import tenacity
|
||||
import multiprocessing
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import resolve, convert
|
||||
|
||||
from tenacity import retry
|
||||
from podop import run_server
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def start_podop():
|
||||
os.setuid(100)
|
||||
url = "http://" + os.environ["ADMIN_ADDRESS"] + "/internal/postfix/"
|
||||
# TODO: Remove verbosity setting from Podop?
|
||||
run_server(0, "postfix", "/tmp/podop.socket", [
|
||||
("transport", "url", "http://admin/internal/postfix/transport/§"),
|
||||
("alias", "url", "http://admin/internal/postfix/alias/§"),
|
||||
("domain", "url", "http://admin/internal/postfix/domain/§"),
|
||||
("mailbox", "url", "http://admin/internal/postfix/mailbox/§"),
|
||||
("senderaccess", "url", "http://admin/internal/postfix/sender/access/§"),
|
||||
("senderlogin", "url", "http://admin/internal/postfix/sender/login/§")
|
||||
("transport", "url", url + "transport/§"),
|
||||
("alias", "url", url + "alias/§"),
|
||||
("domain", "url", url + "domain/§"),
|
||||
("mailbox", "url", url + "mailbox/§"),
|
||||
("senderaccess", "url", url + "sender/access/§"),
|
||||
("senderlogin", "url", url + "sender/login/§")
|
||||
])
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", 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),
|
||||
before=tenacity.before_log(log.getLogger("tenacity.retry"), log.DEBUG),
|
||||
before_sleep=tenacity.before_sleep_log(log.getLogger("tenacity.retry"), log.INFO),
|
||||
after=tenacity.after_log(log.getLogger("tenacity.retry"), log.DEBUG)
|
||||
)
|
||||
def resolve(hostname):
|
||||
logger = log.getLogger("resolve()")
|
||||
logger.info(hostname)
|
||||
return socket.gethostbyname(hostname)
|
||||
|
||||
# Actual startup script
|
||||
os.environ["FRONT_ADDRESS"] = resolve(os.environ.get("FRONT_ADDRESS", "front"))
|
||||
os.environ["HOST_ANTISPAM"] = os.environ.get("HOST_ANTISPAM", "antispam:11332")
|
||||
os.environ["HOST_LMTP"] = os.environ.get("HOST_LMTP", "imap:2525")
|
||||
os.environ["ADMIN_ADDRESS"] = resolve(os.environ.get("ADMIN_ADDRESS", "admin"))
|
||||
os.environ["HOST_ANTISPAM"] = resolve(os.environ.get("HOST_ANTISPAM", "antispam:11332"))
|
||||
os.environ["HOST_LMTP"] = resolve(os.environ.get("HOST_LMTP", "imap:2525"))
|
||||
|
||||
for postfix_file in glob.glob("/conf/*.cf"):
|
||||
convert(postfix_file, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
|
||||
|
43
docs/faq.rst
43
docs/faq.rst
@ -136,6 +136,49 @@ You're mail service will be reachable for IMAP, POP3, SMTP and Webmail at the ad
|
||||
|
||||
*Issue reference:* `742`_, `747`_.
|
||||
|
||||
How to make IPv6 work?
|
||||
``````````````````````
|
||||
|
||||
Docker currently does not expose the IPv6 ports properly, as it does not interface with ``ip6tables``.
|
||||
Lets start with quoting everything that's wrong:
|
||||
|
||||
Unfortunately, initially Docker was not created with IPv6 in mind.
|
||||
It was added later and, while it has come a long way, is still not as usable as one would want.
|
||||
Much discussion is still going on as to how IPv6 should be used in a containerized world;
|
||||
See the various GitHub issues linked below:
|
||||
|
||||
- Giving each container a publicly routable address means all ports (even unexposed / unpublished ports) are suddenly
|
||||
reachable by everyone, if no additional filtering is done
|
||||
(`docker/docker#21614 <https://github.com/docker/docker/issues/21614>`_)
|
||||
- By default, each container gets a random IPv6, making it impossible to do properly do DNS;
|
||||
the alternative is to assign a specific IPv6 address to each container,
|
||||
still an administrative hassle (`docker/docker#13481 <https://github.com/docker/docker/issues/13481>`_)
|
||||
- Published ports won't work on IPv6, unless you have the userland proxy enabled
|
||||
(which, for now, is enabled by default in Docker)
|
||||
- The userland proxy, however, seems to be on its way out
|
||||
(`docker/docker#14856 <https://github.com/docker/docker/issues/14856>`_) and has various issues, like:
|
||||
|
||||
- It can use a lot of RAM (`docker/docker#11185 <https://github.com/docker/docker/issues/11185>`_)
|
||||
- Source IP addresses are rewritten, making it completely unusable for many purposes, e.g. mail servers
|
||||
(`docker/docker#17666 <https://github.com/docker/docker/issues/17666>`_),
|
||||
(`docker/libnetwork#1099 <https://github.com/docker/libnetwork/issues/1099>`_).
|
||||
|
||||
-- `Robbert Klarenbeek <https://github.com/robbertkl>`_ (docker-ipv6nat author)
|
||||
|
||||
So, how to make it work? Well, by using `docker-ipv6nat`_! This nifty container will set up ``ip6tables``,
|
||||
just as Docker would do for IPv4. We know that nat-ing is not advised in IPv6,
|
||||
however exposing all containers to public network neither. The choice is ultimately yous.
|
||||
|
||||
Mailu `setup utility`_ generates a safe IPv6 ULA subnet by default. So when you run the following command,
|
||||
Mailu will start to function on IPv6:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -d --restart=always -v /var/run/docker.sock:/var/run/docker.sock:ro --privileged --net=host robbertkl/ipv6nat
|
||||
|
||||
.. _`docker-ipv6nat`: https://github.com/robbertkl/docker-ipv6nat
|
||||
.. _`setup utility`: https://setup.mailu.io
|
||||
|
||||
How does Mailu scale up?
|
||||
````````````````````````
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
# Shared layer between rspamd, postfix, dovecot, unbound and nginx
|
||||
RUN pip3 install jinja2
|
||||
# Shared layer between rspamd, postfix, dovecot
|
||||
RUN pip3 install tenacity
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
RUN apk add --no-cache rspamd rspamd-controller rspamd-proxy rspamd-fuzzy ca-certificates curl
|
||||
|
||||
|
@ -1,34 +1,13 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import socket
|
||||
import glob
|
||||
import tenacity
|
||||
import logging as log
|
||||
import sys
|
||||
|
||||
from tenacity import retry
|
||||
from mailustart import resolve, convert
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", 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),
|
||||
before=tenacity.before_log(log.getLogger("tenacity.retry"), log.DEBUG),
|
||||
before_sleep=tenacity.before_sleep_log(log.getLogger("tenacity.retry"), log.INFO),
|
||||
after=tenacity.after_log(log.getLogger("tenacity.retry"), log.DEBUG)
|
||||
)
|
||||
def resolve(hostname):
|
||||
logger = log.getLogger("resolve()")
|
||||
logger.info(hostname)
|
||||
return socket.gethostbyname(hostname)
|
||||
|
||||
# Actual startup script
|
||||
os.environ["FRONT_ADDRESS"] = resolve(os.environ.get("FRONT_ADDRESS", "front"))
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
FROM alpine:3.8
|
||||
# python3 shared with most images
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip \
|
||||
python3 py3-pip git \
|
||||
&& pip3 install --upgrade pip
|
||||
# Shared layer between rspamd, postfix, dovecot, unbound and nginx
|
||||
RUN pip3 install jinja2
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
# Image specific layers under this line
|
||||
RUN apk add --no-cache unbound curl bind-tools \
|
||||
&& curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache \
|
||||
|
@ -1,17 +1,12 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import convert
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", src, dst)
|
||||
open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||
|
||||
convert("/unbound.conf", "/etc/unbound/unbound.conf")
|
||||
|
||||
os.execv("/usr/sbin/unbound", ["-c /etc/unbound/unbound.conf"])
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Please read the documentation before attempting any change.
|
||||
# Generated for {{ flavor }} flavor
|
||||
|
||||
version: '3.6'
|
||||
version: '2.2'
|
||||
|
||||
services:
|
||||
|
||||
@ -160,8 +160,14 @@ services:
|
||||
|
||||
networks:
|
||||
default:
|
||||
{% if ipv6_enabled %}
|
||||
enable_ipv6: true
|
||||
{% endif %}
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: {{ subnet }}
|
||||
{% if ipv6_enabled %}
|
||||
- subnet: {{ subnet6 }}
|
||||
{% endif %}
|
||||
|
@ -27,6 +27,9 @@ SECRET_KEY={{ secret(16) }}
|
||||
|
||||
# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
|
||||
SUBNET={{ subnet }}
|
||||
{% if ipv6_enabled %}
|
||||
SUBNET6={{ subnet6 }}
|
||||
{% endif %}
|
||||
|
||||
# Main mail domain
|
||||
DOMAIN={{ domain }}
|
||||
|
@ -9,6 +9,7 @@ import string
|
||||
import random
|
||||
import ipaddress
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
|
||||
version = os.getenv("this_version", "master")
|
||||
@ -33,6 +34,17 @@ def secret(length=16):
|
||||
for _ in range(length)
|
||||
)
|
||||
|
||||
#Original copied from https://github.com/andrewlkho/ulagen
|
||||
def random_ipv6_subnet():
|
||||
eui64 = uuid.getnode() >> 24 << 48 | 0xfffe000000 | uuid.getnode() & 0xffffff
|
||||
eui64_canon = "-".join([format(eui64, "02X")[i:i+2] for i in range(0, 18, 2)])
|
||||
|
||||
h = hashlib.sha1()
|
||||
h.update((eui64_canon + str(time.time() - time.mktime((1900, 1, 1, 0, 0, 0, 0, 1, -1)))).encode('utf-8'))
|
||||
globalid = h.hexdigest()[0:10]
|
||||
|
||||
prefix = ":".join(("fd" + globalid[0:2], globalid[2:6], globalid[6:10]))
|
||||
return prefix
|
||||
|
||||
def build_app(path):
|
||||
|
||||
@ -69,8 +81,9 @@ def build_app(path):
|
||||
@root_bp.route("/submit_flavor", methods=["POST"])
|
||||
def submit_flavor():
|
||||
data = flask.request.form.copy()
|
||||
subnet6 = random_ipv6_subnet()
|
||||
steps = sorted(os.listdir(os.path.join(path, "templates", "steps", data["flavor"])))
|
||||
return flask.render_template('wizard.html', flavor=data["flavor"], steps=steps)
|
||||
return flask.render_template('wizard.html', flavor=data["flavor"], steps=steps, subnet6=subnet6)
|
||||
|
||||
@prefix_bp.route("/submit", methods=["POST"])
|
||||
@root_bp.route("/submit", methods=["POST"])
|
||||
|
@ -86,3 +86,16 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
if ($('#enable_ipv6').prop('checked')) {
|
||||
$("#ipv6").show();
|
||||
}
|
||||
$("#enable_ipv6").change(function() {
|
||||
if ($(this).is(":checked")) {
|
||||
$("#ipv6").show();
|
||||
} else {
|
||||
$("#ipv6").hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -18,13 +18,26 @@ avoid generic all-interfaces addresses like <code>0.0.0.0</code> or <code>::</co
|
||||
<!-- Validates IPv4 address -->
|
||||
<input class="form-control" type="text" name="bind4" value="127.0.0.1"
|
||||
pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
|
||||
<label>Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)</label>
|
||||
<input class="form-control" type="text" name="subnet" required pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$"
|
||||
value="192.168.203.0/24">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" name="ipv6_enabled" value="true" id="enable_ipv6">
|
||||
Enable IPv6
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ipv6" style="display: none">
|
||||
<p><span class="label label-danger">Read this:</span> Docker currently does not expose the IPv6 ports properly, as it does not interface with <code>ip6tables</code>. Be sure to read our <a href="https://mailu.io/{{ version }}/faq.html#how-to-make-ipv6-work">FAQ section</a>!</p>
|
||||
<label>IPv6 listen address</label>
|
||||
<!-- Validates IPv6 address -->
|
||||
<input class="form-control" type="text" name="bind6" value="::1"
|
||||
pattern="^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$">
|
||||
<label>Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)</label>
|
||||
<input class="form-control" type="text" name="subnet6" required value="{{ subnet6 }}:beef::/64">
|
||||
</div>
|
||||
|
||||
<p>The unbound resolver enables Mailu to do DNSsec verification, DNS root lookups and caching. This also helps the antispam service not to get blocked by the public or ISP DNS servers.</p>
|
||||
@ -34,12 +47,6 @@ avoid generic all-interfaces addresses like <code>0.0.0.0</code> or <code>::</co
|
||||
Enable unbound resolver
|
||||
</label>
|
||||
</div>
|
||||
<br><br>
|
||||
<div class="form-group">
|
||||
<label>Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)</label>
|
||||
<input class="form-control" type="text" name="subnet" required pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$"
|
||||
value="192.168.203.0/24">
|
||||
</div>
|
||||
|
||||
<p>You server will be available under a main hostname but may expose multiple public
|
||||
hostnames. Every e-mail domain that points to this server must have one of the
|
||||
|
@ -1,7 +1,7 @@
|
||||
FROM php:7.2-apache
|
||||
#Shared layer between rainloop and roundcube
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3 curl \
|
||||
python3 curl python3-pip git \
|
||||
&& rm -rf /var/lib/apt/lists \
|
||||
&& echo "ServerSignature Off" >> /etc/apache2/apache2.conf
|
||||
|
||||
@ -21,6 +21,8 @@ RUN apt-get update && apt-get install -y \
|
||||
&& chown -R www-data: * \
|
||||
&& apt-get purge -y unzip \
|
||||
&& rm -rf /var/lib/apt/lists
|
||||
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
|
||||
COPY include.php /var/www/html/include.php
|
||||
COPY php.ini /php.ini
|
||||
|
@ -1,21 +1,16 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import shutil
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import resolve, convert
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", src, dst)
|
||||
open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||
|
||||
# Actual startup script
|
||||
os.environ["FRONT_ADDRESS"] = os.environ.get("FRONT_ADDRESS", "front")
|
||||
os.environ["IMAP_ADDRESS"] = os.environ.get("IMAP_ADDRESS", "imap")
|
||||
os.environ["FRONT_ADDRESS"] = resolve(os.environ.get("FRONT_ADDRESS", "front"))
|
||||
os.environ["IMAP_ADDRESS"] = resolve(os.environ.get("IMAP_ADDRESS", "imap"))
|
||||
|
||||
os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT"))*0.66/1048576))
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
FROM php:7.2-apache
|
||||
#Shared layer between rainloop and roundcube
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3 curl \
|
||||
python3 curl python3-pip git \
|
||||
&& rm -rf /var/lib/apt/lists \
|
||||
&& echo "ServerSignature Off" >> /etc/apache2/apache2.conf
|
||||
|
||||
@ -23,6 +23,8 @@ RUN apt-get update && apt-get install -y \
|
||||
&& chown -R www-data: logs temp \
|
||||
&& rm -rf /var/lib/apt/lists
|
||||
|
||||
RUN pip3 install git+https://github.com/usrpro/MailuStart.git#egg=mailustart
|
||||
|
||||
COPY php.ini /php.ini
|
||||
COPY config.inc.php /var/www/html/config/
|
||||
COPY start.py /start.py
|
||||
|
@ -1,17 +1,12 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import jinja2
|
||||
import logging as log
|
||||
import sys
|
||||
from mailustart import convert
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
def convert(src, dst):
|
||||
logger = log.getLogger("convert()")
|
||||
logger.debug("Source: %s, Destination: %s", src, dst)
|
||||
open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||
|
||||
os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT"))*0.66/1048576))
|
||||
|
||||
convert("/php.ini", "/usr/local/etc/php/conf.d/roundcube.ini")
|
||||
|
Loading…
x
Reference in New Issue
Block a user