diff --git a/.travis.yml b/.travis.yml
index 2ee30837..d5114c0d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,11 @@
-language: python
-python:
- - "3.6"
-install:
- - pip install -r docs/requirements.txt
+sudo: required
+services: docker
+addons:
+ apt:
+ packages:
+ - docker-ce
+env:
+ - VERSION=$TRAVIS_BRANCH
+
script:
- - sphinx-versioning build -b -B 1.5 -r 1.5 -w '^[0-9.]*$' -w master -W '^$' docs/ build/
- - python "docs/conf.py" "build" "$DEPLOY_HOST" "$DEPLOY_USERNAME" "$DEPLOY_PASSWORD" "$DEPLOY_REMOTEDIR"
+- docker-compose -f tests/build.yml -p Mailu build
diff --git a/README.md b/README.md
index ccef2e7f..c4354b28 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-![Logo](docs/assets/logo.png)
+
+
Mailu is a simple yet full-featured mail server as a set of Docker images.
It is free software (both as in free beer and as in free speech), open to
diff --git a/core/admin/mailu/internal/__init__.py b/core/admin/mailu/internal/__init__.py
index 45084fe5..6419ad10 100644
--- a/core/admin/mailu/internal/__init__.py
+++ b/core/admin/mailu/internal/__init__.py
@@ -1,3 +1,5 @@
+from flask_limiter import RateLimitExceeded
+
from mailu import limiter
import socket
@@ -6,6 +8,14 @@ import flask
internal = flask.Blueprint('internal', __name__)
+@internal.app_errorhandler(RateLimitExceeded)
+def rate_limit_handler(e):
+ response = flask.Response()
+ response.headers['Auth-Status'] = 'Authentication rate limit from one source exceeded'
+ response.headers['Auth-Error-Code'] = '451 4.3.2'
+ if int(flask.request.headers['Auth-Login-Attempt']) < 10:
+ response.headers['Auth-Wait'] = '3'
+ return response
@limiter.request_filter
def whitelist_webmail():
diff --git a/core/admin/mailu/ui/forms.py b/core/admin/mailu/ui/forms.py
index c5ce5798..326d721b 100644
--- a/core/admin/mailu/ui/forms.py
+++ b/core/admin/mailu/ui/forms.py
@@ -6,6 +6,7 @@ import flask_login
import flask_wtf
import re
+LOCALPART_REGEX = "^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+$"
class DestinationField(fields.SelectMultipleField):
""" Allow for multiple emails selection from current user choices and
@@ -49,7 +50,7 @@ class DomainForm(flask_wtf.FlaskForm):
max_quota_bytes = fields_.IntegerSliderField(_('Maximum user quota'), default=0)
signup_enabled = fields.BooleanField(_('Enable sign-up'), default=False)
comment = fields.StringField(_('Comment'))
- submit = fields.SubmitField(_('Create'))
+ submit = fields.SubmitField(_('Save'))
class DomainSignupForm(flask_wtf.FlaskForm):
@@ -63,18 +64,18 @@ class DomainSignupForm(flask_wtf.FlaskForm):
class AlternativeForm(flask_wtf.FlaskForm):
name = fields.StringField(_('Alternative name'), [validators.DataRequired()])
- submit = fields.SubmitField(_('Create'))
+ submit = fields.SubmitField(_('Save'))
class RelayForm(flask_wtf.FlaskForm):
name = fields.StringField(_('Relayed domain name'), [validators.DataRequired()])
smtp = fields.StringField(_('Remote host'))
comment = fields.StringField(_('Comment'))
- submit = fields.SubmitField(_('Create'))
+ submit = fields.SubmitField(_('Save'))
class UserForm(flask_wtf.FlaskForm):
- localpart = fields.StringField(_('E-mail'), [validators.DataRequired()])
+ localpart = fields.StringField(_('E-mail'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)])
pw = fields.PasswordField(_('Password'), [validators.DataRequired()])
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
quota_bytes = fields_.IntegerSliderField(_('Quota'), default=1000000000)
@@ -86,7 +87,7 @@ class UserForm(flask_wtf.FlaskForm):
class UserSignupForm(flask_wtf.FlaskForm):
- localpart = fields.StringField(_('Email address'), [validators.DataRequired(), validators.Regexp("^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+$")])
+ localpart = fields.StringField(_('Email address'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)])
pw = fields.PasswordField(_('Password'), [validators.DataRequired()])
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
captcha = flask_wtf.RecaptchaField()
@@ -129,7 +130,7 @@ class TokenForm(flask_wtf.FlaskForm):
ip = fields.StringField(
_('Authorized IP'), [validators.Optional(), validators.IPAddress()]
)
- submit = fields.SubmitField(_('Create'))
+ submit = fields.SubmitField(_('Save'))
class AliasForm(flask_wtf.FlaskForm):
@@ -138,7 +139,7 @@ class AliasForm(flask_wtf.FlaskForm):
_('Use SQL LIKE Syntax (e.g. for catch-all aliases)'))
destination = DestinationField(_('Destination'))
comment = fields.StringField(_('Comment'))
- submit = fields.SubmitField(_('Create'))
+ submit = fields.SubmitField(_('Save'))
class AdminForm(flask_wtf.FlaskForm):
diff --git a/core/admin/mailu/ui/templates/sidebar.html b/core/admin/mailu/ui/templates/sidebar.html
index 7ba86e1f..c3a2ced6 100644
--- a/core/admin/mailu/ui/templates/sidebar.html
+++ b/core/admin/mailu/ui/templates/sidebar.html
@@ -32,7 +32,9 @@
+ {% if current_user.manager_of or current_user.global_admin %}
+ {% endif %}
{% if current_user.global_admin %}
diff --git a/core/dovecot/Dockerfile b/core/dovecot/Dockerfile
index 484ab1d6..b15b83c3 100644
--- a/core/dovecot/Dockerfile
+++ b/core/dovecot/Dockerfile
@@ -1,7 +1,7 @@
-FROM alpine:edge
+FROM alpine:3.7
RUN apk add --no-cache \
- dovecot dovecot-pop3d dovecot-lmtpd dovecot-pigeonhole-plugin rspamd-client \
+ dovecot dovecot-pop3d dovecot-lmtpd dovecot-pigeonhole-plugin dovecot-fts-lucene rspamd-client \
python3 py3-pip \
&& pip3 install jinja2 podop
diff --git a/core/dovecot/conf/dovecot.conf b/core/dovecot/conf/dovecot.conf
index d6aee60c..bd4e2893 100644
--- a/core/dovecot/conf/dovecot.conf
+++ b/core/dovecot/conf/dovecot.conf
@@ -7,6 +7,20 @@ postmaster_address = {{ POSTMASTER }}@{{ DOMAIN }}
hostname = {{ HOSTNAMES.split(",")[0] }}
submission_host = {{ FRONT_ADDRESS }}
+###############
+# Full-text search
+###############
+mail_plugins = $mail_plugins fts fts_lucene
+
+plugin {
+ fts = lucene
+
+ fts_autoindex = yes
+ fts_autoindex_exclude = \Junk
+
+ fts_lucene = whitespace_chars=@.
+}
+
###############
# Mailboxes
###############
@@ -21,7 +35,7 @@ mail_access_groups = mail
maildir_stat_dirs = yes
mailbox_list_index = yes
mail_vsize_bg_after_count = 100
-mail_plugins = $mail_plugins quota quota_clone
+mail_plugins = $mail_plugins quota quota_clone zlib
namespace inbox {
inbox = yes
@@ -37,6 +51,14 @@ plugin {
quota = count:User quota
quota_vsizes = yes
quota_clone_dict = proxy:/tmp/podop.socket:quota
+
+ {% if COMPRESSION in [ 'gz', 'bz2' ] %}
+ zlib_save = {{ COMPRESSION }}
+ {% endif %}
+
+ {% if COMPRESSION_LEVEL %}
+ zlib_save_level = {{ COMPRESSION_LEVEL }}
+ {% endif %}
}
###############
diff --git a/core/dovecot/sieve/report-ham.sieve b/core/dovecot/sieve/report-ham.sieve
index 89962067..1ad8abdf 100644
--- a/core/dovecot/sieve/report-ham.sieve
+++ b/core/dovecot/sieve/report-ham.sieve
@@ -1,3 +1,11 @@
-require "vnd.dovecot.execute";
+require ["vnd.dovecot.execute", "copy", "imapsieve", "environment", "variables"];
+
+if environment :matches "imap.mailbox" "*" {
+ set "mailbox" "${1}";
+}
+
+if string "${mailbox}" "Trash" {
+ stop;
+}
execute :pipe "mailtrain" "ham";
diff --git a/core/nginx/Dockerfile b/core/nginx/Dockerfile
index 3be4b50f..8a6536eb 100644
--- a/core/nginx/Dockerfile
+++ b/core/nginx/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:edge
+FROM alpine:3.7
RUN apk add --no-cache nginx nginx-mod-mail python py-jinja2 certbot openssl
diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf
index 8b3d9be1..8fcda1c3 100644
--- a/core/nginx/conf/nginx.conf
+++ b/core/nginx/conf/nginx.conf
@@ -84,15 +84,17 @@ http {
# Actual logic
{% if WEBMAIL != 'none' %}
+ {% if WEB_WEBMAIL != '/' %}
location / {
return 301 {{ WEB_WEBMAIL }};
}
+ {% endif %}
location {{ WEB_WEBMAIL }} {
rewrite ^({{ WEB_WEBMAIL }})$ $1/ permanent;
rewrite ^{{ WEB_WEBMAIL }}/(.*) /$1 break;
include /etc/nginx/proxy.conf;
- client_max_body_size 30M;
+ client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
proxy_pass http://$webmail;
}
{% endif %}
diff --git a/core/postfix/Dockerfile b/core/postfix/Dockerfile
index 81ffc95b..e7501a54 100644
--- a/core/postfix/Dockerfile
+++ b/core/postfix/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine
+FROM alpine:3.7
RUN apk add --no-cache postfix postfix-pcre rsyslog \
python3 py3-pip \
diff --git a/docs/assets/horizontal.png b/docs/assets/horizontal.png
new file mode 100644
index 00000000..431874b4
Binary files /dev/null and b/docs/assets/horizontal.png differ
diff --git a/docs/assets/horizontalv2.png b/docs/assets/horizontalv2.png
new file mode 100644
index 00000000..85e13970
Binary files /dev/null and b/docs/assets/horizontalv2.png differ
diff --git a/docs/assets/logomark.png b/docs/assets/logomark.png
new file mode 100644
index 00000000..5921625b
Binary files /dev/null and b/docs/assets/logomark.png differ
diff --git a/docs/assets/logomarkv2.png b/docs/assets/logomarkv2.png
new file mode 100644
index 00000000..7d0a904e
Binary files /dev/null and b/docs/assets/logomarkv2.png differ
diff --git a/docs/assets/vertical.png b/docs/assets/vertical.png
new file mode 100644
index 00000000..f870a03c
Binary files /dev/null and b/docs/assets/vertical.png differ
diff --git a/docs/compose/.env b/docs/compose/.env
index 06038bc8..9477448a 100644
--- a/docs/compose/.env
+++ b/docs/compose/.env
@@ -87,6 +87,12 @@ WELCOME=false
WELCOME_SUBJECT=Welcome to your new email account
WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
+# Maildir Compression
+# choose compression-method, default: none (value: bz2, gz)
+COMPRESSION=
+# change compression-level, default: 6 (value: 1-9)
+COMPRESSION_LEVEL=
+
###################################
# Web settings
###################################
diff --git a/docs/compose/setup.rst b/docs/compose/setup.rst
index 64e2fa22..8759e2f1 100644
--- a/docs/compose/setup.rst
+++ b/docs/compose/setup.rst
@@ -92,7 +92,7 @@ setting. The configuration option must be one of the following:
- ``none`` disables antivirus checks;
- ``clamav`` is the default values, the popular ClamAV antivirus is enabled.
-Make sure that you have at least 1GB or memory for ClamAV to load its signature
+Make sure that you have at least 1GB of memory for ClamAV to load its signature
database.
If you run Mailu behind a reverse proxy you can use ``REAL_IP_HEADER`` and
diff --git a/docs/index.rst b/docs/index.rst
index 0920bb96..5219145f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -55,7 +55,7 @@ the version of Mailu that you are running.
configuration
compose/requirements
compose/setup
- kubernetes/index
+ kubernetes/stable/index
dns
reverse
diff --git a/docs/kubernetes/1.6/README.md b/docs/kubernetes/1.6/README.md
new file mode 100644
index 00000000..c0dd935b
--- /dev/null
+++ b/docs/kubernetes/1.6/README.md
@@ -0,0 +1,157 @@
+# Install Mailu master on kubernetes
+
+## Prequisites
+
+### Structure
+
+There's chosen to have a double NGINX stack for Mailu, this way the main ingress can still be used to access other websites/domains on your cluster. This is the current structure:
+
+- `NGINX Ingress controller`: Listens to the nodes ports 80 & 443 and directly forwards all TCP traffic on the E-amail ports (993,143,25,587,...). This is because this `DaemonSet` already consumes ports 80 & 443 and uses `hostNetwork: true`
+- `Cert manager`: Creates automatic Lets Encrypt certificates based on an `Ingress`-objects domain name.
+- `Mailu NGINX Front container`: This container receives all the mail traffic forwarded from the ingress controller. The web traffic is also forwarded based on an ingress
+- `Mailu components`: All Mailu components are split into separate files to make them more
+
+### What you need
+- A working Kubernetes cluster (tested with 1.10.5)
+- A working [cert-manager](https://github.com/jetstack/cert-manager) installation
+- A working nginx-ingress controller needed for the lets-encrypt certificates. You can find those files in the `nginx` subfolder
+
+#### Cert manager
+
+The `Cert-manager` is quite easy to deploy using Helm when reading the [docs](https://cert-manager.readthedocs.io/en/latest/getting-started/2-installing.html).
+After booting the `Cert-manager` you'll need a `ClusterIssuer` which takes care of all required certificates through `Ingress` items. An example:
+
+```yaml
+apiVersion: certmanager.k8s.io/v1alpha1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-prod
+spec:
+ acme:
+ email: something@example.com
+ http01: {}
+ privateKeySecretRef:
+ key: ""
+ name: letsencrypt-stage
+ server: https://acme-v02.api.letsencrypt.org/directory
+```
+
+## Deploying Mailu
+
+All manifests can be found in the `mailu` subdirectory. All commands below need to be run from this subdirectory
+
+### Personalization
+- All services run in the same namespace, currently `mailu-mailserver`. So if you want to use a different one, change the `namespace` value in **every** file
+- Check the `storage-class` field in the `pvc.yaml` file, you can also change the sizes to your liking. Note that you need `RWX` (read-write-many) and `RWO` (read-write-once) storageclasses.
+- Check the `configmap.yaml` and adapt it to your needs. Be sure to check the kubernetes DNS values at the end (if you use a different namespace)
+- Check the `ingress-ssl.yaml` and change it to the domain you want (this is for the kubernetes ingress controller, it will forward to `mailu/nginx` a.k.a. the `front` pod)
+
+## Installation
+First run the command to start Mailu:
+
+```bash
+kubectl create -f rbac.yaml
+kubectl create -f configmap.yaml
+kubectl create -f pvc.yaml
+kubectl create -f ingress-ssl.yaml
+kubectl create -f redis.yaml
+kubectl create -f front.yaml
+kubectl create -f webmail.yaml
+kubectl create -f imap.yaml
+kubectl create -f security.yaml
+kubectl create -f smtp.yaml
+kubectl create -f fetchmail.yaml
+kubectl create -f admin.yaml
+kubectl create -f webdav.yaml
+```
+
+## Create the first admin account
+
+When the cluster is online you need to create you master user to access `https://mail.example.com/admin`.
+Enter the main `admin` pod to create the root account:
+
+```bash
+kubectl -n mailu-mailserver get po
+kubectl -n mailu-mailserver exec -it mailu-admin-.... /bin/sh
+```
+
+And in the pod run the following command. The command uses following entries:
+- `admin` Make it an admin user
+- `root` The first part of the e-mail adres (ROOT@example.com)
+- `example.com` the domain appendix
+- `password` the chosen password for the user
+
+```bash
+python manage.py admin root example.com password
+```
+
+Now you should be able to login on the mail account: `https://mail.example.com/admin`
+
+## Adaptations
+
+### Postfix
+I noticed you need an override for the `postfix` server in order to be able to send mail. I noticed Google wasn't able to deliver mail to my account and it had to do with the `smtpd_authorized_xclient_hosts` value in the config file. The config can be read [here](https://github.com/hacor/Mailu/blob/master/core/postfix/conf/main.cf#L35) and is pointing to a single IP of the service. But the requests come from the host IPs (the NGINX Ingress proxy) and they don't use the service specific IP.
+
+Enter the `postfix` pod:
+
+```bash
+kubectl -n mailu-mailserver get po
+kubectl -n mailu-mailserver exec -it mailu-smtp-.... /bin/sh
+```
+
+Now you're in the pod, create an override file like so:
+
+```bash
+vi /overrides/postfix.cf
+```
+
+And give it the following contents, off course replacing `10.2.0.0/16` with the CIDR of your pod range. This way the NGINX pods can also restart and your mail server will still operate
+
+```bash
+not_needed = true
+smtpd_authorized_xclient_hosts = 10.2.0.0/16
+```
+
+The first line seems stupid, but is needed because its pasted after a #, so from the second line we're really in action.
+Save and close the file and exit. Now you need to delete the pod in order to recreate the config file.
+
+```bash
+kubectl -n mailu-mailserver delete po/mailu-smtp-....
+```
+
+### Dovecot
+- If you are using Dovecot on a shared file system (Glusterfs, NFS,...), you need to create a special override otherwise a lot of indexing errors will occur on your Dovecot pod.
+- I also higher the number of max connections per IP. Now it's limited to 10.
+Enter the dovecot pod:
+
+```bash
+kubectl -n mailu-mailserver get po
+kubectl -n mailu-mailserver exec -it mailu-imap-.... /bin/sh
+```
+
+Create the file `/overrides/dovecot.conf`
+
+```bash
+vi /overrides/dovecot.conf
+```
+
+And enter following contents:
+```bash
+mail_nfs_index = yes
+mail_nfs_storage = yes
+mail_fsync = always
+mmap_disable = yes
+mail_max_userip_connections=100
+```
+
+Save and close the file and delete the imap pod to get it recreated.
+
+```bash
+kubectl -n mailu-mailserver delete po/mailu-imap-....
+```
+
+Wait for the pod to recreate and you're online!
+Happy mailing!
+
+Wait for the pod to recreate and you're online!
+Happy mailing!
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/admin.yaml b/docs/kubernetes/1.6/mailu/admin.yaml
new file mode 100644
index 00000000..b36760a2
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/admin.yaml
@@ -0,0 +1,64 @@
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-admin
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-admin
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: admin
+ image: mailu/admin:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ volumeMounts:
+ - name: maildata
+ mountPath: /data
+ subPath: maildata
+ - name: maildata
+ mountPath: /dkim
+ subPath: dkim
+ ports:
+ - name: http
+ containerPort: 80
+ protocol: TCP
+ resources:
+ requests:
+ memory: 500Mi
+ cpu: 500m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: admin
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-admin
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-admin
+ role: mail
+ tier: backend
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/configmap.yaml b/docs/kubernetes/1.6/mailu/configmap.yaml
new file mode 100644
index 00000000..9ebce8b1
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/configmap.yaml
@@ -0,0 +1,153 @@
+ apiVersion: v1
+ kind: ConfigMap
+ metadata:
+ name: mailu-config
+ namespace: mailu-mailserver
+ data:
+ # Mailu main configuration file
+ #
+ # Most configuration variables can be modified through the Web interface,
+ # these few settings must however be configured before starting the mail
+ # server and require a restart upon change.
+
+ ###################################
+ # Common configuration variables
+ ###################################
+
+ # Set this to the path where Mailu data and configuration is stored
+ ROOT: "/mailu"
+
+ # Mailu version to run (1.0, 1.1, etc. or master)
+ VERSION: "master"
+
+ # Set to a randomly generated 16 bytes string
+ SECRET_KEY: "YourKeyHere"
+
+ # Address where listening ports should bind
+ BIND_ADDRESS4: "127.0.0.1"
+ #BIND_ADDRESS6: "::1"
+
+ # Main mail domain
+ DOMAIN: "example.com"
+
+ # Hostnames for this server, separated with comas
+ HOSTNAMES: "mail.example.com"
+
+ # Postmaster local part (will append the main mail domain)
+ POSTMASTER: "admin"
+
+ # Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
+ TLS_FLAVOR: "cert"
+
+ # Authentication rate limit (per source IP address)
+ AUTH_RATELIMIT: "10/minute;1000/hour"
+
+ # Opt-out of statistics, replace with "True" to opt out
+ DISABLE_STATISTICS: "False"
+
+ ###################################
+ # Optional features
+ ###################################
+
+ # Expose the admin interface (value: true, false)
+ ADMIN: "true"
+ # Run the admin interface in debug mode
+ #DEBUG: "True"
+
+ # Choose which webmail to run if any (values: roundcube, rainloop, none)
+ WEBMAIL: "roundcube"
+
+ # Dav server implementation (value: radicale, none)
+ WEBDAV: "radicale"
+
+ # Antivirus solution (value: clamav, none)
+ ANTIVIRUS: "clamav"
+
+ ###################################
+ # Mail settings
+ ###################################
+
+ # Message size limit in bytes
+ # Default: accept messages up to 50MB
+ MESSAGE_SIZE_LIMIT: "50000000"
+
+ # Networks granted relay permissions, make sure that you include your Docker
+ # internal network (default to 172.17.0.0/16)
+ # For kubernetes this is the CIDR of the pod network
+ RELAYNETS: "10.2.0.0/16"
+ POD_ADDRESS_RANGE: "10.2.0.0/16"
+
+
+ # Will relay all outgoing mails if configured
+ #RELAYHOST=
+
+ # This part is needed for the XCLIENT login for postfix. This should be the POD ADDRESS range
+ FRONT_ADDRESS: "front.mailu-mailserver.svc.cluster.local"
+
+ # Fetchmail delay
+ FETCHMAIL_DELAY: "600"
+
+ # Recipient delimiter, character used to delimiter localpart from custom address part
+ # e.g. localpart+custom@domain;tld
+ RECIPIENT_DELIMITER: "+"
+
+ # DMARC rua and ruf email
+ DMARC_RUA: "root"
+ DMARC_RUF: "root"
+
+ # Welcome email, enable and set a topic and body if you wish to send welcome
+ # emails to all users.
+ WELCOME: "false"
+ WELCOME_SUBJECT: "Welcome to your new email account"
+ WELCOME_BODY: "Welcome to your new email account, if you can read this, then it is configured properly!"
+
+ ###################################
+ # Web settings
+ ###################################
+
+ # Path to the admin interface if enabled
+ WEB_ADMIN: "/admin"
+
+ # Path to the webmail if enabled
+ WEB_WEBMAIL: "/webmail"
+
+ # Website name
+ SITENAME: "AppSynth"
+
+ # Linked Website URL
+ WEBSITE: "https://example.com"
+
+ # Registration reCaptcha settings (warning, this has some privacy impact)
+ # RECAPTCHA_PUBLIC_KEY=
+ # RECAPTCHA_PRIVATE_KEY=
+
+ # Domain registration, uncomment to enable
+ # DOMAIN_REGISTRATION=true
+
+ ###################################
+ # Advanced settings
+ ###################################
+
+ # Docker-compose project name, this will prepended to containers names.
+ COMPOSE_PROJECT_NAME: "mailu"
+
+ # Default password scheme used for newly created accounts and changed passwords
+ # (value: SHA512-CRYPT, SHA256-CRYPT, MD5-CRYPT, CRYPT)
+ PASSWORD_SCHEME: "SHA512-CRYPT"
+
+ # Header to take the real ip from
+ #REAL_IP_HEADER:
+
+ # IPs for nginx set_real_ip_from (CIDR list separated by commas)
+ #REAL_IP_FROM:
+
+ # Host settings
+ HOST_IMAP: "imap.mailu-mailserver.svc.cluster.local"
+ HOST_POP3: "imap.mailu-mailserver.svc.cluster.local"
+ HOST_SMTP: "smtp.mailu-mailserver.svc.cluster.local"
+ HOST_AUTHSMTP: "smtp.mailu-mailserver.svc.cluster.local"
+ HOST_WEBMAIL: "webmail.mailu-mailserver.svc.cluster.local"
+ HOST_ADMIN: "admin.mailu-mailserver.svc.cluster.local"
+ HOST_WEBDAV: "webdav.mailu-mailserver.svc.cluster.local:5232"
+ HOST_ANTISPAM: "antispam.mailu-mailserver.svc.cluster.local:11332"
+ HOST_REDIS: "redis.mailu-mailserver.svc.cluster.local"
diff --git a/docs/kubernetes/1.6/mailu/fetchmail.yaml b/docs/kubernetes/1.6/mailu/fetchmail.yaml
new file mode 100644
index 00000000..cf3271e7
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/fetchmail.yaml
@@ -0,0 +1,39 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-fetchmail
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-fetchmail
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: fetchmail
+ image: mailu/fetchmail:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ volumeMounts:
+ - name: maildata
+ mountPath: /data
+ subPath: maildata
+ ports:
+ - containerPort: 5232
+ - containerPort: 80
+ resources:
+ requests:
+ memory: 100Mi
+ cpu: 100m
+ limits:
+ memory: 100Mi
+ cpu: 100m
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/front.yaml b/docs/kubernetes/1.6/mailu/front.yaml
new file mode 100644
index 00000000..e25ac828
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/front.yaml
@@ -0,0 +1,129 @@
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-front
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-front
+ role: mail
+ tier: backend
+ spec:
+ restartPolicy: Always
+ terminationGracePeriodSeconds: 60
+ containers:
+ - name: front
+ image: mailu/nginx:latest
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ volumeMounts:
+ - name: certs
+ mountPath: /certs
+ ports:
+ - name: http
+ containerPort: 80
+ protocol: TCP
+ - name: https
+ containerPort: 443
+ protocol: TCP
+ - name: pop3
+ containerPort: 110
+ protocol: TCP
+ - name: pop3s
+ containerPort: 995
+ protocol: TCP
+ - name: imap
+ containerPort: 143
+ protocol: TCP
+ - name: imaps
+ containerPort: 993
+ protocol: TCP
+ - name: smtp
+ containerPort: 25
+ protocol: TCP
+ - name: smtp-auth
+ containerPort: 10025
+ protocol: TCP
+ - name: imap-auth
+ containerPort: 10143
+ protocol: TCP
+ - name: smtps
+ containerPort: 465
+ protocol: TCP
+ - name: smtpd
+ containerPort: 587
+ protocol: TCP
+ - name: auth
+ containerPort: 8000
+ protocol: TCP
+ resources:
+ requests:
+ memory: 100Mi
+ cpu: 100m
+ limits:
+ memory: 200Mi
+ cpu: 200m
+ volumes:
+ - name: certs
+ secret:
+ items:
+ - key: tls.crt
+ path: cert.pem
+ - key: tls.key
+ path: key.pem
+ secretName: letsencrypt-certs-all
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: front
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-admin
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-front
+ role: mail
+ tier: backend
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
+ - name: https
+ port: 443
+ protocol: TCP
+ - name: pop3
+ port: 110
+ protocol: TCP
+ - name: pop3s
+ port: 995
+ protocol: TCP
+ - name: imap
+ port: 143
+ protocol: TCP
+ - name: imaps
+ port: 993
+ protocol: TCP
+ - name: smtp
+ port: 25
+ protocol: TCP
+ - name: smtps
+ port: 465
+ protocol: TCP
+ - name: smtpd
+ port: 587
+ protocol: TCP
+ - name: smtp-auth
+ port: 10025
+ protocol: TCP
+ - name: imap-auth
+ port: 10143
+ protocol: TCP
diff --git a/docs/kubernetes/1.6/mailu/imap.yaml b/docs/kubernetes/1.6/mailu/imap.yaml
new file mode 100644
index 00000000..069b7730
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/imap.yaml
@@ -0,0 +1,80 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-imap
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-imap
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: imap
+ image: mailu/dovecot:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ volumeMounts:
+ - mountPath: /data
+ name: maildata
+ subPath: maildata
+ - mountPath: /mail
+ name: maildata
+ subPath: mailstate
+ - mountPath: /overrides
+ name: maildata
+ subPath: overrides
+ ports:
+ - containerPort: 2102
+ - containerPort: 2525
+ - containerPort: 143
+ - containerPort: 993
+ - containerPort: 4190
+ resources:
+ requests:
+ memory: 500Mi
+ cpu: 500m
+ limits:
+ memory: 1Gi
+ cpu: 1000m
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: imap
+ namespace: mailu-mailserver
+ labels:
+ app: mailu
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-imap
+ role: mail
+ tier: backend
+ ports:
+ ports:
+ - name: imap-auth
+ port: 2102
+ protocol: TCP
+ - name: imap-transport
+ port: 2525
+ protocol: TCP
+ - name: imap-default
+ port: 143
+ protocol: TCP
+ - name: imap-ssl
+ port: 993
+ protocol: TCP
+ - name: sieve
+ port: 4190
+ protocol: TCP
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/ingress-ssl.yaml b/docs/kubernetes/1.6/mailu/ingress-ssl.yaml
new file mode 100644
index 00000000..61ae3cf7
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/ingress-ssl.yaml
@@ -0,0 +1,32 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: mailu-ssl-ingress
+ namespace: mailu-mailserver
+ annotations:
+ kubernetes.io/ingress.class: tectonic
+ kubernetes.io/tls-acme: "true"
+ nginx.ingress.kubernetes.io/proxy-body-size: "0"
+ ingress.kubernetes.io/ssl-redirect: "true"
+ # Replace letsencrypt-prod with the name of the certificate issuer
+ certmanager.k8s.io/cluster-issuer: letsencrypt-prod
+ #ingress.kubernetes.io/rewrite-target: "/"
+ #ingress.kubernetes.io/app-root: "/ui"
+ #ingress.kubernetes.io/follow-redirects: "true"
+ labels:
+ app: mailu
+ role: mail
+ tier: backend
+spec:
+ tls:
+ - hosts:
+ - "mail.example.com"
+ secretName: letsencrypt-certs-all # If unsure how to generate these, check out https://github.com/ployst/docker-letsencrypt
+ rules:
+ - host: "mail.example.com"
+ http:
+ paths:
+ - path: "/"
+ backend:
+ serviceName: front
+ servicePort: 80
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/pvc.yaml b/docs/kubernetes/1.6/mailu/pvc.yaml
new file mode 100644
index 00000000..0ec2852f
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/pvc.yaml
@@ -0,0 +1,27 @@
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: redis-hdd
+ namespace: mailu-mailserver
+ annotations:
+ volume.beta.kubernetes.io/storage-class: "glusterblock-hdd"
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: mail-storage
+ namespace: mailu-mailserver
+ annotations:
+ volume.beta.kubernetes.io/storage-class: "gluster-heketi-hdd"
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 100Gi
diff --git a/docs/kubernetes/1.6/mailu/rbac.yaml b/docs/kubernetes/1.6/mailu/rbac.yaml
new file mode 100644
index 00000000..33255130
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/rbac.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: mailu-mailserver
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/redis.yaml b/docs/kubernetes/1.6/mailu/redis.yaml
new file mode 100644
index 00000000..d6bb1eb8
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/redis.yaml
@@ -0,0 +1,56 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-redis
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-redis
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: redis
+ image: redis:4.0-alpine
+ imagePullPolicy: Always
+ volumeMounts:
+ - mountPath: /data
+ name: redisdata
+ ports:
+ - containerPort: 6379
+ name: redis
+ protocol: TCP
+ resources:
+ requests:
+ memory: 200Mi
+ cpu: 100m
+ limits:
+ memory: 300Mi
+ cpu: 200m
+ volumes:
+ - name: redisdata
+ persistentVolumeClaim:
+ claimName: redis-hdd
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-redis
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-redis
+ role: mail
+ tier: backend
+ ports:
+ - name: redis
+ port: 6379
+ protocol: TCP
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/security.yaml b/docs/kubernetes/1.6/mailu/security.yaml
new file mode 100644
index 00000000..c1c1ac0b
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/security.yaml
@@ -0,0 +1,110 @@
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-security
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-security
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: antispam
+ image: mailu/rspamd:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ resources:
+ requests:
+ memory: 100Mi
+ cpu: 100m
+ limits:
+ memory: 200Mi
+ cpu: 200m
+ ports:
+ - name: antispam
+ containerPort: 11332
+ protocol: TCP
+ volumeMounts:
+ - name: filter
+ subPath: filter
+ mountPath: /var/lib/rspamd
+ - name: filter
+ mountPath: /dkim
+ subPath: dkim
+ - name: filter
+ mountPath: /etc/rspamd/override.d
+ subPath: rspamd-overrides
+ - name: antivirus
+ image: mailu/clamav:master
+ imagePullPolicy: Always
+ resources:
+ requests:
+ memory: 1Gi
+ cpu: 1000m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ ports:
+ - name: antivirus
+ containerPort: 3310
+ protocol: TCP
+ volumeMounts:
+ - name: filter
+ subPath: filter
+ mountPath: /data
+ volumes:
+ - name: filter
+ persistentVolumeClaim:
+ claimName: mail-storage
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: antispam
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-antispam
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-security
+ role: mail
+ tier: backend
+ ports:
+ - name: antispam
+ port: 11332
+ protocol: TCP
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: antivirus
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-antivirus
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-security
+ role: mail
+ tier: backend
+ ports:
+ - name: antivirus
+ port: 3310
+ protocol: TCP
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/smtp.yaml b/docs/kubernetes/1.6/mailu/smtp.yaml
new file mode 100644
index 00000000..454b8ed7
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/smtp.yaml
@@ -0,0 +1,80 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-smtp
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-smtp
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: smtp
+ image: mailu/postfix:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ resources:
+ requests:
+ memory: 500Mi
+ cpu: 200m
+ limits:
+ memory: 1Gi
+ cpu: 500m
+ volumeMounts:
+ - mountPath: /data
+ name: maildata
+ subPath: maildata
+ - mountPath: /overrides
+ name: maildata
+ subPath: overrides
+ ports:
+ - name: smtp
+ containerPort: 25
+ protocol: TCP
+ - name: smtp-ssl
+ containerPort: 465
+ protocol: TCP
+ - name: smtp-starttls
+ containerPort: 587
+ protocol: TCP
+ - name: smtp-auth
+ containerPort: 10025
+ protocol: TCP
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: smtp
+ namespace: mailu-mailserver
+ labels:
+ app: mailu
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-smtp
+ role: mail
+ tier: backend
+ ports:
+ - name: smtp
+ port: 25
+ protocol: TCP
+ - name: smtp-ssl
+ port: 465
+ protocol: TCP
+ - name: smtp-starttls
+ port: 587
+ protocol: TCP
+ - name: smtp-auth
+ port: 10025
+ protocol: TCP
diff --git a/docs/kubernetes/1.6/mailu/static-ips.yaml b/docs/kubernetes/1.6/mailu/static-ips.yaml
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/kubernetes/1.6/mailu/webdav.yaml b/docs/kubernetes/1.6/mailu/webdav.yaml
new file mode 100644
index 00000000..07b7733c
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/webdav.yaml
@@ -0,0 +1,63 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-webdav
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-webdav
+ role: mail
+ tier: backend
+ spec:
+ containers:
+ - name: radicale
+ image: mailu/radicale:master
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ volumeMounts:
+ - mountPath: /data
+ name: maildata
+ subPath: dav
+ ports:
+ - containerPort: 5232
+ - containerPort: 80
+ resources:
+ requests:
+ memory: 100Mi
+ cpu: 100m
+ limits:
+ memory: 100Mi
+ cpu: 100m
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: webdav
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-webdav
+ role: mail
+ tier: backend
+spec:
+ selector:
+ app: mailu-webdav
+ role: mail
+ tier: backend
+ ports:
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
+ - name: http-ui
+ port: 5232
+ protocol: TCP
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/mailu/webmail.yaml b/docs/kubernetes/1.6/mailu/webmail.yaml
new file mode 100644
index 00000000..81798782
--- /dev/null
+++ b/docs/kubernetes/1.6/mailu/webmail.yaml
@@ -0,0 +1,59 @@
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: mailu-roundcube
+ namespace: mailu-mailserver
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: mailu-roundcube
+ role: mail
+ tier: frontend
+ spec:
+ containers:
+ - name: roundcube
+ image: mailu/roundcube:1.5
+ imagePullPolicy: Always
+ envFrom:
+ - configMapRef:
+ name: mailu-config
+ resources:
+ requests:
+ memory: 100Mi
+ cpu: 100m
+ limits:
+ memory: 200Mi
+ cpu: 200m
+ volumeMounts:
+ - mountPath: /data
+ name: maildata
+ subPath: webmail
+ ports:
+ - containerPort: 80
+ volumes:
+ - name: maildata
+ persistentVolumeClaim:
+ claimName: mail-storage
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: webmail
+ namespace: mailu-mailserver
+ labels:
+ app: mailu-roundcube
+ role: mail
+ tier: frontend
+spec:
+ selector:
+ app: mailu-roundcube
+ role: mail
+ tier: frontend
+ ports:
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
diff --git a/docs/kubernetes/1.6/nginx/default-http-backend.yaml b/docs/kubernetes/1.6/nginx/default-http-backend.yaml
new file mode 100644
index 00000000..097fe7c5
--- /dev/null
+++ b/docs/kubernetes/1.6/nginx/default-http-backend.yaml
@@ -0,0 +1,55 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: default-http-backend
+ labels:
+ app: default-http-backend
+ namespace: kube-ingress
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: default-http-backend
+ template:
+ metadata:
+ labels:
+ app: default-http-backend
+ spec:
+ terminationGracePeriodSeconds: 60
+ containers:
+ - name: default-http-backend
+ # Any image is permissible as long as:
+ # 1. It serves a 404 page at /
+ # 2. It serves 200 on a /healthz endpoint
+ image: gcr.io/google_containers/defaultbackend:1.4
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: 8080
+ scheme: HTTP
+ initialDelaySeconds: 30
+ timeoutSeconds: 5
+ ports:
+ - containerPort: 8080
+ resources:
+ limits:
+ cpu: 10m
+ memory: 20Mi
+ requests:
+ cpu: 10m
+ memory: 20Mi
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: default-http-backend
+ namespace: kube-ingress
+ labels:
+ app: default-http-backend
+spec:
+ ports:
+ - port: 80
+ targetPort: 8080
+ selector:
+ app: default-http-backend
\ No newline at end of file
diff --git a/docs/kubernetes/1.6/nginx/nginx-ingress.yaml b/docs/kubernetes/1.6/nginx/nginx-ingress.yaml
new file mode 100644
index 00000000..90b24f24
--- /dev/null
+++ b/docs/kubernetes/1.6/nginx/nginx-ingress.yaml
@@ -0,0 +1,139 @@
+apiVersion: v1
+kind: Service
+metadata:
+ # keep it under 24 chars
+ name: appsynth-lb
+ namespace: kube-ingress
+ labels:
+ k8s-app: appsynth-lb
+ component: ingress-controller
+spec:
+ type: ClusterIP
+ selector:
+ k8s-app: appsynth-lb
+ component: ingress-controller
+ ports:
+ - name: http
+ protocol: TCP
+ port: 80
+ targetPort: 80
+ - name: https
+ protocol: TCP
+ port: 443
+ targetPort: 443
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: udp-services
+ namespace: kube-ingress
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: tcp-services
+ namespace: kube-ingress
+data:
+ 25: "mailu-mailserver/front:25"
+ 110: "mailu-mailserver/front:110"
+ 465: "mailu-mailserver/front:465"
+ 587: "mailu-mailserver/front:587"
+ 143: "mailu-mailserver/front:143"
+ 993: "mailu-mailserver/front:993"
+ 995: "mailu-mailserver/front:995"
+
+---
+apiVersion: v1
+data:
+ enable-vts-status: "true"
+kind: ConfigMap
+metadata:
+ name: nginx-ingress-lb-conf
+ namespace: kube-ingress
+---
+apiVersion: apps/v1beta2
+kind: DaemonSet
+metadata:
+ name: ingress-controller
+ namespace: kube-ingress
+ annotations:
+ prometheus.io/port: "10254"
+ prometheus.io/scrape: "true"
+ labels:
+ k8s-app: appsynth-lb
+ component: ingress-controller
+ type: nginx
+spec:
+ updateStrategy:
+ rollingUpdate:
+ maxUnavailable: 1
+ type: RollingUpdate
+ selector:
+ matchLabels:
+ k8s-app: appsynth-lb
+ component: ingress-controller
+ type: nginx
+ template:
+ metadata:
+ labels:
+ k8s-app: appsynth-lb
+ component: ingress-controller
+ type: nginx
+ spec:
+ serviceAccount: kube-nginx-ingress
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: node-role.kubernetes.io/master
+ operator: DoesNotExist
+ containers:
+ - name: nginx-ingress-lb
+ image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.16.2
+ args:
+ - /nginx-ingress-controller
+ - --configmap=$(POD_NAMESPACE)/tectonic-custom-error
+ - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
+ #- --default-ssl-certificate=tectonic-system/tectonic-ingress-tls-secret
+ - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
+ - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
+ - --annotations-prefix=ingress.kubernetes.io
+ - --enable-ssl-passthrough
+ - --ingress-class=tectonic
+ # use downward API
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ ports:
+ - name: http
+ containerPort: 80
+ hostPort: 80
+ - name: https
+ containerPort: 443
+ hostPort: 443
+ readinessProbe:
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ livenessProbe:
+ initialDelaySeconds: 10
+ timeoutSeconds: 1
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ hostNetwork: true
+ nodeSelector:
+ node-role.kubernetes.io/node: ""
+ dnsPolicy: ClusterFirst
+ restartPolicy: Always
+ terminationGracePeriodSeconds: 60
diff --git a/docs/kubernetes/1.6/nginx/rbac.yaml b/docs/kubernetes/1.6/nginx/rbac.yaml
new file mode 100644
index 00000000..d3c01384
--- /dev/null
+++ b/docs/kubernetes/1.6/nginx/rbac.yaml
@@ -0,0 +1,129 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: kube-ingress
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: kube-nginx-ingress
+ namespace: kube-ingress
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+ name: kube-nginx-ingress
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - endpoints
+ - nodes
+ - pods
+ - secrets
+ verbs:
+ - list
+ - watch
+ - update
+ - apiGroups:
+ - ""
+ resources:
+ - nodes
+ verbs:
+ - get
+ - apiGroups:
+ - ""
+ resources:
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - "extensions"
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
+ - apiGroups:
+ - "extensions"
+ resources:
+ - ingresses/status
+ verbs:
+ - update
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: Role
+metadata:
+ name: kube-nginx-ingress
+ namespace: kube-ingress
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - pods
+ - secrets
+ - namespaces
+ verbs:
+ - get
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ resourceNames:
+ - "ingress-controller-leader-nginx"
+ verbs:
+ - get
+ - update
+ - apiGroups:
+ - ""
+ resources:
+ - configmaps
+ verbs:
+ - create
+ - apiGroups:
+ - ""
+ resources:
+ - endpoints
+ verbs:
+ - get
+ - create
+ - update
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: RoleBinding
+metadata:
+ name: kube-nginx-ingress
+ namespace: kube-ingress
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: kube-nginx-ingress
+subjects:
+ - kind: ServiceAccount
+ name: kube-nginx-ingress
+ namespace: kube-ingress
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+ name: kube-nginx-ingress
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: kube-nginx-ingress
+subjects:
+ - kind: ServiceAccount
+ name: kube-nginx-ingress
+ namespace: kube-ingress
\ No newline at end of file
diff --git a/docs/kubernetes/index.rst b/docs/kubernetes/stable/index.rst
similarity index 100%
rename from docs/kubernetes/index.rst
rename to docs/kubernetes/stable/index.rst
diff --git a/docs/kubernetes/kubernetes-mailu.yaml b/docs/kubernetes/stable/kubernetes-mailu.yaml
similarity index 100%
rename from docs/kubernetes/kubernetes-mailu.yaml
rename to docs/kubernetes/stable/kubernetes-mailu.yaml
diff --git a/docs/kubernetes/kubernetes-nginx-ingress-controller.yaml b/docs/kubernetes/stable/kubernetes-nginx-ingress-controller.yaml
similarity index 100%
rename from docs/kubernetes/kubernetes-nginx-ingress-controller.yaml
rename to docs/kubernetes/stable/kubernetes-nginx-ingress-controller.yaml
diff --git a/docs/swarm/1.5/README.md b/docs/swarm/1.5/README.md
new file mode 100644
index 00000000..6b56e642
--- /dev/null
+++ b/docs/swarm/1.5/README.md
@@ -0,0 +1,364 @@
+# Install Mailu on a docker swarm
+
+## Prequisites
+
+### Swarm
+
+In order to deploy Mailu on a swarm, you will first need to initialize the swarm:
+
+The main command will be:
+```bash
+docker swarm init --advertise-addr
+```
+See https://docs.docker.com/engine/swarm/swarm-tutorial/create-swarm/
+
+If you want to add other managers or workers, please use:
+```bash
+docker swarm join --token xxxxx
+```
+See https://docs.docker.com/engine/swarm/join-nodes/
+
+You have now a working swarm, and you can check its status with:
+```bash
+core@coreos-01 ~/git/Mailu/docs/swarm/1.5 $ docker node ls
+ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
+xhgeekkrlttpmtgmapt5hyxrb black-pearl Ready Active 18.06.0-ce
+sczlqjgfhehsfdjhfhhph1nvb * coreos-01 Ready Active Leader 18.03.1-ce
+mzrm9nbdggsfz4sgq6dhs5i6n flying-dutchman Ready Active 18.06.0-ce
+```
+
+### Volume definition
+For data persistance (the Mailu services might be launched/relaunched on any of the swarm nodes), we need to have Mailu data stored in a manner accessible by every manager or worker in the swarm.
+Hereafter we will use a NFS share:
+```bash
+core@coreos-01 ~ $ showmount -e 192.168.0.30
+Export list for 192.168.0.30:
+/mnt/Pool1/pv 192.168.0.0
+```
+
+on the nfs server, I am using the following /etc/exports
+```bash
+$more /etc/exports
+/mnt/Pool1/pv -alldirs -mapall=root -network 192.168.0.0 -mask 255.255.255.0
+```
+on the nfs server, I created the Mailu directory (in fact I copied a working Mailu set-up)
+```bash
+$mkdir /mnt/Pool1/pv/mailu
+```
+
+On your manager node, mount the nfs share to check that the share is available:
+```bash
+core@coreos-01 ~ $ sudo mount -t nfs 192.168.0.30:/mnt/Pool1/pv/mailu /mnt/local/
+```
+If this is ok, you can umount it:
+```bash
+core@coreos-01 ~ $ sudo umount /mnt/local/
+```
+
+
+### Networking mode
+On a swarm, the services are available (default mode) through a routing mesh managed by docker itself. With this mode, each service is given a virtual IP adress and docker manages the routing between this virtual IP and the container(s) provinding this service.
+With this default networking mode, I cannot get login working properly... As found in https://github.com/Mailu/Mailu/issues/375 , a workaround is to use the dnsrr networking mode at least for the front services.
+
+The main consequence/limitation will be that the front services will *not* be available on every node, but only on the node where it will be deployed. In my case, I have only one manager and I choose to deploy the front service to the manager node, so I know on wich IP the front service will be available (aka the IP adress of my manager node).
+
+### Variable substitution and docker-compose.yml
+The docker stack deploy command doesn't support variable substitution in the .yml file itself (but we still can use .env file to pass variables to the services). As a consequence we need to adjust the docker-compose file in order to :
+- remove all variables : $VERSION , $BIND_ADDRESS4 , $BIND_ADDRESS6 , $ANTIVIRUS , $WEBMAIL , etc
+- change the way we define the volumes (nfs share in our case)
+- add a deploy section for every service
+
+### Docker compose
+An example of docker-compose-stack.yml file is available here:
+
+```yaml
+
+version: '3.2'
+
+services:
+
+ front:
+ image: mailu/nginx:1.5
+ env_file: .env
+ ports:
+ - target: 80
+ published: 80
+ mode: host
+ - target: 443
+ published: 443
+ mode: host
+ - target: 110
+ published: 110
+ mode: host
+ - target: 143
+ published: 143
+ mode: host
+ - target: 993
+ published: 993
+ mode: host
+ - target: 995
+ published: 995
+ mode: host
+ - target: 25
+ published: 25
+ mode: host
+ - target: 465
+ published: 465
+ mode: host
+ - target: 587
+ published: 587
+ mode: host
+ volumes:
+# - "$ROOT/certs:/certs"
+ - type: volume
+ source: mailu_certs
+ target: /certs
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ redis:
+ image: redis:alpine
+ restart: always
+ volumes:
+# - "$ROOT/redis:/data"
+ - type: volume
+ source: mailu_redis
+ target: /data
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ imap:
+ image: mailu/dovecot:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/data:/data"
+ - type: volume
+ source: mailu_data
+ target: /data
+# - "$ROOT/mail:/mail"
+ - type: volume
+ source: mailu_mail
+ target: /mail
+# - "$ROOT/overrides:/overrides"
+ - type: volume
+ source: mailu_overrides
+ target: /overrides
+ depends_on:
+ - front
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ smtp:
+ image: mailu/postfix:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/data:/data"
+ - type: volume
+ source: mailu_data
+ target: /data
+# - "$ROOT/overrides:/overrides"
+ - type: volume
+ source: mailu_overrides
+ target: /overrides
+ depends_on:
+ - front
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ antispam:
+ image: mailu/rspamd:1.5
+ restart: always
+ env_file: .env
+ depends_on:
+ - front
+ volumes:
+# - "$ROOT/filter:/var/lib/rspamd"
+ - type: volume
+ source: mailu_filter
+ target: /var/lib/rspamd
+# - "$ROOT/dkim:/dkim"
+ - type: volume
+ source: mailu_dkim
+ target: /dkim
+# - "$ROOT/overrides/rspamd:/etc/rspamd/override.d"
+ - type: volume
+ source: mailu_overrides_rspamd
+ target: /etc/rspamd/override.d
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ antivirus:
+ image: mailu/none:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/filter:/data"
+ - type: volume
+ source: mailu_filter
+ target: /data
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ webdav:
+ image: mailu/none:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/dav:/data"
+ - type: volume
+ source: mailu_dav
+ target: /data
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ admin:
+ image: mailu/admin:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/data:/data"
+ - type: volume
+ source: mailu_data
+ target: /data
+# - "$ROOT/dkim:/dkim"
+ - type: volume
+ source: mailu_dkim
+ target: /dkim
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ depends_on:
+ - redis
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ webmail:
+ image: "mailu/roundcube:1.5"
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/webmail:/data"
+ - type: volume
+ source: mailu_data
+ target: /data
+ depends_on:
+ - imap
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+ fetchmail:
+ image: mailu/fetchmail:1.5
+ restart: always
+ env_file: .env
+ volumes:
+# - "$ROOT/data:/data"
+ - type: volume
+ source: mailu_data
+ target: /data
+ logging:
+ driver: none
+ deploy:
+ endpoint_mode: dnsrr
+ replicas: 1
+ placement:
+ constraints: [node.role == manager]
+
+volumes:
+ mailu_filter:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/filter"
+ mailu_dkim:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/dkim"
+ mailu_overrides_rspamd:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/overrides/rspamd"
+ mailu_data:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/data"
+ mailu_mail:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/mail"
+ mailu_overrides:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/overrides"
+ mailu_dav:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/dav"
+ mailu_certs:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/certs"
+ mailu_redis:
+ driver_opts:
+ type: "nfs"
+ o: "addr=192.168.0.30,nolock,soft,rw"
+ device: ":/mnt/Pool1/pv/mailu/redis"
+```
+
+### Deploy Mailu on the docker swarm
+Run the following command:
+```bash
+docker stack deploy -c docker-compose-stack.yml mailu
+```
+See how the services are being deployed:
+```bash
+core@coreos-01 ~ $ docker service ls
+ID NAME MODE REPLICAS IMAGE PORTS
+ywnsetmtkb1l mailu_antivirus replicated 1/1 mailu/none:1.5
+pqokiaz0q128 mailu_fetchmail replicated 1/1 mailu/fetchmail:1.5
+```
+check a specific service:
+```bash
+core@coreos-01 ~ $ docker service ps mailu_fetchmail
+ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
+tbu8ppgsdffj mailu_fetchmail.1 mailu/fetchmail:1.5 coreos-01 Running Running 11 days ago
+```
+
+### Remove the stack
+Run the follwoing command:
+```bash
+core@coreos-01 ~ $ docker stack rm mailu
+```
diff --git a/setup/Dockerfile b/setup/Dockerfile
index 9111ae44..1fc808f1 100644
--- a/setup/Dockerfile
+++ b/setup/Dockerfile
@@ -15,4 +15,4 @@ 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
+CMD gunicorn -w 4 -b :80 --access-logfile - --error-logfile - --preload main:app
diff --git a/setup/docker-compose.yml b/setup/docker-compose.yml
new file mode 100644
index 00000000..9288bb7e
--- /dev/null
+++ b/setup/docker-compose.yml
@@ -0,0 +1,13 @@
+# This file is used to run the mailu/setup utility
+
+version: '2'
+
+services:
+ redis:
+ image: redis:alpine
+
+ setup:
+ image: mailu/setup
+ ports:
+ - "80:80"
+
diff --git a/tests/build.yml b/tests/build.yml
new file mode 100644
index 00000000..674abf8c
--- /dev/null
+++ b/tests/build.yml
@@ -0,0 +1,47 @@
+version: '3'
+
+services:
+
+ front:
+ image: mailu/nginx:$VERSION
+ build: ../core/nginx
+
+ imap:
+ image: mailu/dovecot:$VERSION
+ build: ../core/dovecot
+
+ smtp:
+ image: mailu/postfix:$VERSION
+ build: ../core/postfix
+
+ antispam:
+ image: mailu/rspamd:$VERSION
+ build: ../services/rspamd
+
+ antivirus:
+ image: mailu/clamav:$VERSION
+ build: ../optional/clamav
+
+ webdav:
+ image: mailu/radicale:$VERSION
+ build: ../optional/radicale
+
+ admin:
+ image: mailu/admin:$VERSION
+ build: ../core/admin
+
+ roundcube:
+ image: mailu/roundcube:$VERSION
+ build: ../webmails/roundcube
+
+ rainloop:
+ image: mailu/rainloop:$VERSION
+ build: ../webmails/rainloop
+
+ fetchmail:
+ image: mailu/fetchmail:$VERSION
+ build: ../services/fetchmail
+
+ none:
+ image: mailu/none:$VERSION
+ build: ../core/none
diff --git a/webmails/rainloop/Dockerfile b/webmails/rainloop/Dockerfile
index 714390d8..dfc6c83e 100644
--- a/webmails/rainloop/Dockerfile
+++ b/webmails/rainloop/Dockerfile
@@ -3,7 +3,7 @@ FROM php:5-apache
RUN apt-get update && apt-get install -y \
unzip python3 python3-jinja2
-ENV RAINLOOP_URL https://github.com/RainLoop/rainloop-webmail/releases/download/v1.12.0/rainloop-community-1.12.0.zip
+ENV RAINLOOP_URL https://github.com/RainLoop/rainloop-webmail/releases/download/v1.12.1/rainloop-community-1.12.1.zip
RUN rm -rf /var/www/html/ \
&& mkdir /var/www/html \
diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile
index c779e71a..3f7eee0d 100644
--- a/webmails/roundcube/Dockerfile
+++ b/webmails/roundcube/Dockerfile
@@ -4,10 +4,10 @@ RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
- libpng12-dev \
+ libpng-dev \
&& docker-php-ext-install pdo_mysql mcrypt zip
-ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.3.6/roundcubemail-1.3.6-complete.tar.gz
+ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.3.7/roundcubemail-1.3.7-complete.tar.gz
RUN echo date.timezone=UTC > /usr/local/etc/php/conf.d/timezone.ini
diff --git a/webmails/roundcube/config.inc.php b/webmails/roundcube/config.inc.php
index 379b3025..35088107 100644
--- a/webmails/roundcube/config.inc.php
+++ b/webmails/roundcube/config.inc.php
@@ -6,6 +6,7 @@ $config = array();
$config['db_dsnw'] = 'sqlite:////data/roundcube.db';
$config['temp_dir'] = '/tmp/';
$config['des_key'] = getenv('SECRET_KEY');
+$config['cipher_method'] = 'AES-256-CBC';
$config['identities_level'] = 3;
$config['reply_all_mode'] = 1;
@@ -18,16 +19,19 @@ $config['plugins'] = array(
'enigma'
);
+$front = getenv('FRONT_ADDRESS') ? getenv('FRONT_ADDRESS') : 'front';
+$imap = getenv('IMAP_ADDRESS') ? getenv('IMAP_ADDRESS') : 'imap';
+
// Mail servers
-$config['default_host'] = getenv('FRONT_ADDRESS') || 'front';
+$config['default_host'] = $front;
$config['default_port'] = 10143;
-$config['smtp_server'] = getenv('FRONT_ADDRESS') || 'front';
+$config['smtp_server'] = $front;
$config['smtp_port'] = 10025;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
// Sieve script management
-$config['managesieve_host'] = getenv('IMAP_ADDRESS') || 'imap';
+$config['managesieve_host'] = $imap;
$config['managesieve_usetls'] = false;
// We access the IMAP and SMTP servers locally with internal names, SSL