Rename the config dir to setup

This commit is contained in:
kaiyou
2018-04-22 16:10:25 +02:00
parent 40720fb3ea
commit f5538698d3
17 changed files with 0 additions and 0 deletions

18
setup/Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM python:3-alpine
RUN mkdir -p /app
WORKDIR /app
COPY requirements.txt requirements.txt
RUN apk add --no-cache git \
&& pip install -r requirements.txt
COPY server.py ./server.py
COPY setup.py ./setup.py
COPY main.py ./main.py
RUN python setup.py https://github.com/mailu/mailu /data
EXPOSE 80/tcp
CMD gunicorn -w 4 -b 0.0.0.0:80 -b [::]:80 --access-logfile - --error-logfile - --preload main:app

View File

@@ -0,0 +1,124 @@
{% set env='mailu.env' %}
# This file is auto-generated by the Mailu configuration wizard.
# Please read the documentation before attempting any change.
version: '2'
services:
# External dependencies
redis:
image: redis:alpine
restart: always
volumes:
- "$ROOT/redis:/data"
# Core services
front:
image: mailu/nginx:{{ version }}
restart: always
env_file: {{ env }}
env:
- TLS_FLAVOR={{ tls_flavor or 'letsencrypt' }}
- ADMIN={{ expose_admin or 'no' }}
ports:
{% for port in (80, 443, 25, 465, 587, 110, 995, 143, 993) %}
{% if bind4 %}
- "$PUBLIC_IPV4:{{ port }}:{{ port }}"
{% endif %}
{% if bind6 %}
- "$PUBLIC_IPV6:{{ port }}:{{ port }}"
{% endif %}
{% endfor %}
{% if flavor in ('cert', 'mail') %}
volumes:
- "$ROOT/certs:/certs"
{% endif %}
admin:
image: mailu/admin:{{ version }}
restart: always
env_file: {{ env }}
{% if not expose_admin %}
ports:
- 127.0.0.1:8080:80
{% endif %}
volumes:
- "$ROOT/data:/data"
- "$ROOT/dkim:/dkim"
depends_on:
- redis
imap:
image: mailu/dovecot:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/data:/data"
- "$ROOT/mail:/mail"
- "$ROOT/overrides:/overrides"
depends_on:
- front
smtp:
image: mailu/postfix:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/data:/data"
- "$ROOT/overrides:/overrides"
depends_on:
- front
# Optional services
{% if enable_antispam %}
antispam:
image: mailu/rspamd:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/filter:/var/lib/rspamd"
- "$ROOT/dkim:/dkim"
- "$ROOT/overrides/rspamd:/etc/rspamd/override.d"
depends_on:
- front
{% endif %}
{% if enable_antivirus %}
antivirus:
image: mailu/clamav:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/filter:/data"
{% endif %}
{% if enable_webdav %}
webdav:
image: mailu/radivale:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/dav:/data"
{% endif %}
{% if enable_fetchmail %}
fetchmail:
image: mailu/fetchmail:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/data:/data"
{% endif %}
# Webmail
{% if enable_webmail %}
webmail:
image: mailu/{{ webmail }}:{{ version }}
restart: always
env_file: {{ env }}
volumes:
- "$ROOT/webmail:/data"
depends_on:
- imap
{% endif %}

View File

