Merge pull request #668 from usrpro/feat-setup

Feat setup
master
mergify[bot] 6 years ago committed by GitHub
commit d167c8ca7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,8 +10,10 @@ RUN apk add --no-cache git \
COPY server.py ./server.py COPY server.py ./server.py
COPY setup.py ./setup.py COPY setup.py ./setup.py
COPY main.py ./main.py COPY main.py ./main.py
COPY flavors /data/master/flavors
COPY templates /data/master/templates
RUN python setup.py https://github.com/mailu/mailu /data #RUN python setup.py https://github.com/mailu/mailu /data
EXPOSE 80/tcp EXPOSE 80/tcp

@ -9,5 +9,6 @@ services:
setup: setup:
image: mailu/setup image: mailu/setup
ports: ports:
- "80:80" - "8000:80"
build: .

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

@ -1,5 +1,7 @@
# Mailu main configuration file # Mailu main configuration file
# #
# Generated for {{ flavor }} flavor
#
# This file is autogenerated by the configuration management wizard. # This file is autogenerated by the configuration management wizard.
# For a detailed list of configuration variables, see the documentation at # For a detailed list of configuration variables, see the documentation at
# https://mailu.io # https://mailu.io
@ -9,60 +11,118 @@
################################### ###################################
# Set this to the path where Mailu data and configuration is stored # Set this to the path where Mailu data and configuration is stored
ROOT=/mailu # This variable is now set directly in `docker-compose.yml by the setup utility
# ROOT={{ root }}
# Mailu version to run (1.0, 1.1, etc. or master)
#VERSION={{ version }}
# Set to a randomly generated 16 bytes string # Set to a randomly generated 16 bytes string
SECRET_KEY={{ secret(16) }} SECRET_KEY={{ secret(16) }}
# Address where listening ports should bind # Address where listening ports should bind
{% if bind4 %}PUBLIC_IPV4={{ bind4 }}{% endif %} # This variables are now set directly in `docker-compose.yml by the setup utility
{% if bind6 %}PUBLIC_IPV6={{ bind6 }}{% endif %} # PUBLIC_IPV4= {{ bind4 }} (default: 127.0.0.1)
# PUBLIC_IPV6= {{ bind6 }} (default: ::1)
# Mail address of the postmaster # Main mail domain
POSTMASTER={{ postmaster }} DOMAIN={{ domain }}
# Hostnames for this server, separated with comas # Hostnames for this server, separated with comas
HOSTNAMES={{ hostnames }} HOSTNAMES={{ hostnames }}
# Postmaster local part (will append the main mail domain)
POSTMASTER={{ postmaster }}
# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
TLS_FLAVOR={{ tls_flavor }}
# Authentication rate limit (per source IP address) # Authentication rate limit (per source IP address)
AUTH_RATELIMIT={{ auth_ratelimit }} {% if auth_ratelimit_pm > '0' and auth_ratelimit_ph > '0' %}
AUTH_RATELIMIT={{ auth_ratelimit_pm }}/minute;{{ auth_ratelimit_ph }}/hour
{% endif %}
# Opt-out of statistics, replace with "True" to opt out # Opt-out of statistics, replace with "True" to opt out
DISABLE_STATISTICS={{ disable_statistics }} DISABLE_STATISTICS={{ disable_statistics or 'False' }}
################################### ###################################
# Server behavior # Optional features
###################################
# Expose the admin interface (value: true, false)
ADMIN={{ admin_enabled or 'false' }}
# Choose which webmail to run if any (values: roundcube, rainloop, none)
WEBMAIL={{ webmail_type }}
# Dav server implementation (value: radicale, none)
WEBDAV={{ webdav_enabled or 'none' }}
# Antivirus solution (value: clamav, none)
#ANTIVIRUS={{ antivirus_enabled or 'none' }}
#Antispam solution
ANTISPAM={{ antispam_enabled or 'none'}}
###################################
# Mail settings
################################### ###################################
# Message size limit in bytes # Message size limit in bytes
# Default: accept messages up to 50MB # Default: accept messages up to 50MB
MESSAGE_SIZE_LIMIT={{ message_size_limit }} MESSAGE_SIZE_LIMIT={{ message_size_limit or '50000000' }}
# Networks granted relay permissions, make sure that you include your Docker # Networks granted relay permissions, make sure that you include your Docker
# internal network (default to 172.17.0.0/16) # internal network (default to 172.17.0.0/16)
RELAYNETS={{ relaynets }} RELAYNETS={{ relaynets or '172.17.0.0/16' }}
# Will relay all outgoing mails if configured # Will relay all outgoing mails if configured
RELAYHOST={{ relayhost }} RELAYHOST={{ relayhost }}
# Fetchmail delay # Fetchmail delay
FETCHMAIL_DELAY={{ fetchmail_delay }} FETCHMAIL_DELAY={{ fetchmail_delay or '600' }}
# Recipient delimiter, character used to delimiter localpart from custom address part # Recipient delimiter, character used to delimiter localpart from custom address part
RECIPIENT_DELIMITER={{ recipient_delimiter }} RECIPIENT_DELIMITER={{ recipient_delimiter or '+' }}
{% if dmarc_rua or dmarc_ruf %}
# DMARC rua and ruf email # DMARC rua and ruf email
{% if dmarc_rua %}DMARC_RUA={{ dmarc_rua }}{% endif %} DMARC_RUA={{ dmarc_rua or 'admin' }}
{% if dmarc_ruf %}DMARC_RUF={{ dmarc_ruf }}{% endif %} DMARC_RUF={{ dmarc_ruf or 'admin' }}
{% endif %}
{% if welcome_enabled %} {% if welcome_enabled %}
# Welcome email, enable and set a topic and body if you wish to send welcome # Welcome email, enable and set a topic and body if you wish to send welcome
# emails to all users. # emails to all users.
WELCOME={{ welcome_enable }} WELCOME={{ welcome_enable or 'false' }}
WELCOME_SUBJECT={{ welcome_subject }} WELCOME_SUBJECT={{ welcome_subject or 'Welcome to your new email account' }}
WELCOME_BODY={{ welcome_body }} WELCOME_BODY={{ welcome_body or 'Welcome to your new email account, if you can read this, then it is configured properly!' }}
{% endif %}
# Maildir Compression
# choose compression-method, default: none (value: bz2, gz)
COMPRESSION={{ compression }}
# change compression-level, default: 6 (value: 1-9)
COMPRESSION_LEVEL={{ compression_level }}
###################################
# Web settings
###################################
# Path to the admin interface if enabled
WEB_ADMIN={{ admin_path }}
# Path to the webmail if enabled
WEB_WEBMAIL={{ webmail_path }}
# Website name
SITENAME={{ site_name }}
# Linked Website URL
WEBSITE={{ website }}
{% 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 %} {% endif %}
{% if domain_registration %} {% if domain_registration %}
@ -70,39 +130,28 @@ WELCOME_BODY={{ welcome_body }}
DOMAIN_REGISTRATION=true DOMAIN_REGISTRATION=true
{% endif %} {% 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 # Advanced settings
################################### ###################################
{% if password_scheme %} # Log driver for front service. Possible values:
# Specific password storage scheme # json-file (default)
PASSWORD_SCHEME={{ password_scheme }} # journald (On systemd platforms, useful for Fail2Ban integration)
{% endif %} # syslog (Non systemd platforms, Fail2Ban integration. Disables `docker-compose log` for front!)
LOG_DRIVER={{ log_driver or 'json-file' }}
# Docker-compose project name, this will prepended to containers names.
COMPOSE_PROJECT_NAME={{ compose_project_name or 'mailu' }}
# Default password scheme used for newly created accounts and changed passwords
# (value: BLF-CRYPT, SHA512-CRYPT, SHA256-CRYPT, MD5-CRYPT, CRYPT)
PASSWORD_SCHEME={{ password_scheme or 'BLF-CRYPT' }}
# Header to take the real ip from # Header to take the real ip from
REAL_IP_HEADER={{ real_ip_header }} REAL_IP_HEADER={{ real_ip_header }}
# IPs for nginx set_real_ip_from (CIDR list separated by commas) # IPs for nginx set_real_ip_from (CIDR list separated by commas)
REAL_IP_FROM={{ real_ip_from }} REAL_IP_FROM={{ real_ip_from }}
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT={{ reject_unlisted_recipient }}

@ -4,15 +4,15 @@
<p>Docker Compose expects a project file, named <code>docker-compose.yml</code> <p>Docker Compose expects a project file, named <code>docker-compose.yml</code>
in a project directory. First create your project directory.</p> in a project directory. First create your project directory.</p>
<pre><code>mkdir /mailu <pre><code>mkdir {{ root }}
</pre></code> </pre></code>
<p>Then download the project file. A side configuration file makes it easier <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> to read and check the configuration variables generated by the wizard.</p>
<pre><code>cd /mailu <pre><code>cd {{ root }}
wget {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }} curl {{ url_for('.file', uid=uid, filepath='docker-compose.yml', _external=True) }} > docker-compose.yml
wget {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }} curl {{ url_for('.file', uid=uid, filepath='mailu.env', _external=True) }} > mailu.env
</pre></code> </pre></code>
{% endcall %} {% endcall %}
@ -30,7 +30,22 @@ files before going any further.</p>
<p>To start your compose project, simply run the Docker Compose <code>up</code> <p>To start your compose project, simply run the Docker Compose <code>up</code>
command.</p> command.</p>
<pre><code>cd /mailu <pre><code>cd {{ root }}
docker-compose up -d docker-compose up -d
</pre></code> </pre></code>
Before you can use Mailu, you must create the primary administrator user account. This should be {{ postmaster }}@{{ domain }}. Use the following command, changing PASSWORD to your liking:
<pre><code>docker-compose exec admin python manage.py admin {{ postmaster }} {{ domain }} PASSWORD
</pre></code>
<p>Login to the admin interface to change the password for a safe one, at
{% if admin_enabled %}
one of the hostnames
<a href="https://{{ hostnames.split(',')[0] }}{{ admin_path }}">{{ hostnames.split(',')[0] }}{{ admin_path }}</a>.
{% else %}
<a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a> (only directly from the host running docker).
{% endif %}
And choose the "Update password" option in the left menu.
</p>
{% endcall %} {% endcall %}

@ -0,0 +1,128 @@
{% set env='mailu.env' %}
# This file is auto-generated by the Mailu configuration wizard.
# Please read the documentation before attempting any change.
# Generated for {{ flavor }} flavor
version: '3.6'
services:
# External dependencies
redis:
image: redis:alpine
restart: always
volumes:
- "{{ root }}/redis:/data"
# Core services
front:
image: mailu/nginx:{{ version }}
env_file: {{ env }}
ports:
{% for port in (80, 443, 25, 465, 587, 110, 995, 143, 993) %}
- target: {{ port }}
published: {{ port }}
mode: overlay
{% endfor %}
volumes:
- "{{ root }}/certs:/certs"
deploy:
replicas: 1
admin:
image: mailu/admin:{{ version }}
env_file: {{ env }}
{% if not admin_enabled %}
ports:
- 127.0.0.1:8080:80
{% endif %}
volumes:
- "{{ root }}/data:/data"
- "{{ root }}/dkim:/dkim"
deploy:
replicas: 1
imap:
image: mailu/dovecot:{{ version }}
env_file: {{ env }}
environment:
# Default to 10.0.1.0/24
- POD_ADDRESS_RANGE={{ subnet }}
volumes:
- "{{ root }}/mail:/mail"
- "{{ root }}/overrides:/overrides"
deploy:
replicas: 1
smtp:
image: mailu/postfix:{{ version }}
env_file: {{ env }}
environment:
- POD_ADDRESS_RANGE={{ subnet }}
volumes:
- "{{ root }}/overrides:/overrides"
deploy:
replicas: 1
# Optional services
{% if antispam_enabled %}
antispam:
image: mailu/rspamd:{{ version }}
env_file: {{ env }}
environment:
- POD_ADDRESS_RANGE={{ subnet }}
volumes:
- "{{ root }}/filter:/var/lib/rspamd"
- "{{ root }}/dkim:/dkim"
- "{{ root }}/overrides/rspamd:/etc/rspamd/override.d"
deploy:
replicas: 1
{% endif %}
{% if antivirus_enabled %}
antivirus:
image: mailu/clamav:{{ version }}
env_file: {{ env }}
volumes:
- "{{ root }}/filter:/data"
deploy:
replicas: 1
{% endif %}
{% if webdav_enabled %}
webdav:
image: mailu/none:{{ version }}
env_file: {{ env }}
volumes:
- "{{ root }}/dav:/data"
deploy:
replicas: 1
{% endif %}
{% if fetchmail_enabled %}
fetchmail:
image: mailu/fetchmail:{{ version }}
env_file: {{ env }}
volumes:
- "{{ root }}/data:/data"
deploy:
replicas: 1
{% endif %}
{% if webmail_type != 'none' %}
webmail:
image: mailu/roundcube:{{ version }}
env_file: {{ env }}
volumes:
- "{{ root }}/webmail:/data"
deploy:
replicas: 1
{% endif %}
networks:
default:
driver: overlay
ipam:
driver: default
config:
- subnet: {{ subnet }}