@@ -0,0 +1,108 @@
# Mailu main configuration file
#
# This file is autogenerated by the configuration management wizard.
# For a detailed list of configuration variables, see the documentation at
# https://mailu.io
###################################
# Common configuration variables
###################################
# Set this to the path where Mailu data and configuration is stored
ROOT=/mailu
# Set to a randomly generated 16 bytes string
SECRET_KEY={{ secret(16) }}
# Address where listening ports should bind
{% if bind4 %}PUBLIC_IPV4={{ bind4 }}{% endif %}
{% if bind6 %}PUBLIC_IPV6={{ bind6 }}{% endif %}
# Mail address of the postmaster
POSTMASTER={{ postmaster }}
# Hostnames for this server, separated with comas
HOSTNAMES={{ hostnames }}
# Authentication rate limit (per source IP address)
AUTH_RATELIMIT={{ auth_ratelimit }}
# Opt-out of statistics, replace with "True" to opt out
DISABLE_STATISTICS={{ disable_statistics }}
###################################
# Server behavior
###################################
# Message size limit in bytes
# Default: accept messages up to 50MB
MESSAGE_SIZE_LIMIT={{ message_size_limit }}
# Networks granted relay permissions, make sure that you include your Docker
# internal network (default to 172.17.0.0/16)
RELAYNETS={{ relaynets }}
# Will relay all outgoing mails if configured
RELAYHOST={{ relayhost }}
# Fetchmail delay
FETCHMAIL_DELAY={{ fetchmail_delay }}
# Recipient delimiter, character used to delimiter localpart from custom address part
RECIPIENT_DELIMITER={{ recipient_delimiter }}
{% if dmarc_rua or dmarc_ruf %}
# DMARC rua and ruf email
{% if dmarc_rua %}DMARC_RUA={{ dmarc_rua }}{% endif %}
{% if dmarc_ruf %}DMARC_RUF={{ dmarc_ruf }}{% endif %}
{% endif %}
{% if welcome_enabled %}
# Welcome email, enable and set a topic and body if you wish to send welcome
# emails to all users.
WELCOME={{ welcome_enable }}
WELCOME_SUBJECT={{ welcome_subject }}
WELCOME_BODY={{ welcome_body }}
{% endif %}
{% if domain_registration %}
# Domain registration (remove to disable)
DOMAIN_REGISTRATION=true
{% endif %}
###################################
# 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
{% if recaptcha_public_key and recaptcha_private_key %}
# Registration reCaptcha settings (warning, this has some privacy impact)
# RECAPTCHA_PUBLIC_KEY={{ recaptcha_public_key }}
# RECAPTCHA_PRIVATE_KEY={{ recaptcha_private_key }}
{% endif %}
###################################
# Advanced settings
###################################
{% if password_scheme %}
# Specific password storage scheme
PASSWORD_SCHEME={{ password_scheme }}
{% endif %}
# Header to take the real ip from
REAL_IP_HEADER={{ real_ip_header }}
# IPs for nginx set_real_ip_from (CIDR list separated by commas)
REAL_IP_FROM={{ real_ip_from }}

View File

@@ -0,0 +1,36 @@
{% import "macros.html" as macros %}
{% call macros.panel("info", "Step 1 - Download your configuration files") %}
<p>Docker Compose expects a project file, named <code>docker-compose.yml</code>
in a project directory. First create your project directory.</p>
<pre><code>mkdir /mailu
</pre></code>
<p>Then download the project file. A side configuration file makes it easier
to read and check the configuration variables generated by the wizard.</p>
<pre><code>cd /mailu
wget {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }}
wget {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }}
</pre></code>
{% endcall %}
{% call macros.panel("info", "Step 2 - Review the configuration") %}
<p>We did not insert any malicious code on purpose in the configurations we
distribute, but your download could have been intercepted, or our wizard
website could have been compromised, so make sure you check the configuration
files before going any further.</p>
<p>When you are done checking them, check them one last time.</p>
{% endcall %}
{% call macros.panel("info", "Step 3 - Start the Compose project") %}
<p>To start your compose project, simply run the Docker Compose <code>up</code>
command.</p>
<pre><code>cd /mailu
docker-compose up -d
</pre></code>
{% endcall %}

4
setup/main.py Normal file
View File

@@ -0,0 +1,4 @@
from server import app, build_app
build_app("/data")

5
setup/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
flask
flask-bootstrap
redis
gitpython
gunicorn

94
setup/server.py Normal file
View File