@ -0,0 +1 @@
../compose/mailu.env

@ -0,0 +1,60 @@
{% import "macros.html" as macros %}
{% call macros.panel("info", "Step 1 - Download your configuration files") %}
<p>Docker Stack expects a project file, named <code>docker-compose.yml</code>
in a project directory. First create your project directory.</p>
<pre><code>mkdir -p /{{ root }}/{redis,certs,data,dkim,mail,overrides/rspamd,filter,dav,webmail}
</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 {{ 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
</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 - Deploy docker stack") %}
<p>To deploy the docker stack use the following commands. For more information about setting up docker swarm nodes read the
<a href="https://docs.docker.com/get-started">docker documentation</a></p>
<pre><code>cd {{ root }}
docker swarm init
docker stack deploy -c docker-compose.yml mailu
</pre></code>
In the docker stack deploy command, mailu is the app name. Feel free to change it.<br/>
In order to display the running container you can use<br/>
<pre><code>docker ps</code></pre>
or
<pre><code>docker stack ps --no-trunc mailu</code></pre>
Command for removing docker stack is
<pre><code>docker stack rm mailu</code></pre>
Before you can use Mailu, you must create the primary administrator user account. This should be {{ postmaster }}@{{ domain }}. Use the following command, changing PASSWORD to your liking:
<pre><code>docker exec $(docker ps | grep admin | cut -d ' ' -f1) python manage.py admin {{ postmaster }} {{ domain }} PASSWORD
</pre></code>
<p>Login to the admin interface to change the password for a safe one, at
{% if admin_enabled %}
one of the hostnames
<a href="https://{{ hostnames.split(',')[0] }}{{ admin_path }}">{{ hostnames.split(',')[0] }}{{ admin_path }}</a>.
{% else %}
<a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a> (only directly from the host running docker).
{% endif %}
And choose the "Update password" option in the left menu.
</p>
{% endcall %}

@ -32,9 +32,11 @@ def secret(length=16):
def build_app(path): def build_app(path):
#Hardcoded master as the only version for test purposes
versions = [ versions = [
version for version in os.listdir(path) # version for version in os.listdir(path)
if os.path.isdir(os.path.join(path, version)) # if os.path.isdir(os.path.join(path, version))
"master"
] ]
app.jinja_env.trim_blocks = True app.jinja_env.trim_blocks = True
@ -63,6 +65,12 @@ def build_app(path):
def wizard(): def wizard():
return flask.render_template('wizard.html') return flask.render_template('wizard.html')
@bp.route("/submit_flavor", methods=["POST"])
def submit_flavor():
data = flask.request.form.copy()
steps = sorted(os.listdir(path + "/" + version + "/templates/steps/" + data["flavor"]))
return flask.render_template('wizard.html', flavor=data["flavor"], steps=steps)
@bp.route("/submit", methods=["POST"]) @bp.route("/submit", methods=["POST"])
def submit(): def submit():
data = flask.request.form.copy() data = flask.request.form.copy()

@ -8,7 +8,7 @@
<h1>Mailu configuration</h1> <h1>Mailu configuration</h1>
<p> <p>
Version Version
<select onchange="window.location.href=this.value;"> <select onchange="window.location.href=this.value;" class="btn btn-primary dropdown-toggle">
{% for available in versions %} {% for available in versions %}
<option value="{{ url_for('{}.wizard'.format(available)) }}" {% if available == version %}selected{% endif %}>{{ available }}</option> <option value="{{ url_for('{}.wizard'.format(available)) }}" {% if available == version %}selected{% endif %}>{{ available }}</option>
{% endfor %} {% endfor %}

@ -9,10 +9,10 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro radio(name, value, emph, text) %} {% macro radio(name, value, emph, text, current) %}
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" name="{{ name }}" value="{{ value }}"> <input type="radio" name="{{ name }}" value="{{ value }}"{% if current == value %} checked="checked"{% endif %}>
{% if emph %} {% if emph %}
<strong>{{ emph }}</strong>, <strong>{{ emph }}</strong>,
{% endif %} {% endif %}

@ -3,31 +3,27 @@
interface, Web email clients (webmails), antispam, antivirus, etc. If you interface, Web email clients (webmails), antispam, antivirus, etc. If you
wish to disable some of these features, you are free to do so.</p> 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 <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 email client. These do add some complexity but provide an easier way of
accessing messages for beginner users.</p> accessing messages for beginner users.</p>
<!-- Switched from radio buttons to dropdown menu in order to remove the checkbox -->
<div class="form-group"> <div class="form-group">
<label>Enable Web email client (and path to the Web email client)</label> <label>Enable Web email client (and path to the Web email client)</label>
<div class="input-group"> <!-- <div class="radio"> -->
<div class="input-group-addon"><input type="checkbox" name="webmail_enabled" checked></div> <!-- {{ macros.radio("webmail_type", "roundcube", "RoundCube", "popular Webmail running on top of PHP") }} -->
<input class="form-control" type="text" name="webmail_path" value="/webmail"> <!-- {{ macros.radio("webmail_type", "rainloop", "Rainloop", "lightweight Webmail based on PHP, no database") }} -->
</div> <!-- </div> -->
<br/>
<select class="btn btn-primary dropdown-toggle" name="webmail_type">
{% for webmailtype in ["none", "roundcube", "rainloop"] %}
<option value="{{ webmailtype }}" >{{ webmailtype }}</option>
{% endfor %}
</select>
<p></p> <p></p>
<div class="radio"> <div class="input-group">
{{ macros.radio("webmail_type", "roundcube", "RoundCube", "popular Webmail running on top of PHP") }} <!-- <div class="input-group-addon"><input type="checkbox" name="webmail_enabled" value="true"></div> -->
{{ macros.radio("webmail_type", "rainloop", "Rainloop", "lightweight Webmail based on PHP, no database") }} <input class="form-control" type="text" name="webmail_path" value="/webmail">
</div> </div>
</div> </div>
@ -38,15 +34,29 @@ also disable the antivirus if required (it does use aroung 1GB of ram).</p>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<label class="form-check-label"> <label class="form-check-label">
<input class="form-check-input" type="checkbox" name="antispam_enabled" checked> <input class="form-check-input" type="checkbox" name="antispam_enabled" value="rspamd" checked>
Enable the filtering service Enable the spam filtering service
</label> </label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<label class="form-check-label"> <label class="form-check-label">
<input class="form-check-input" type="checkbox" name="antivirus_enabled" checked> <input class="form-check-input" type="checkbox" name="antivirus_enabled" value="clamav">
Enable the antivirus service Enable the antivirus service
</label> </label>
</div> </div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="webdav_enabled" value="radicale">
Enable the webdav service
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="fetchmail_enabled" value="true">
Enable fetchmail
</label>
</div>
{% endcall %} {% endcall %}

@ -0,0 +1,39 @@
{% call macros.panel("info", "Step 4 - 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>
<!-- 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]?)$">
</div>
<div class="form-group">
<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]))?$">
</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>
<!-- Validates hostname or list of hostnames -->
<input class="form-control" type="text" name="hostnames" placeholder="my.host.name,other.host.name" multiple required
pattern="^(?:(?:\w+(?:-+\w+)*\.)+[a-z]+)*(?:,(?:(?:\w+(?:-+\w+)*\.)+[a-z]+)\s*)*$">
</div>
{% endcall %}