@@ -0,0 +1,94 @@
import flask
import flask_bootstrap
import redis
import json
import os
import jinja2
import uuid
import string
import random
app = flask.Flask(__name__)
flask_bootstrap.Bootstrap(app)
db = redis.StrictRedis(host='redis', port=6379, db=0)
def render_flavor(flavor, template, data):
return flask.render_template(
os.path.join(flavor, template),
**data
)
@app.add_template_global
def secret(length=16):
charset = string.ascii_uppercase + string.digits
return ''.join(
random.SystemRandom().choice(charset)
for _ in range(length)
)
def build_app(path):
versions = [
version for version in os.listdir(path)
if os.path.isdir(os.path.join(path, version))
]
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
@app.context_processor
def app_context():
return dict(versions=versions)
@app.route("/")
def index():
return flask.redirect(flask.url_for('{}.wizard'.format(versions[-1])))
for version in versions:
bp = flask.Blueprint(version, __name__)
bp.jinja_loader = jinja2.ChoiceLoader([
jinja2.FileSystemLoader(os.path.join(path, version, "templates")),
jinja2.FileSystemLoader(os.path.join(path, version, "flavors"))
])
@bp.context_processor
def bp_context(version=version):
return dict(version=version)
@bp.route("/")
def wizard():
return flask.render_template('wizard.html')
@bp.route("/submit", methods=["POST"])
def submit():
data = flask.request.form.copy()
data['uid'] = str(uuid.uuid4())
db.set(data['uid'], json.dumps(data))
return flask.redirect(flask.url_for('.setup', uid=data['uid']))
@bp.route("/setup/<uid>", 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/<uid>/<filepath>", methods=["GET"])
def file(uid, filepath):
data = json.loads(db.get(uid))
flavor = data.get("flavor", "compose")
return flask.Response(
render_flavor(flavor, filepath, data),
mimetype="application/text"
)
app.register_blueprint(bp, url_prefix="/{}".format(version))
if __name__ == "__main__":
build_app("/tmp/mailutest")
app.run(debug=True)

39
setup/setup.py Normal file
View File

@@ -0,0 +1,39 @@
import git
import tempfile
import argparse
import os
import shutil
import re
VERSION_BRANCH = re.compile("(master|\d+\.\d+)")
def main(upstream, dest, dev=True):
shutil.rmtree(dest, ignore_errors=True)
os.makedirs(dest, exist_ok=True)
with tempfile.TemporaryDirectory() as clone_path:
repo = git.Repo.clone_from(upstream, clone_path)
for branch in repo.refs:
if not branch.name.startswith("origin/"):
continue
name = branch.name[len("origin/"):]
if not VERSION_BRANCH.match(name):
continue
branch.checkout()
config_path = os.path.join(clone_path, "config")
if os.path.exists(config_path):
shutil.copytree(config_path, os.path.join(dest, name))
print("Imported branch {}".format(name))
if dev:
shutil.copytree(".", os.path.join(dest, "dev"))
print("Imported dev")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--dev", action="store_true", help="Copy the local dir in /dev")
parser.add_argument("upstream", help="Path to Mailu git repository")
parser.add_argument("dest", help="Destination directory for data files")
args = parser.parse_args()
main(**vars(args))

22
setup/templates/base.html Normal file
View File

@@ -0,0 +1,22 @@
{% extends "bootstrap/base.html" %}
{% import "macros.html" as macros %}
{% block title %}Mailu setup{% endblock %}
{% block content %}
<div class="container">
<h1>Mailu configuration</h1>
<p>
Version
<select onchange="window.location.href=this.value;">
{% for available in versions %}
<option value="{{ url_for('{}.wizard'.format(available)) }}" {% if available == version %}selected{% endif %}>{{ available }}</option>
{% endfor %}
</select>
</p>
{% block page %}{% endblock %}
</div>
<p></p>
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% macro panel(style, title) %}
<div class="panel panel-{{ style }}">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
{{ caller() }}
</div>
</div>
{% endmacro %}
{% macro radio(name, value, emph, text) %}
<div class="radio">
<label>
<input type="radio" name="{{ name }}" value="{{ value }}">
{% if emph %}
<strong>{{ emph }}</strong>,
{% endif %}
{{ text }}
</label>
</div>
{% endmacro %}

View File

@@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block content %}
<div class="container">
<h1>Mailu configuration - {{ branch }}</h1>
{% call macros.panel("success", "Your configuration was generated") %}
<p>The following steps will guide you towards downloading and using your
configuration files. Keep in mind that you should review every downloaded
file before running anything based on it.</p>
<p>If you encounter issues while setting Mailu up, please review the
documentation first, then check if an issue is open for that specific
problem. If not, you may either use Github to open an issue and detail what
your problem or bug looks like, or join us on Matrix and discuss it
with contributors.</p>
{% endcall %}
{% autoescape false %}
{{ contents }}
{% endautoescape %}
</div>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% call macros.panel("info", "Step 2 - expose Mailu to the world") %}
<p>A mail server must be exposed to the world to receive emails, send emails,
and let users access their mailboxes. Mailu has some flexibility in the way
you expose it to the world.</p>
<p>Among Mailu services, the <em>front</em> server is the one accepting connections,
be it directly from the outside world, through a reverse proxy or in any
complex configuration that you might want to setup. It needs to listen on some
IP addresses in order to expose its public services. You must at least setup
an IPv4 or an IPv6 address if you wish to access Mailu.</p>
<p><span class="label label-warning">Warning</span> You must use specific addresses, please
avoid generic all-interfaces addresses like <code>0.0.0.0</code> or <code>::</code>.</p>
<div class="form-group">
<label>IPv4 listen address</label>
<input class="form-control" type="text" name="ip4" placeholder="1.2.3.4">
</div>
<div class="form-group">
<label>IPv6 listen address</label>
<input class="form-control" type="text" name="ip6" placeholder="2001:be4:1234::1">
</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
hostnames in its <code>MX</code> record. Hostnames must be coma-separated.</p>
<div class="form-group">
<label>Public hostnames</label>
<input class="form-control" type="text" name="hostnames" placeholder="my.host.name,other.host.name" multiple>
</div>
{% endcall %}

View File

@@ -0,0 +1,16 @@
{% call macros.panel("info", "Step 1 - pick a flavor") %}
<p>Mailu comes in multiple "flavors". It was originally
designed to run on top of Docker Compose but now offers multiple options
including Docker Stack, Rancher, Kubernetes.</p>
<p>Please note that "official" support, that is provided by the most active
developpers, will mostly cover Compose and Stack, while other flavors are
maintained by specific contributors.</p>
<div class="radio">
{{ macros.radio("flavor", "compose", "Compose", "simply using Docker Compose manager") }}
{{ macros.radio("flavor", "stack", "Stack", "using stack deployments in a Swarm cluster") }}
{{ macros.radio("flavor", "rancher", "Rancher", "on top of the Rancher container manager") }}
{{ macros.radio("flavor", "kubernetes", "Kubernetes", "on top of the Kubernetes container manager") }}
</div>
{% endcall %}

View File

@@ -0,0 +1,16 @@
{% call macros.panel("info", "Step 4 - enable optional features") %}
<p>Mailu also comes with less common optional features that you might wish
to enable.</p>
<p>The DAV service enables contacts and calendar storage through Mailu,
it is especially userful when synchronizing your desktop and mobile devices.</p>
<div class="form-group">
<label>Enable the DAV service (and path to the DAV service)</label>
<div class="input-group">
<div class="input-group-addon"><input type="checkbox" name="dav_enabled" checked></div>
<input class="form-control" type="text" name="admin_path" value="/webdav">
</div>
</div>
{% endcall %}

View File

@@ -0,0 +1,52 @@
{% call macros.panel("info", "Step 3 - pick some features") %}
<p>Mailu comes with multiple base features, including a specific admin
interface, Web email clients (webmails), antispam, antivirus, etc. If you
wish to disable some of these features, you are free to do so.</p>
<p>The admin interface is the main Mailu-specific bit, it provides tools to
manage your email domains, users, etc.</p>
<div class="form-group">
<label>Enable the admin UI (and path to the admin UI)</label>
<div class="input-group">
<div class="input-group-addon"><input type="checkbox" name="admin_enabled" checked></div>
<input class="form-control" type="text" name="admin_path" value="/admin">
</div>
</div>
<p>Emails will be available through IMAP and POP3. You may also enable a Web
email client. These do add some complexity but provide an easier way of
accessing messages for beginner users.</p>
<div class="form-group">
<label>Enable Web email client (and path to the Web email client)</label>
<div class="input-group">
<div class="input-group-addon"><input type="checkbox" name="webmail_enabled" checked></div>
<input class="form-control" type="text" name="webmail_path" value="/webmail">
</div>
<p></p>
<div class="radio">
{{ macros.radio("webmail_type", "roundcube", "RoundCube", "popular Webmail running on top of PHP") }}
{{ macros.radio("webmail_type", "rainloop", "Rainloop", "lightweight Webmail based on PHP, no database") }}
</div>
</div>
<p>Email filtering is a really important features. You can still disable it, which
will prevent Mailu from doing spam filtering, virus filtering, and from applying
white and blacklists that you may configure in the admin interface. You may
also disable the antivirus if required (it does use aroung 1GB of ram).</p>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="antispam_enabled" checked>
Enable the filtering service
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="antivirus_enabled" checked>
Enable the antivirus service
</label>
</div>
{% endcall %}

View File

@@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block page %}
{% call macros.panel("warning", "Before starting, read the docs!") %}
Mailu is not perfectly documented, but still has a lot of documentation
available at <a href="https://mailu.io">mailu.io</a>. Make sure you read
the appropriate documentation for your setup and have all the requirements
ready when using this wizard.
{% endcall %}
<form method="post" action="{{ url_for(".submit") }}">
{% include "steps/flavor.html" %}
{% include "steps/expose.html" %}
{% include "steps/services.html" %}
{% include "steps/optional.html" %}
<input class="btn btn-primary" type="submit" value="Setup Mailu">
</form>
{% endblock %}

0
setup/test Normal file
View File