@ -0,0 +1,78 @@
{% call macros.panel("info", "Step 2 - Initial configuration") %}
<p>Before starting some variables must be set</p>
<div class="form-group">
<label>Root path: </label>
<!-- Validates path -->
<input class="form-control" type="text" name="root" value="/mailu" required pattern="^/[-_A-Za-z0-9]+(/[-_A-Za-z0-9]*)*">
</div>
<p>In the next sections we need to set the postmaster address. This is a combination from the <i>postmaster</i> local part and the <i>main mail domain</i>.
The <i>main mail domain</i> is also used as </i>"server display name"</i>. This is the way the SMTP server identifies himself when connecting to others.
The Postmaster will get an e-mail address &lt;postmaster&gt;@&lt;main_domain&gt;. This address will receive the DMARC "rua" and "ruf" reports.
Or in plain english: if receivers start to classify your mail as spam, this postmaster will be informed.</p>
<div class="form-group">
<label>
Main mail domain and server display name.
</label>
<!-- Validates domain name -->
<input class="form-control" type="text" name="domain" placeholder="e.g. mailu.io"
required pattern="^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$">
</div>
<div class="form-group">
<label>Postmaster local part</label>
<input class="form-control" type="text" name="postmaster" value="admin" required>
</div>
<div class="form-group">
<label>Choose how you wish to handle security (TLS) certificates</label>
<br/>
<select class="btn btn-primary dropdown-toggle" name="tls_flavor">
{% for tlsflavor in ["letsencrypt", "cert", "notls", "mail", "mail-letsencrypt"] %}
<option value="{{ tlsflavor }}" >{{ tlsflavor }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>Authentication rate limit (per source IP address)</label>
<!-- Validates number input only -->
<p><input class="form-control" style="width: 7%; display: inline;" type="number" name="auth_ratelimit_pm"
value="10" required >/minute;
<input class="form-control" style="width: 7%; display: inline;;" type="number" name="auth_ratelimit_ph"
value="1000" required >/hour</p>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="disable_statistics" value="True">
Opt-out of statistics
</label>
</div>
<div class="form-group">
<label>Website name</label>
<input class="form-control" type="text" name="site_name" value="Mailu" required>
</div>
<div class="form-group">
<label>Linked Website URL</label>
<!-- Validates url with or without https:// -->
<input class="form-control" type="url" name="website" value="https://mailu.io" required
pattern="^(https?://)?([a-zA-Z0-9]([a-zA-ZäöüÄÖÜ0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$">
</div>
<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" value="true"></div>
<input class="form-control" type="text" name="admin_path" value="/admin">
</div>
</div>
{% endcall %}

@ -1,33 +0,0 @@
{% 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 %}

@ -7,10 +7,10 @@ developpers, will mostly cover Compose and Stack, while other flavors are
maintained by specific contributors.</p> maintained by specific contributors.</p>
<div class="radio"> <div class="radio">
{{ macros.radio("flavor", "compose", "Compose", "simply using Docker Compose manager") }} {{ macros.radio("flavor", "compose", "Compose", "simply using Docker Compose manager", flavor) }}
{{ macros.radio("flavor", "stack", "Stack", "using stack deployments in a Swarm cluster") }} {{ macros.radio("flavor", "stack", "Stack", "using stack deployments in a Swarm cluster", flavor) }}
{{ macros.radio("flavor", "rancher", "Rancher", "on top of the Rancher container manager") }} {{ macros.radio("flavor", "rancher", "Rancher", "on top of the Rancher container manager", flavor) }}
{{ macros.radio("flavor", "kubernetes", "Kubernetes", "on top of the Kubernetes container manager") }} {{ macros.radio("flavor", "kubernetes", "Kubernetes", "on top of the Kubernetes container manager", flavor) }}
</div> </div>
{% endcall %} {% endcall %}

@ -1,16 +0,0 @@
{% 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 %}

@ -0,0 +1,62 @@
{% 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>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>
<!-- Switched from radio buttons to dropdown menu in order to remove the checkbox -->
<div class="form-group">
<label>Enable Web email client (and path to the Web email client)</label>
<!-- <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> -->
<br/>
<select class="btn btn-primary dropdown-toggle" name="webmail_type">
{% for webmailtype in ["none", "roundcube", "rainloop"] %}
<option value="{{ webmailtype }}" >{{ webmailtype }}</option>
{% endfor %}
</select>
<p></p>
<div class="input-group">
<!-- <div class="input-group-addon"><input type="checkbox" name="webmail_enabled" value="true"></div> -->
<input class="form-control" type="text" name="webmail_path" value="/webmail">
</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" value="rspamd" checked>
Enable the spam 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" value="clamav">
Enable the antivirus service
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="webdav_enabled" value="radicale">
Enable the webdav service
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="fetchmail_enabled" value="true">
Enable fetchmail
</label>
</div>
{% endcall %}

@ -0,0 +1,21 @@
{% call macros.panel("info", "Step 4 - 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>
<div class="form-group">
<label>Subnet</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]))$">
</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>
<!-- Validates hostname or list of hostnames -->
<input class="form-control" type="text" name="hostnames" placeholder="my.host.name,other.host.name" multiple required
pattern="^(?:(?:\w+(?:-+\w+)*\.)+[a-z]+)*(?:,(?:(?:\w+(?:-+\w+)*\.)+[a-z]+)\s*)*$">
</div>
{% endcall %}

@ -8,12 +8,18 @@
ready when using this wizard. ready when using this wizard.
{% endcall %} {% endcall %}
<form method="post" action="{{ url_for(".submit") }}"> <form method="post" action="{{ url_for(".submit_flavor") }}">
{% include "steps/flavor.html" %} {% include "steps/flavor.html" %}
{% include "steps/expose.html" %} <input class="btn btn-primary" type="submit" value="Next >" style="margin-bottom: 15px">
{% include "steps/services.html" %} </form>
{% include "steps/optional.html" %} {% if flavor %}
<form method="post" action="{{ url_for(".submit") }}">
<input type="hidden" name="flavor" value="{{ flavor }}">
{% include "steps/config.html" %}
{%for file in steps %}
{% include "steps/" + flavor + "/" + file %}
{% endfor %}
<input class="btn btn-primary" type="submit" value="Setup Mailu"> <input class="btn btn-primary" type="submit" value="Setup Mailu">
{% endif %}
</form> </form>
{% endblock %} {% endblock %}

Loading…
Cancel
Save