mirror of
https://github.com/Mailu/Mailu.git
synced 2025-03-17 20:57:54 +02:00
Merge remote-tracking branch 'upstream/master' into upgrade-alpine
This commit is contained in:
commit
d3d7916b58
6
.github/workflows/build_test_deploy.yml
vendored
6
.github/workflows/build_test_deploy.yml
vendored
@ -340,7 +340,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ["core", "fetchmail", "filters", "snappymail", "roundcube", "webdav"]
|
||||
target: ["core", "fetchmail", "filters", "webmail", "webdav"]
|
||||
time: ["2"]
|
||||
include:
|
||||
- target: "filters"
|
||||
@ -394,7 +394,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ["setup", "docs", "fetchmail", "roundcube", "admin", "traefik-certdumper", "radicale", "clamav", "rspamd", "postfix", "dovecot", "unbound", "nginx", "snappymail"]
|
||||
target: ["setup", "docs", "fetchmail", "webmail", "admin", "traefik-certdumper", "radicale", "clamav", "rspamd", "postfix", "dovecot", "unbound", "nginx"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Retrieve global variables
|
||||
@ -439,7 +439,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ["setup", "docs", "fetchmail", "roundcube", "admin", "traefik-certdumper", "radicale", "clamav", "rspamd", "postfix", "dovecot", "unbound", "nginx", "snappymail"]
|
||||
target: ["setup", "docs", "fetchmail", "webmail", "admin", "traefik-certdumper", "radicale", "clamav", "rspamd", "postfix", "dovecot", "unbound", "nginx"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Retrieve global variables
|
||||
|
@ -12,10 +12,12 @@ def fetch_list():
|
||||
"id": fetch.id,
|
||||
"tls": fetch.tls,
|
||||
"keep": fetch.keep,
|
||||
"scan": fetch.scan,
|
||||
"user_email": fetch.user_email,
|
||||
"protocol": fetch.protocol,
|
||||
"host": fetch.host,
|
||||
"port": fetch.port,
|
||||
"folders": fetch.folders,
|
||||
"username": fetch.username,
|
||||
"password": fetch.password
|
||||
} for fetch in models.Fetch.query.all()
|
||||
|
@ -771,6 +771,8 @@ class Fetch(Base):
|
||||
username = db.Column(db.String(255), nullable=False)
|
||||
password = db.Column(db.String(255), nullable=False)
|
||||
keep = db.Column(db.Boolean, nullable=False, default=False)
|
||||
scan = db.Column(db.Boolean, nullable=False, default=False)
|
||||
folders = db.Column(CommaSeparatedList, nullable=True, default=list)
|
||||
last_check = db.Column(db.DateTime, nullable=True)
|
||||
error = db.Column(db.String(1023), nullable=True)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
from mailu.sso import sso
|
||||
import flask
|
||||
|
||||
@sso.route('/language/<language>', methods=['POST'])
|
||||
@sso.route('/language/<language>', methods=['GET','POST'])
|
||||
def set_language(language=None):
|
||||
if language:
|
||||
flask.session['language'] = language
|
||||
|
@ -41,6 +41,16 @@ class MultipleEmailAddressesVerify(object):
|
||||
if not pattern.match(field.data.replace(" ", "")):
|
||||
raise validators.ValidationError(self.message)
|
||||
|
||||
class MultipleFoldersVerify(object):
|
||||
""" Ensure that we have CSV formated data """
|
||||
def __init__(self,message=_('Invalid list of folders.')):
|
||||
self.message = message
|
||||
|
||||
def __call__(self, form, field):
|
||||
pattern = re.compile(r'^\w+(\s*,\s*\w+)*$')
|
||||
if not pattern.match(field.data.replace(" ", "")):
|
||||
raise validators.ValidationError(self.message)
|
||||
|
||||
class ConfirmationForm(flask_wtf.FlaskForm):
|
||||
submit = fields.SubmitField(_('Confirm'))
|
||||
|
||||
@ -164,11 +174,13 @@ class FetchForm(flask_wtf.FlaskForm):
|
||||
('imap', 'IMAP'), ('pop3', 'POP3')
|
||||
])
|
||||
host = fields.StringField(_('Hostname or IP'), [validators.DataRequired()])
|
||||
port = fields.IntegerField(_('TCP port'), [validators.DataRequired(), validators.NumberRange(min=0, max=65535)])
|
||||
tls = fields.BooleanField(_('Enable TLS'))
|
||||
port = fields.IntegerField(_('TCP port'), [validators.DataRequired(), validators.NumberRange(min=0, max=65535)], default=993)
|
||||
tls = fields.BooleanField(_('Enable TLS'), default=True)
|
||||
username = fields.StringField(_('Username'), [validators.DataRequired()])
|
||||
password = fields.PasswordField(_('Password'))
|
||||
keep = fields.BooleanField(_('Keep emails on the server'))
|
||||
scan = fields.BooleanField(_('Rescan emails locally'))
|
||||
folders = fields.StringField(_('Folders to fetch on the server'), [validators.Optional(), MultipleFoldersVerify()], default='INBOX,Junk')
|
||||
submit = fields.SubmitField(_('Submit'))
|
||||
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
{%- call macros.card(title="Settings") %}
|
||||
{{ macros.form_field(form.keep) }}
|
||||
{{ macros.form_field(form.scan) }}
|
||||
{{ macros.form_field(form.folders) }}
|
||||
{%- endcall %}
|
||||
|
||||
{{ macros.form_field(form.submit) }}
|
||||
|
@ -20,6 +20,8 @@
|
||||
<th>{% trans %}Endpoint{% endtrans %}</th>
|
||||
<th>{% trans %}Username{% endtrans %}</th>
|
||||
<th>{% trans %}Keep emails{% endtrans %}</th>
|
||||
<th>{% trans %}Rescan emails{% endtrans %}</th>
|
||||
<th>{% trans %}Folders{% endtrans %}</th>
|
||||
<th>{% trans %}Last check{% endtrans %}</th>
|
||||
<th>{% trans %}Status{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
@ -36,6 +38,8 @@
|
||||
<td>{{ fetch.protocol }}{{ 's' if fetch.tls else '' }}://{{ fetch.host }}:{{ fetch.port }}</td>
|
||||
<td>{{ fetch.username }}</td>
|
||||
<td data-sort="{{ fetch.keep }}">{% if fetch.keep %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
|
||||
<td data-sort="{{ fetch.scan }}">{% if fetch.scan %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
|
||||
<td>{{ fetch.folders | join(',') }}</td>
|
||||
<td>{{ fetch.last_check | format_datetime or '-' }}</td>
|
||||
<td>{{ fetch.error or '-' }}</td>
|
||||
<td data-sort="{{ fetch.created_at or '0000-00-00' }}">{{ fetch.created_at | format_date }}</td>
|
||||
|
@ -1,4 +1,4 @@
|
||||
from mailu import models
|
||||
from mailu import models, utils
|
||||
from mailu.ui import ui, forms, access
|
||||
from flask import current_app as app
|
||||
|
||||
@ -28,9 +28,12 @@ def fetch_create(user_email):
|
||||
user = models.User.query.get(user_email) or flask.abort(404)
|
||||
form = forms.FetchForm()
|
||||
form.password.validators = [wtforms.validators.DataRequired()]
|
||||
utils.formatCSVField(form.folders)
|
||||
if form.validate_on_submit():
|
||||
fetch = models.Fetch(user=user)
|
||||
form.populate_obj(fetch)
|
||||
if form.folders.data:
|
||||
fetch.folders = form.folders.data.replace(' ','').split(',')
|
||||
models.db.session.add(fetch)
|
||||
models.db.session.commit()
|
||||
flask.flash('Fetch configuration created')
|
||||
@ -46,10 +49,13 @@ def fetch_edit(fetch_id):
|
||||
flask.abort(404)
|
||||
fetch = models.Fetch.query.get(fetch_id) or flask.abort(404)
|
||||
form = forms.FetchForm(obj=fetch)
|
||||
utils.formatCSVField(form.folders)
|
||||
if form.validate_on_submit():
|
||||
if not form.password.data:
|
||||
form.password.data = fetch.password
|
||||
form.populate_obj(fetch)
|
||||
if form.folders.data:
|
||||
fetch.folders = form.folders.data.replace(' ','').split(',')
|
||||
models.db.session.commit()
|
||||
flask.flash('Fetch configuration updated')
|
||||
return flask.redirect(
|
||||
|
@ -64,10 +64,11 @@ def user_edit(user_email):
|
||||
form.quota_bytes.validators = [
|
||||
wtforms.validators.NumberRange(max=max_quota_bytes)]
|
||||
if form.validate_on_submit():
|
||||
if msg := utils.isBadOrPwned(form):
|
||||
flask.flash(msg, "error")
|
||||
return flask.render_template('user/edit.html', form=form, user=user,
|
||||
domain=user.domain, max_quota_bytes=max_quota_bytes)
|
||||
if form.pw.data:
|
||||
if msg := utils.isBadOrPwned(form):
|
||||
flask.flash(msg, "error")
|
||||
return flask.render_template('user/edit.html', form=form, user=user,
|
||||
domain=user.domain, max_quota_bytes=max_quota_bytes)
|
||||
form.populate_obj(user)
|
||||
if form.pw.data:
|
||||
user.set_password(form.pw.data)
|
||||
@ -99,11 +100,7 @@ def user_settings(user_email):
|
||||
user_email_or_current = user_email or flask_login.current_user.email
|
||||
user = models.User.query.get(user_email_or_current) or flask.abort(404)
|
||||
form = forms.UserSettingsForm(obj=user)
|
||||
if isinstance(form.forward_destination.data,str):
|
||||
data = form.forward_destination.data.replace(" ","").split(",")
|
||||
else:
|
||||
data = form.forward_destination.data
|
||||
form.forward_destination.data = ", ".join(data)
|
||||
utils.formatCSVField(form.forward_destination)
|
||||
if form.validate_on_submit():
|
||||
form.forward_destination.data = form.forward_destination.data.replace(" ","").split(",")
|
||||
form.populate_obj(user)
|
||||
|
@ -518,3 +518,10 @@ def isBadOrPwned(form):
|
||||
if breaches > 0:
|
||||
return f"This password appears in {breaches} data breaches! It is not unique; please change it."
|
||||
return None
|
||||
|
||||
def formatCSVField(field):
|
||||
if isinstance(field.data,str):
|
||||
data = field.data.replace(" ","").split(",")
|
||||
else:
|
||||
data = field.data
|
||||
field.data = ", ".join(data)
|
||||
|
25
core/admin/migrations/versions/f4f0f89e0047_.py
Normal file
25
core/admin/migrations/versions/f4f0f89e0047_.py
Normal file
@ -0,0 +1,25 @@
|
||||
""" Add fetch.scan and fetch.folders
|
||||
|
||||
Revision ID: f4f0f89e0047
|
||||
Revises: 8f9ea78776f4
|
||||
Create Date: 2022-11-13 16:29:01.246509
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'f4f0f89e0047'
|
||||
down_revision = '8f9ea78776f4'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import mailu
|
||||
|
||||
def upgrade():
|
||||
with op.batch_alter_table('fetch') as batch:
|
||||
batch.add_column(sa.Column('scan', sa.Boolean(), nullable=False, server_default=sa.sql.expression.false()))
|
||||
batch.add_column(sa.Column('folders', mailu.models.CommaSeparatedList(), nullable=True))
|
||||
|
||||
def downgrade():
|
||||
with op.batch_alter_table('fetch') as batch:
|
||||
batch.drop_column('fetch', 'folders')
|
||||
batch.drop_column('fetch', 'scan')
|
@ -8,14 +8,13 @@ ENV TZ=Etc/UTC LANG=C.UTF-8
|
||||
|
||||
ARG MAILU_UID=1000
|
||||
ARG MAILU_GID=1000
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; addgroup -Sg ${MAILU_GID} mailu \
|
||||
; adduser -Sg ${MAILU_UID} -G mailu -h /app -g "mailu app" -s /bin/bash mailu \
|
||||
; apk add --no-cache bash ca-certificates curl python3 tzdata libcap \
|
||||
; machine="$(uname -m)" \
|
||||
; ! [[ "${TARGETPLATFORM}" != linux/arm/v7 && \( "${machine}" == x86_64 || "${machine}" == armv8* || "${machine}" == aarch64 \) ]] \
|
||||
; ! [[ "${machine}" == x86_64 ]] \
|
||||
|| apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing hardened-malloc
|
||||
|
||||
ENV LD_PRELOAD=/usr/lib/libhardened_malloc.so
|
||||
|
@ -157,7 +157,11 @@ You can add a fetched account by clicking on the `Add an account` button on the
|
||||
|
||||
* Keep emails on the server. When ticked, retains the email message in the email account after retrieving it.
|
||||
|
||||
Click the submit button to apply settings. With the default polling interval, fetchmail will start polling the email account after 10 minutes.
|
||||
* Scan emails. When ticked, all the fetched emails will go through the local filters (rspamd, clamav, ...).
|
||||
|
||||
* Folders. A comma separated list of folders to fetch from the server. This is optional, by default only the INBOX will be pulled.
|
||||
|
||||
Click the submit button to apply settings. With the default polling interval, fetchmail will start polling the email account after ``FETCHMAIL_DELAY``.
|
||||
|
||||
|
||||
Authentication tokens
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
import time
|
||||
import os
|
||||
from pathlib import Path
|
||||
from pwd import getpwnam
|
||||
import tempfile
|
||||
import shlex
|
||||
import subprocess
|
||||
import re
|
||||
import requests
|
||||
from socrate import system
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
@ -14,6 +17,7 @@ import traceback
|
||||
FETCHMAIL = """
|
||||
fetchmail -N \
|
||||
--idfile /data/fetchids --uidl \
|
||||
--pidfile /dev/shm/fetchmail.pid \
|
||||
--sslcertck --sslcertpath /etc/ssl/certs \
|
||||
-f {}
|
||||
"""
|
||||
@ -24,7 +28,9 @@ poll "{host}" proto {protocol} port {port}
|
||||
user "{username}" password "{password}"
|
||||
is "{user_email}"
|
||||
smtphost "{smtphost}"
|
||||
{folders}
|
||||
{options}
|
||||
{lmtp}
|
||||
"""
|
||||
|
||||
|
||||
@ -48,26 +54,37 @@ def fetchmail(fetchmailrc):
|
||||
|
||||
def run(debug):
|
||||
try:
|
||||
fetches = requests.get("http://" + os.environ.get("HOST_ADMIN", "admin") + "/internal/fetch").json()
|
||||
smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None)
|
||||
os.environ["SMTP_ADDRESS"] = system.get_host_address_from_environment("SMTP", "smtp")
|
||||
os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
|
||||
fetches = requests.get(f"http://{os.environ['ADMIN_ADDRESS']}/internal/fetch").json()
|
||||
smtphost, smtpport = extract_host_port(os.environ["SMTP_ADDRESS"], None)
|
||||
if smtpport is None:
|
||||
smtphostport = smtphost
|
||||
else:
|
||||
smtphostport = "%s/%d" % (smtphost, smtpport)
|
||||
os.environ["LMTP_ADDRESS"] = system.get_host_address_from_environment("LMTP", "imap:2525")
|
||||
lmtphost, lmtpport = extract_host_port(os.environ["LMTP_ADDRESS"], None)
|
||||
if lmtpport is None:
|
||||
lmtphostport = lmtphost
|
||||
else:
|
||||
lmtphostport = "%s/%d" % (lmtphost, lmtpport)
|
||||
for fetch in fetches:
|
||||
fetchmailrc = ""
|
||||
options = "options antispam 501, 504, 550, 553, 554"
|
||||
options += " ssl" if fetch["tls"] else ""
|
||||
options += " keep" if fetch["keep"] else " fetchall"
|
||||
folders = "folders %s" % ((','.join('"' + item + '"' for item in fetch['folders'])) if fetch['folders'] else '"INBOX"')
|
||||
fetchmailrc += RC_LINE.format(
|
||||
user_email=escape_rc_string(fetch["user_email"]),
|
||||
protocol=fetch["protocol"],
|
||||
host=escape_rc_string(fetch["host"]),
|
||||
port=fetch["port"],
|
||||
smtphost=smtphostport,
|
||||
smtphost=smtphostport if fetch['scan'] else lmtphostport,
|
||||
username=escape_rc_string(fetch["username"]),
|
||||
password=escape_rc_string(fetch["password"]),
|
||||
options=options
|
||||
options=options,
|
||||
folders=folders,
|
||||
lmtp='' if fetch['scan'] else 'lmtp',
|
||||
)
|
||||
if debug:
|
||||
print(fetchmailrc)
|
||||
@ -86,14 +103,21 @@ def run(debug):
|
||||
user_info in error_message):
|
||||
print(error_message)
|
||||
finally:
|
||||
requests.post("http://" + os.environ.get("HOST_ADMIN", "admin") + "/internal/fetch/{}".format(fetch["id"]),
|
||||
json=error_message.split("\n")[0]
|
||||
requests.post("http://{}/internal/fetch/{}".format(os.environ['ADMIN_ADDRESS'],fetch['id']),
|
||||
json=error_message.split('\n')[0]
|
||||
)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
id_fetchmail = getpwnam('fetchmail')
|
||||
Path('/data/fetchids').touch()
|
||||
os.chown("/data/fetchids", id_fetchmail.pw_uid, id_fetchmail.pw_gid)
|
||||
os.chown("/data/", id_fetchmail.pw_uid, id_fetchmail.pw_gid)
|
||||
os.chmod("/data/fetchids", 0o700)
|
||||
os.setgid(id_fetchmail.pw_gid)
|
||||
os.setuid(id_fetchmail.pw_uid)
|
||||
while True:
|
||||
delay = int(os.environ.get("FETCHMAIL_DELAY", 60))
|
||||
print("Sleeping for {} seconds".format(delay))
|
||||
|
@ -157,8 +157,11 @@ services:
|
||||
env_file: {{ env }}
|
||||
volumes:
|
||||
- "{{ root }}/data/fetchmail:/data"
|
||||
{% if resolver_enabled %}
|
||||
depends_on:
|
||||
- admin
|
||||
- smtp
|
||||
- imap
|
||||
{% if resolver_enabled %}
|
||||
- resolver
|
||||
dns:
|
||||
- {{ dns }}
|
||||
@ -168,7 +171,7 @@ services:
|
||||
# Webmail
|
||||
{% if webmail_type != 'none' %}
|
||||
webmail:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}{{ webmail_type }}:${MAILU_VERSION:-{{ version }}}
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}webmail:${MAILU_VERSION:-{{ version }}}
|
||||
restart: always
|
||||
env_file: {{ env }}
|
||||
volumes:
|
||||
|
@ -119,7 +119,7 @@ services:
|
||||
|
||||
{% if webmail_type != 'none' %}
|
||||
webmail:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}{{ webmail_type }}:${MAILU_VERSION:-{{ version }}}
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}webmail:${MAILU_VERSION:-{{ version }}}
|
||||
env_file: {{ env }}
|
||||
volumes:
|
||||
- "{{ root }}/webmail:/data"
|
||||
|
@ -36,8 +36,7 @@ group "default" {
|
||||
"imap",
|
||||
"smtp",
|
||||
|
||||
"snappymail",
|
||||
"roundcube",
|
||||
"webmail",
|
||||
|
||||
"antivirus",
|
||||
"fetchmail",
|
||||
@ -172,24 +171,15 @@ target "smtp" {
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
# Webmail images
|
||||
# Webmail image
|
||||
# -----------------------------------------------------------------------------------------
|
||||
target "snappymail" {
|
||||
target "webmail" {
|
||||
inherits = ["defaults"]
|
||||
context = "webmails/snappymail/"
|
||||
context = "webmails/"
|
||||
contexts = {
|
||||
base = "target:base"
|
||||
}
|
||||
tags = tag("snappymail")
|
||||
}
|
||||
|
||||
target "roundcube" {
|
||||
inherits = ["defaults"]
|
||||
context = "webmails/roundcube/"
|
||||
contexts = {
|
||||
base = "target:base"
|
||||
}
|
||||
tags = tag("roundcube")
|
||||
tags = tag("webmail")
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
@ -1,106 +0,0 @@
|
||||
# This file is auto-generated by the Mailu configuration wizard.
|
||||
# Please read the documentation before attempting any change.
|
||||
# Generated for compose flavor
|
||||
|
||||
version: '3.6'
|
||||
|
||||
services:
|
||||
|
||||
# External dependencies
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- "/mailu/redis:/data"
|
||||
|
||||
# Core services
|
||||
front:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
logging:
|
||||
driver: json-file
|
||||
ports:
|
||||
- "127.0.0.1:80:80"
|
||||
- "127.0.0.1:443:443"
|
||||
- "127.0.0.1:25:25"
|
||||
- "127.0.0.1:465:465"
|
||||
- "127.0.0.1:587:587"
|
||||
- "127.0.0.1:110:110"
|
||||
- "127.0.0.1:995:995"
|
||||
- "127.0.0.1:143:143"
|
||||
- "127.0.0.1:993:993"
|
||||
volumes:
|
||||
- "/mailu/certs:/certs"
|
||||
|
||||
admin:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}admin:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
||||
- "/mailu/data:/data"
|
||||
- "/mailu/dkim:/dkim"
|
||||
depends_on:
|
||||
- redis
|
||||
- resolver
|
||||
dns:
|
||||
- 192.168.203.254
|
||||
|
||||
imap:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}dovecot:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
||||
- "/mailu/mail:/mail"
|
||||
- "/mailu/overrides:/overrides"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
smtp:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}postfix:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
||||
- "/mailu/overrides:/overrides"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
antispam:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}rspamd:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
||||
- "/mailu/filter:/var/lib/rspamd"
|
||||
- "/mailu/dkim:/dkim"
|
||||
- "/mailu/overrides/rspamd:/etc/rspamd/override.d"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
# Optional services
|
||||
|
||||
resolver:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}unbound:${MAILU_VERSION:-local}
|
||||
env_file: mailu.env
|
||||
restart: always
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 192.168.203.254
|
||||
|
||||
# Webmail
|
||||
webmail:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}snappymail:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
||||
- "/mailu/webmail:/data"
|
||||
depends_on:
|
||||
- imap
|
||||
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 192.168.203.0/24
|
@ -1,138 +0,0 @@
|
||||
# Mailu main configuration file
|
||||
#
|
||||
# Generated for compose flavor
|
||||
#
|
||||
# This file is autogenerated by the configuration management wizard.
|
||||
# For a detailed list of configuration variables, see the documentation at
|
||||
# https://mailu.io
|
||||
|
||||
###################################
|
||||
# Common configuration variables
|
||||
###################################
|
||||
|
||||
# Set this to the path where Mailu data and configuration is stored
|
||||
# This variable is now set directly in `docker-compose.yml by the setup utility
|
||||
# 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=V5J4SHRYVW9PZIQU
|
||||
|
||||
# Address where listening ports should bind
|
||||
# This variables are now set directly in `docker-compose.yml by the setup utility
|
||||
# PUBLIC_IPV4= 127.0.0.1 (default: 127.0.0.1)
|
||||
# PUBLIC_IPV6= (default: ::1)
|
||||
|
||||
# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
|
||||
SUBNET=192.168.203.0/24
|
||||
|
||||
# Main mail domain
|
||||
DOMAIN=mailu.io
|
||||
|
||||
# Hostnames for this server, separated with comas
|
||||
HOSTNAMES=localhost
|
||||
|
||||
# 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=false
|
||||
|
||||
# Choose which webmail to run if any (values: roundcube, snappymail, none)
|
||||
WEBMAIL=snappymail
|
||||
|
||||
# Dav server implementation (value: radicale, none)
|
||||
WEBDAV=none
|
||||
|
||||
# Antivirus solution (value: clamav, none)
|
||||
#ANTIVIRUS=none
|
||||
|
||||
#Antispam solution
|
||||
ANTISPAM=none
|
||||
|
||||
###################################
|
||||
# Mail settings
|
||||
###################################
|
||||
|
||||
# Message size limit in bytes
|
||||
# Default: accept messages up to 50MB
|
||||
MESSAGE_SIZE_LIMIT=50000000
|
||||
|
||||
# Networks granted relay permissions
|
||||
# Use this with care, all hosts in this networks will be able to send mail without authentication!
|
||||
RELAYNETS=
|
||||
|
||||
# Will relay all outgoing mails if configured
|
||||
RELAYHOST=
|
||||
|
||||
# Fetchmail delay
|
||||
FETCHMAIL_DELAY=600
|
||||
|
||||
# Recipient delimiter, character used to delimiter localpart from custom address part
|
||||
RECIPIENT_DELIMITER=+
|
||||
|
||||
# DMARC rua and ruf email
|
||||
DMARC_RUA=admin
|
||||
DMARC_RUF=admin
|
||||
|
||||
|
||||
# Maildir Compression
|
||||
# choose compression-method, default: none (value: gz, bz2, lz4, zstd)
|
||||
COMPRESSION=
|
||||
# change compression-level, default: 6 (value: 1-9)
|
||||
COMPRESSION_LEVEL=
|
||||
|
||||
###################################
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
###################################
|
||||
# Advanced settings
|
||||
###################################
|
||||
|
||||
# Log driver for front service. Possible values:
|
||||
# json-file (default)
|
||||
# journald (On systemd platforms, useful for Fail2Ban integration)
|
||||
# syslog (Non systemd platforms, Fail2Ban integration. Disables `docker-compose log` for front!)
|
||||
# LOG_DRIVER=json-file
|
||||
|
||||
# Docker-compose project name, this will prepended to containers names.
|
||||
COMPOSE_PROJECT_NAME=mailu
|
||||
|
||||
# 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=
|
||||
|
||||
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
|
||||
REJECT_UNLISTED_RECIPIENT=
|
10
tests/compose/webmail/01_ensure_admin_unreachable.sh
Executable file
10
tests/compose/webmail/01_ensure_admin_unreachable.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
IP="$(docker inspect webmail_webmail_1|jq -r '.[0].NetworkSettings.Networks.webmail_default.IPAddress')"
|
||||
|
||||
MAIN_RETURN_CODE=$(curl -I -so /dev/null -w "%{http_code}" http://$IP/)
|
||||
[[ $MAIN_RETURN_CODE -ne 200 && $MAIN_RETURN_CODE -ne 302 ]] && echo "The default page of snappymail hasn't returned 200 but $MAIN_RETURN_CODE!" >>/dev/stderr && exit 1
|
||||
[[ $(curl -I -so /dev/null -w "%{http_code}" http://$IP/?admin) -ne 403 ]] && echo "The admin of snappymail is not disabled!" >>/dev/stderr && exit 1
|
||||
echo "Everything OK" >/dev/stderr
|
||||
|
||||
exit 0
|
@ -88,7 +88,7 @@ services:
|
||||
|
||||
# Webmail
|
||||
webmail:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}roundcube:${MAILU_VERSION:-local}
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}webmail:${MAILU_VERSION:-local}
|
||||
restart: always
|
||||
env_file: mailu.env
|
||||
volumes:
|
@ -54,7 +54,7 @@ DISABLE_STATISTICS=False
|
||||
ADMIN=false
|
||||
|
||||
# Choose which webmail to run if any (values: roundcube, snappymail, none)
|
||||
WEBMAIL=roundcube
|
||||
WEBMAIL=snappymail
|
||||
|
||||
# Dav server implementation (value: radicale, none)
|
||||
WEBDAV=none
|
1
towncrier/newsfragments/1231.bugfix
Normal file
1
towncrier/newsfragments/1231.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Add an option so that emails fetched with fetchmail don't go through the filters (closes #1231)
|
1
towncrier/newsfragments/2246.bugfix
Normal file
1
towncrier/newsfragments/2246.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fetchmail: Missing support for '*_ADDRESS' env vars
|
1
towncrier/newsfragments/2526.misc
Normal file
1
towncrier/newsfragments/2526.misc
Normal file
@ -0,0 +1 @@
|
||||
Upgrade Snappymail to 2.21 and merge the webmail containers
|
1
towncrier/newsfragments/711.feature
Normal file
1
towncrier/newsfragments/711.feature
Normal file
@ -0,0 +1 @@
|
||||
Allow other folders to be synced by fetchmail
|
93
webmails/Dockerfile
Normal file
93
webmails/Dockerfile
Normal file
@ -0,0 +1,93 @@
|
||||
# syntax=docker/dockerfile-upstream:1.4.3
|
||||
|
||||
FROM base
|
||||
|
||||
ARG VERSION
|
||||
LABEL version=$VERSION
|
||||
|
||||
COPY snappymail/pubkey.asc /tmp/snappymail.asc
|
||||
COPY roundcube/pubkey.asc /tmp/roundcube.asc
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; apk add --no-cache \
|
||||
nginx gpg gpg-agent \
|
||||
php81 php81-fpm php81-mbstring php81-zip php81-xml php81-simplexml php81-pecl-apcu \
|
||||
php81-dom php81-curl php81-exif gd php81-gd php81-iconv php81-intl php81-openssl \
|
||||
php81-pdo_sqlite php81-pdo_mysql php81-pdo_pgsql php81-pdo php81-sodium libsodium php81-tidy php81-pecl-uuid \
|
||||
php81-pspell php81-pecl-imagick php81-opcache php81-session php81-sockets php81-fileinfo \
|
||||
aspell-uk aspell-ru aspell-fr aspell-de aspell-en \
|
||||
; rm /etc/nginx/http.d/default.conf \
|
||||
; rm /etc/php81/php-fpm.d/www.conf \
|
||||
; ln -s /usr/bin/php81 /usr/bin/php \
|
||||
; gpg --import /tmp/snappymail.asc \
|
||||
; gpg --import /tmp/roundcube.asc \
|
||||
; mkdir -p /run/nginx \
|
||||
; mkdir -p /conf
|
||||
|
||||
# roundcube
|
||||
ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.3/roundcubemail-1.5.3-complete.tar.gz
|
||||
ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.4.3/carddav-v4.4.3.tar.gz
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; cd /var/www \
|
||||
; curl -sLo /dev/shm/roundcube.tgz ${ROUNDCUBE_URL} \
|
||||
; curl -sLo /dev/shm/roundcube.tgz.asc ${ROUNDCUBE_URL}.asc \
|
||||
; gpg --status-fd 1 --verify /dev/shm/roundcube.tgz.asc \
|
||||
; tar xzf /dev/shm/roundcube.tgz \
|
||||
; curl -sL ${CARDDAV_URL} | tar xz \
|
||||
; mv roundcubemail-* roundcube \
|
||||
; mkdir -p /var/www/roundcube/config \
|
||||
; mv carddav roundcube/plugins/ \
|
||||
; cd roundcube \
|
||||
; rm -rf CHANGELOG.md SECURITY.md INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \
|
||||
; ln -sf index.php /var/www/roundcube/public_html/sso.php \
|
||||
; rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query}
|
||||
|
||||
COPY roundcube/config/config.inc.php /conf/
|
||||
COPY roundcube/login/mailu.php /var/www/roundcube/plugins/mailu/
|
||||
COPY roundcube/config/config.inc.carddav.php /var/www/roundcube/plugins/carddav/config.inc.php
|
||||
|
||||
# snappymail
|
||||
|
||||
ENV SNAPPYMAIL_URL https://github.com/the-djmaze/snappymail/releases/download/v2.21.3/snappymail-2.21.3.tar.gz
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; mkdir /var/www/snappymail \
|
||||
; cd /var/www/snappymail \
|
||||
; curl -sLo /dev/shm/snappymail.tgz ${SNAPPYMAIL_URL} \
|
||||
; curl -sLo /dev/shm/snappymail.tgz.asc ${SNAPPYMAIL_URL}.asc \
|
||||
; gpg --status-fd 1 --verify /dev/shm/snappymail.tgz.asc \
|
||||
; tar xzf /dev/shm/snappymail.tgz
|
||||
|
||||
# SnappyMail login
|
||||
COPY snappymail/login/include.php /var/www/snappymail/
|
||||
COPY snappymail/login/sso.php /var/www/snappymail/
|
||||
|
||||
# Parsed and moved at startup
|
||||
COPY snappymail/defaults/application.ini /defaults/
|
||||
COPY snappymail/defaults/default.json /defaults/
|
||||
|
||||
# set perms
|
||||
RUN set -euxo pipefail \
|
||||
; chmod -R a+rX /var/www/snappymail \
|
||||
; chown -R root:root /var/www/snappymail \
|
||||
; chown -R mailu:mailu /var/www/snappymail/data \
|
||||
; chown -R root:root /var/www/roundcube/ \
|
||||
; chown -R mailu:mailu /var/www/roundcube/temp /var/www/roundcube/logs \
|
||||
; chmod -R a+rX /var/www/roundcube
|
||||
|
||||
# common
|
||||
COPY start.py /
|
||||
COPY php.ini /defaults/
|
||||
COPY php-webmail.conf /etc/php81/php-fpm.d/
|
||||
COPY nginx-webmail.conf /conf/
|
||||
|
||||
EXPOSE 80/tcp
|
||||
VOLUME /data
|
||||
VOLUME /overrides
|
||||
|
||||
CMD /start.py
|
||||
|
||||
HEALTHCHECK CMD curl -f -L http://localhost/ping || exit 1
|
||||
|
||||
RUN echo $VERSION >> /version
|
@ -2,7 +2,11 @@ server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
root /var/www/webmail;
|
||||
{% if WEBMAIL == 'roundcube' %}
|
||||
root /var/www/{{ WEBMAIL }}/public_html;
|
||||
{% else %}
|
||||
root /var/www/{{ WEBMAIL }};
|
||||
{% endif %}
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
@ -16,6 +20,11 @@ server {
|
||||
|
||||
# set maximum body size to configured limit
|
||||
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
add_header X-Download-Options "noopen" always;
|
||||
add_header X-Robots-Tag "none" always;
|
||||
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
||||
add_header Referrer-Policy "no-referrer" always;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php$args;
|
||||
@ -42,11 +51,11 @@ server {
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
location ~ (^|/)\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ^~ /data {
|
||||
location ~* /(config|temp|logs|data) {
|
||||
deny all;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
; Start a new pool named 'roundcube'.
|
||||
; Start a new pool named 'php'.
|
||||
; the variable $pool can be used in any directive and will be replaced by the
|
||||
; pool name ('roundcube' here)
|
||||
[roundcube]
|
||||
; pool name ('php' here)
|
||||
[php]
|
||||
|
||||
; Redirect worker stdout and stderr into main error log. If not set, stdout and
|
||||
; stderr will be redirected to /dev/null according to FastCGI specs.
|
||||
@ -11,8 +11,8 @@ catch_workers_output = 1
|
||||
; Unix user/group of processes
|
||||
; Note: The user is mandatory. If the group is not set, the default user's group
|
||||
; will be used.
|
||||
user = nginx
|
||||
group = nginx
|
||||
user = mailu
|
||||
group = mailu
|
||||
|
||||
; The address on which to accept FastCGI requests.
|
||||
; Valid syntaxes are:
|
@ -2,7 +2,12 @@ expose_php=Off
|
||||
date.timezone={{ TZ }}
|
||||
upload_max_filesize = {{ MAX_FILESIZE }}M
|
||||
post_max_size = {{ MAX_FILESIZE }}M
|
||||
suhosin.session.encrypt=Off
|
||||
session.auto_start=Off
|
||||
mbstring.func_overload=Off
|
||||
file_uploads=On
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE
|
||||
display_errors=Off
|
||||
log_errors=On
|
||||
zlib.output_compression=Off
|
||||
access.log = /dev/fd/2
|
||||
error_log = /dev/fd/2
|
@ -1,58 +0,0 @@
|
||||
# syntax=docker/dockerfile-upstream:1.4.3
|
||||
|
||||
#roundcube image
|
||||
FROM base
|
||||
|
||||
ARG VERSION
|
||||
LABEL version=$VERSION
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; apk add --no-cache \
|
||||
nginx gpg gpg-agent \
|
||||
php81 php81-fpm php81-mbstring php81-zip php81-xml php81-simplexml \
|
||||
php81-dom php81-curl php81-exif gd php81-gd php81-iconv php81-intl php81-openssl \
|
||||
php81-pdo_sqlite php81-pdo_mysql php81-pdo_pgsql php81-pdo php81-sodium libsodium php81-tidy php81-pecl-uuid \
|
||||
php81-pspell php81-pecl-imagick php81-opcache php81-session php81-sockets php81-fileinfo \
|
||||
; rm /etc/nginx/http.d/default.conf \
|
||||
; rm /etc/php81/php-fpm.d/www.conf \
|
||||
; ln -s /usr/bin/php81 /usr/bin/php \
|
||||
; mkdir -p /run/nginx \
|
||||
; mkdir -p /conf
|
||||
|
||||
ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.3/roundcubemail-1.5.3-complete.tar.gz
|
||||
ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.4.3/carddav-v4.4.3.tar.gz
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; cd /var/www \
|
||||
; curl -sL ${ROUNDCUBE_URL} | tar xz \
|
||||
; curl -sL ${CARDDAV_URL} | tar xz \
|
||||
; mv roundcubemail-* webmail \
|
||||
; mkdir -p /var/www/webmail/config \
|
||||
; mv carddav webmail/plugins/ \
|
||||
; cd webmail \
|
||||
; rm -rf CHANGELOG.md SECURITY.md INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \
|
||||
; ln -sf index.php /var/www/webmail/sso.php \
|
||||
; chmod -R u+w,a+rX /var/www/webmail \
|
||||
; chown -R nginx:nginx /var/www/webmail \
|
||||
; rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query}
|
||||
|
||||
|
||||
# nginx / PHP config files
|
||||
COPY config/nginx-roundcube.conf /conf/
|
||||
COPY config/php-roundcube.conf /etc/php81/php-fpm.d/roundcube.conf
|
||||
COPY config/php.ini /conf/
|
||||
COPY config/config.inc.php /conf/
|
||||
COPY login/mailu.php /var/www/webmail/plugins/mailu/
|
||||
COPY config/config.inc.carddav.php /var/www/webmail/plugins/carddav/config.inc.php
|
||||
|
||||
COPY start.py /
|
||||
|
||||
EXPOSE 80/tcp
|
||||
VOLUME /data
|
||||
VOLUME /overrides
|
||||
|
||||
CMD /start.py
|
||||
|
||||
HEALTHCHECK CMD curl -f -L http://localhost/ping || exit 1
|
||||
|
||||
RUN echo $VERSION >> /version
|
@ -4,7 +4,7 @@ $config = array();
|
||||
|
||||
// Generals
|
||||
$config['db_dsnw'] = '{{ DB_DSNW }}';
|
||||
$config['temp_dir'] = '/tmp/';
|
||||
$config['temp_dir'] = '/dev/shm/';
|
||||
$config['des_key'] = '{{ SECRET_KEY }}';
|
||||
$config['cipher_method'] = 'AES-256-CBC';
|
||||
$config['identities_level'] = 0;
|
||||
|
@ -1,63 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
root /var/www/webmail;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
# /dev/stdout (Default), <path>, off
|
||||
access_log off;
|
||||
|
||||
# /dev/stderr (Default), <path>, debug, info, notice, warn, error, crit, alert, emerg
|
||||
error_log /dev/stderr notice;
|
||||
|
||||
index index.php;
|
||||
|
||||
# set maximum body size to configured limit
|
||||
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php$args;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include /etc/nginx/fastcgi_params;
|
||||
|
||||
fastcgi_intercept_errors on;
|
||||
fastcgi_index index.php;
|
||||
|
||||
fastcgi_keep_conn on;
|
||||
|
||||
fastcgi_pass unix:/var/run/php8-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
{% if WEB_WEBMAIL == '/' %}
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
{% else %}
|
||||
fastcgi_param SCRIPT_NAME {{WEB_WEBMAIL}}/$fastcgi_script_name;
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ^~ /data {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location = /ping {
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all;
|
||||
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_pass unix:/var/run/php8-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
}
|
@ -18,13 +18,6 @@ class mailu extends rcube_plugin
|
||||
$args['action'] = 'login';
|
||||
}
|
||||
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
$ra = $_SERVER['REMOTE_ADDR'];
|
||||
if ($ua == 'health' and ($ra == '127.0.0.1' or $ra == '::1')) {
|
||||
print('OK');
|
||||
exit();
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
@ -35,7 +28,7 @@ class mailu extends rcube_plugin
|
||||
header('HTTP/1.0 403 Forbidden');
|
||||
print('mailu sso failure');
|
||||
} else {
|
||||
header('Location: sso.php');
|
||||
header('Location: sso.php', 302);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
@ -54,19 +47,19 @@ class mailu extends rcube_plugin
|
||||
{
|
||||
$this->load_config();
|
||||
$sso_logout_url = rcmail::get_instance()->config->get('sso_logout_url');
|
||||
header('Location: ' . $sso_logout_url, true);
|
||||
header('Location: ' . $sso_logout_url, true, 302);
|
||||
exit();
|
||||
}
|
||||
|
||||
function login($args)
|
||||
{
|
||||
header('Location: index.php');
|
||||
header('Location: index.php', 302);
|
||||
exit();
|
||||
}
|
||||
|
||||
function login_failed($args)
|
||||
{
|
||||
header('Location: sso.php');
|
||||
header('Location: sso.php', 302);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
102
webmails/roundcube/pubkey.asc
Normal file
102
webmails/roundcube/pubkey.asc
Normal file
@ -0,0 +1,102 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFcNX2kBEACmCY1yOI8MUk0fHtMOqxzDwA/CH0yN2nQu/mNiwOzx9pCtpX2u
|
||||
F//FAql2Ob8ZVpwichouC//y7+dpqhzF+1TQYKZP9wtR4f5Y5T4SEDMGS+mhsdvO
|
||||
LBSSpbteLtwbWrWU7CGTx6ohGO15VYfLagVKUvKkslSXFgWAfH+VrD1x05AlNeio
|
||||
rgbdHLZsh5+JhqiyOMg8lsLkUA5mwe75TLjMF7xS3BKqBlnE7grWUfBs3/5vhIiu
|
||||
/vsmnLX98tbBk6ZY+FB0xuzqiA8rW1LCB0d8eIBHnU1Xi0n1ebEG2xqtxV2Kprvj
|
||||
NZDIZfOrTRqoP0fe36PxWXGHoR7tntWyqXfC3ZWgw00S7wrp0f3YZAASVbj2863i
|
||||
gMs06zSHhVKnKqo6r+eDRcie+CRvtRVlh3PKaluh1ea+ad8A3BK1F8MKEpm3zBAn
|
||||
/RP+p0ZNa0K3IDkuacG/yJ8f+VAeJl5KYu6Uv3+jADbCUuZFbm8ZGDoT1qcxkATd
|
||||
S35D26oe41STPRUMppb+aJFMbgFLQLE5lHPEROUG1I5trrV9cfi5zP4G1A9bc9Cj
|
||||
B9m5kyz5tmST1WVYB2yFsngYCIRx2sbQwAY8z2JThTUUWL6KaJuwcFXInGQqjUU1
|
||||
GJHBGED0lduVnK3WgVKNLthABFMXJ34dzxPsiAJ68295OhUP9G4Qvo5DzQARAQAB
|
||||
tClSb3VuZGN1YmUgRGV2ZWxvcGVycyA8ZGV2c0Byb3VuZGN1YmUubmV0PokCOQQT
|
||||
AQgAIwUCVw1faQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEFqyuqFB
|
||||
xPfVN3IP/2ANH6mgd66Acz7AuUp9YhZ6A00VkrGfmdju9aA8LuEBdt2dUyUIvzzm
|
||||
BqKbIfotbpn7lpJsDRV2L2alDUL0fvVcuH6vy1u/LrAOVXPuE0ACyRuwBIzmKV8g
|
||||
iJYES5FOVVfjZh/k+rdWDj654ohOyQxPYiW/213/MNonbgodXk5H+jTMGxsVJHhi
|
||||
VyRwiwzkFV9qozb+R/fCirCayHL6v0A0HWtAwXbHabZUoHXEY/XtQFnvEw1HR3u5
|
||||
1nIl17ClaKtoOeXh35ONXqu27Xzxw/skqOVUj3LNzZN7IhR4PzKaTCg4g6n1ngyU
|
||||
VgrXIS6JLwLSyyurkdGCIKifW/5BqmikXdp6oJ6x3/nDzg7IzpEbipetiYsVVjZG
|
||||
aZkuATC+Pj/kW/AmWYX9vxxEDnVEu6r71zMWIqiEzu+8JoO2IvvuU5tvbbMhRze7
|
||||
/tc/WxZSYOzaudb6Bi/4FX2x8l6FGiIP/xI6Gpyjd5HwRWYnUqv7pBqyzs0Z15vG
|
||||
roYcayLaFAhLCxBnBhUVbwVoRif4h9ihPc6PndZp/nOIAOpNGVqZbXcoXjz+Ugvb
|
||||
icGKul/q7t1vl+3cf0bBT8O918TvzVXJIixnW/f9rdPAGT0KtsE7B7UXxOkV3xpC
|
||||
uh+kA0W8huJLaEWFZ5izBixkhzdLwITJD2VQ/TVuwHSI2A4kFnF5iQIiBBMBCAAM
|
||||
BQJXDWCdBYMHhh+AAAoJED5UKNAmLFT4KOoQAJ7qQ25imKrnebNVQ7unSCDIcZ7n
|
||||
wc7MGlOCmO0txGtDgaVZy2pvBd/zIliYtrGkbkDpMTTVds73/XofLJ+n41nNLPI7
|
||||
jDdVOnYpcu2bj74KUQRY+2WQ6riewsFUF52FtNOegsIj8JXmK58CPoW3M/uVZRdf
|
||||
ISVAUHkQuP9YWJoeToB/RXqICCRX3DfUgFSbHaEVRqpln+mnljopNBrDMe9ZthC2
|
||||
6Py8HwhshtBiwcP9NlaGTeG+Ks2A7Ujt2BUgBWyN4ouf8ehmyjD5D9RCxjPh7lof
|
||||
Ap8JhGpbd8Yu97Ax8bwZcHZ1ePx9NxcC+PFf6wK3jK464Vx7JTKk4gS3Ktk/+adA
|
||||
b9dasn+/OOaWwzHkpBTUJP7gW1pv8xhA+Op2VqwRNqB2WfiqOHyydQSZKJVncdA6
|
||||
/p3p4ABluPtbe8L1SE0ZDEOGjXwTMxH3ssDLlQ4BlqlWzhudeNv9Tizd8tlgtBvg
|
||||
VprEpWd++JovQs8MmEcoLaDS1DSglEsoRnrpCJ1vkacQZlN2wpv7PEEmH8SBaYU7
|
||||
xRZhRmc1arRFnelVo4OPzLTSMSFjZIdmMs8Lfzrw2fRGesrJGpb3DnVphwML1aXp
|
||||
mSFHKuXDqDVMW+Ey437KadG/Bd92q4FEeyCjjoHYa2C86dZG1yMfuVVMfvVz0A+v
|
||||
lSR6abLAK3f+VO1piQEcBBMBAgAGBQJXGG4NAAoJEL7mdKAZNZ3BLmkH/i03cRxM
|
||||
WU9baZgpZ7IkIz77tJJdcW51dZKy04FhbFKH6Qlp6WcGHEPy6EZWRdktJlSXTc+T
|
||||
/1lhlXeRPGesqvIAqnDfOayKf2rihBoAfPQCzxaJOAldt0KdDX6zGIYa4Xqappla
|
||||
kPLHeCSKhGm8eYf7IQjiq3AoMRvtGDtv8ygrA7sN8vc7Ftr1fg3s8UaB8QULLRD4
|
||||
INRgxfuPG9St5V5zYV/3Xf/61uOlNfxxikx5PCHle4jKJGkP+smXON4l8+XPyhSG
|
||||
US7aIGalr58acv0VZHFkTaCi+96s14df0XRENO5D4l5n18PiHQvh/th995ba96K/
|
||||
8jrcY7f8wjM0OYm5Ag0EVw1faQEQAPII9TY0LeEWP+4/FFQCBmgXR+aWjMK0O3fa
|
||||
BuPzL/VVHQJ3i41PvvP+Osb7BYPFTxPWkvVF2J1bLZfH1wFq+hMfEOkGMGtBFOP2
|
||||
VxWEYxMondktMhKDHT5EppPwqsZYPqlNz6Sk/bW81IXKtSG/hvPyBDv1+GaHZlz+
|
||||
NJrKjVlBN+6U4noM2P9n/QPCd5VmkZMWzCfbtmGZKHspOJswMhcW28YvMmYTK+0b
|
||||
ZcKCs2S2wgfM8d5EEeoYTXH6PqxfW3ezZXQ5ieM1sub59GnS+7gqxPEs+LyVQtxT
|
||||
7dgCnZQ73tmQP3pG2Zx0pKQHK/hZk8R6aEaYtV1QlfUI1TMG1eH+xHXGSWFnCbiX
|
||||
cGLltaLFBX11+qwF50FfYu8MRUM9rKW+ms2wBVmHuSGKgn0lglBGU2s/pPPw6Alu
|
||||
GWa289vGdnztoQyY33L3u/la0wCBbM/8JxZYZdmTq1iL0oYuPbn3axfa6JCX9CwC
|
||||
KQjOcJe8K+scRsSFI23M3ZySVgKpkOdhz9VfBZHTqMpbsTd8kNHBDu5J3C0v2NsV
|
||||
gJsqI5c3cVtaGPL2NVdfjZ668aXs89JA0Sc9Q1ppiDQX2ArNbq0ZRG4pGfAP3zA9
|
||||
6RyfHTgM9PZ5M4BReeWJCYQb6UI8Uw/NlUYsMMMbi8yqhIkXCY0U7I0ZKtVUSHSR
|
||||
W6gftdEhABEBAAGJAh8EGAEIAAkFAlcNX2kCGwwACgkQWrK6oUHE99XmpA/5AXxm
|
||||
SfeyUcUUaMH+n1EJt7lH6u8Tg4WxoSpSoF/GrArEBfdDGmUog2kR8cgyTFKjtiuP
|
||||
icCIapeezP2QMxWfm0TTITtFiHAUJZn0642SY4uXI/73Bwa0r5Vi1UevaFrRPkee
|
||||
0Jt3Tg45nvkUNQBuRK81Wr2o+EuNiMgssd78MHiWjllVptFg0GnfE1VUeMeM8Rwa
|
||||
QnVzVyYZbqe4jL20+QCba/zyrcQgcxZ/gtojADpPHojI2BQlsXnIhrSlXYXIDhmF
|
||||
SCG4+RdUq+JVI8vjO42bHA51gGyvZR7Fh7tcdU++U6wbhF5gkzB3v+NjHxwmcI/t
|
||||
pnrTP7nT1rZOUdyuKSJkcCUa3l8u+bqlxgQ3r+PJOXuW5Tn53HYkxdTSgzFwc9GS
|
||||
SvyTZnz/JYE241Yf14Vjn8fZqPsN+uplc4b42G08gQi0Juni7W5dPo3Jl+7MgXJR
|
||||
0vBtCEuZLJ49ZUpKwf0vS1aDDfMNA4ESs/TagIakUMGNH0tVsEm5YNMoNx9qZA3a
|
||||
rJT+ZhpZNFBW94QU3hQ+hbtyR/0rO8BGlpA0XLhNoPUNhgWMobgWAIA9kEQilm1Y
|
||||
tPDS5EHhsAiLi60/bIuti4T0nhxlgw+yfeb5kEnm5v5XYSj5w0XzfyGirfV80QP4
|
||||
7CE8GKy2q+e3xau15t/eVvMtYd2RDgykqIjvwtC5Ag0EVw1f/QEQAO2JeXBrzcBt
|
||||
TeUcPA70W9quirv4wnXtUTwAGRXklK/OaKPruPTPJIQu6qdimJO+p6KbWP4mD8b9
|
||||
t7mWilDpJO3omZKqMqCRqd+TPp0rzvHde1QhwCNIByCIkrTjcsq2JuGTSEME09Aa
|
||||
nOTE5/UeThTeXI+xvta63kpHgBolBunMUwPlde36KOUgWktr6NiCr3CQ1MtzDuBl
|
||||
wEAi1/K8/mkIU5SXmmC7NOKQVsK/HCpuhkT0fZY4RGIHlauIiOs8vXvJ9kajkvF+
|
||||
HJcmsQ/8GuMELVKi/V9BnObCCL49EykK5s5VEF4guQ4r3ElbS/PXvE4OXL+0vmBR
|
||||
YQFdVUdHNS36LErGzYIgghQIgDF1JS08EuoD86+fVHwwbupCp9SMQRWjrvWroipG
|
||||
Sk6K3BJfM9deZhuMH2j2ab4OleHZdJH+4PLIa+NwXMhuvKPJPKXmP5c1Seu7AyON
|
||||
hUQEU/lHEW03NvS4nh/ArM/za+dFplzSSaoUq8Qhr3AeyAVd+4PXgpbj7pIdfaBI
|
||||
IADx/uFYLLcc/whD/2C2t37h3TIjR18IS05aiGHDJyZ9eV2K/wf8kZ7Xq4ix+6Or
|
||||
Jt37g2/klHsvHo3kb+6XPpo263+pRj/bcA2vUA3c26cZ8nCsHu9K4aN4VN8DTTPS
|
||||
YYT9940OfRh8CRCNlcVerfbjNAE3fgnbABEBAAGJBD4EGAEIAAkFAlcNX/0CGwIC
|
||||
KQkQWrK6oUHE99XBXSAEGQEIAAYFAlcNX/0ACgkQwpRqlgnNVrRIXRAA48pg+pQG
|
||||
aqghqsVPtRt4yZy3zc0RDr5vV3r00Tqutg7l1J/8gNm9NayyBX0BEY+bKvNPeNjl
|
||||
gNkXCSH7eXX1mvUJuUUnbqJv+MT3roCcvLz6KLdQQdHarJSs4LmqF9/4NfHsSecg
|
||||
jq3Y9fsG5sNf/a7BraIcdlOq92t0DlpAmAtm10ywUXJPc1uAxqd/2QyfuPQE/eoR
|
||||
rmGnKR1W6FO1cAZYVWd3hyPAyr/EHHJonycpp8CKCe9CLu3iFXR8+GVq7ZiDVNk+
|
||||
MHMYg1Njfk3TY/UEUGXqFfTsD47S8fqEV/koWSSxTkSwPjwVP1z0yu9cV87ULeJN
|
||||
LDdwyFvmTrQv71YkAD12CchRymqLxtItSF1QMiHBFXTICreYGk41pS89KNshgFpe
|
||||
WfRq6WpPegUj1qdM/GJuBvSu7CTT2mpQQNk4maIIeUPcHRCA//H3WvXj3jMp3CFK
|
||||
S82YYDkUW/XWkWIRmpALrX8gSYlthKFf24RZZFrAd7NfSq1Hy0RjAwtm0+LsRTtT
|
||||
znzTUr2SocCEGqFjiczIJ/4zQ+25N2PPg1G5lCrIeE7VOifKD3jujMYiAEr6QUUm
|
||||
Vldw7Rn0tmJIiq0bc3MbadUxrT0PJXxOlQpfV2ZjM76gMpvvSCe6o6mckDT4sT3G
|
||||
4vfc02Pe4g4DYpVPlV/GE1T26NzK1Z3ONFzhLQ//abRaJKfy19+lNNJoGfGGLher
|
||||
AdymumxmGZf74wS6xAlP+LwJldUA8iidSxM0gR6bmw8q2SO7dqziGreaPaFVmeUB
|
||||
62rSXD0QSielIoRP1QZuD1ZO5tEZ2wxjcCnaBj2nG3bBj4RJ7FAD9CceSyPJFNYD
|
||||
n6cvslV/MGzacMtTTIwdFJmHaoU86heADWkYIFm/jndYX6b/IdJDNOYDYA4m+5S8
|
||||
ANQ3uOuaBMDo4sOAUCeophdjZeyne2kIWR7kmWis5kFf/Criy6u+yPs+a7kt+PbI
|
||||
2Uo1rmrNUiMiROkezbnZAEf/8wUi7KgRjZ6qfij/QM+0WMeUWu8NRqiS+KRLQIh7
|
||||
Y8f3u0ddlfGF7/UpAEXzv2KKpLO+SaUkvaatZucOD/hbDThqOVCtX7mQ03XTO9Pn
|
||||
SHVSxBsJse4Jn/n6oCt6FT7wMbh3IuZTeU7kiT9VO8+M/ehUS0sIbwwsYrdAT2Od
|
||||
/Txs7jWinvsuH/qsNFVDrxKKcFQi99m0Zm3IIo2DX5PUo9KvPO8xzZgFKQDOIKBw
|
||||
1PNQr0xRqbI1dsFcaN2yqF4hrYYmn4bDJCOMHV3gxltFaLU/rj7atdIWGOPzw/1N
|
||||
WQujs2OMoiJWTidcd/LTxbEvEDyS9vMiIXrAoadvRtBxmFqJfcmRhOrbKIcA4A65
|
||||
0dXJnhEe7eXkwBbfEzk=
|
||||
=lBKd
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -1,54 +0,0 @@
|
||||
# syntax=docker/dockerfile-upstream:1.4.3
|
||||
|
||||
#snappymail image
|
||||
FROM base
|
||||
|
||||
ARG VERSION
|
||||
LABEL version=$VERSION
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; apk add --no-cache \
|
||||
nginx curl \
|
||||
php81 php81-fpm php81-mbstring php81-zip php81-xml php81-simplexml \
|
||||
php81-dom php81-curl php81-exif gd php81-gd php81-iconv php81-intl php81-openssl \
|
||||
php81-pdo_sqlite php81-pdo php81-sodium libsodium php81-tidy php81-pecl-uuid \
|
||||
; ln -s /usr/bin/php81 /usr/bin/php \
|
||||
; rm /etc/nginx/http.d/default.conf \
|
||||
; rm /etc/php81/php-fpm.d/www.conf \
|
||||
; mkdir -p /run/nginx \
|
||||
; mkdir -p /var/www/webmail \
|
||||
; mkdir -p /config
|
||||
|
||||
# nginx / PHP config files
|
||||
COPY config/nginx-snappymail.conf /config/
|
||||
COPY config/php-snappymail.conf /etc/php81/php-fpm.d/snappymail.conf
|
||||
|
||||
# Parsed and moved at startup
|
||||
COPY defaults/php.ini /defaults/
|
||||
COPY defaults/application.ini /defaults/
|
||||
COPY defaults/default.ini /defaults/
|
||||
|
||||
# Install Snappymail from source
|
||||
ENV SNAPPYMAIL_URL https://github.com/the-djmaze/snappymail/releases/download/v2.19.4/snappymail-2.19.4.tar.gz
|
||||
# Note. This is the last working snappymail version. 2.19.6 up to 2.20.6 do not work.
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; cd /var/www/webmail \
|
||||
; curl -sL ${SNAPPYMAIL_URL} | tar xz \
|
||||
; chmod -R u+w,a+rX /var/www/webmail \
|
||||
; chown -R nginx:nginx /var/www/webmail
|
||||
|
||||
# SnappyMail login
|
||||
COPY login/include.php /var/www/webmail/
|
||||
COPY login/sso.php /var/www/webmail/
|
||||
|
||||
COPY start.py /
|
||||
COPY config.py /
|
||||
|
||||
EXPOSE 80/tcp
|
||||
VOLUME ["/data"]
|
||||
|
||||
CMD /start.py
|
||||
|
||||
HEALTHCHECK CMD curl -f -L http://localhost/ping || exit 1
|
||||
RUN echo $VERSION >> /version
|
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import logging as log
|
||||
import sys
|
||||
|
||||
from socrate import system, conf
|
||||
|
||||
args = os.environ.copy()
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
# Build final configuration paths
|
||||
conf.jinja("/config/nginx-snappymail.conf", args, "/etc/nginx/http.d/snappymail.conf")
|
||||
if os.path.exists("/var/run/nginx.pid"):
|
||||
os.system("nginx -s reload")
|
@ -1,118 +0,0 @@
|
||||
; Start a new pool named 'snappymail'.
|
||||
; the variable $pool can be used in any directive and will be replaced by the
|
||||
; pool name ('snappymail' here)
|
||||
[snappymail]
|
||||
|
||||
; Redirect worker stdout and stderr into main error log. If not set, stdout and
|
||||
; stderr will be redirected to /dev/null according to FastCGI specs.
|
||||
; Default value: no.
|
||||
catch_workers_output = 1
|
||||
|
||||
; Unix user/group of processes
|
||||
; Note: The user is mandatory. If the group is not set, the default user's group
|
||||
; will be used.
|
||||
user = nginx
|
||||
group = nginx
|
||||
|
||||
; The address on which to accept FastCGI requests.
|
||||
; Valid syntaxes are:
|
||||
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
|
||||
; a specific port;
|
||||
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
|
||||
; a specific port;
|
||||
; 'port' - to listen on a TCP socket to all addresses
|
||||
; (IPv6 and IPv4-mapped) on a specific port;
|
||||
; '/path/to/unix/socket' - to listen on a unix socket.
|
||||
; Note: This value is mandatory.
|
||||
listen = /var/run/php8-fpm.sock
|
||||
|
||||
; Set permissions for unix socket, if one is used. In Linux, read/write
|
||||
; permissions must be set in order to allow connections from a web server. Many
|
||||
; BSD-derived systems allow connections regardless of permissions.
|
||||
; Default Values: user and group are set as the running user
|
||||
; mode is set to 0660
|
||||
listen.owner = nginx
|
||||
listen.group = nginx
|
||||
listen.mode = 0660
|
||||
|
||||
; Choose how the process manager will control the number of child processes.
|
||||
; Possible Values:
|
||||
; static - a fixed number (pm.max_children) of child processes;
|
||||
; dynamic - the number of child processes are set dynamically based on the
|
||||
; following directives. With this process management, there will be
|
||||
; always at least 1 children.
|
||||
; pm.max_children - the maximum number of children that can
|
||||
; be alive at the same time.
|
||||
; pm.start_servers - the number of children created on startup.
|
||||
; pm.min_spare_servers - the minimum number of children in 'idle'
|
||||
; state (waiting to process). If the number
|
||||
; of 'idle' processes is less than this
|
||||
; number then some children will be created.
|
||||
; pm.max_spare_servers - the maximum number of children in 'idle'
|
||||
; state (waiting to process). If the number
|
||||
; of 'idle' processes is greater than this
|
||||
; number then some children will be killed.
|
||||
; ondemand - no children are created at startup. Children will be forked when
|
||||
; new requests will connect. The following parameter are used:
|
||||
; pm.max_children - the maximum number of children that
|
||||
; can be alive at the same time.
|
||||
; pm.process_idle_timeout - The number of seconds after which
|
||||
; an idle process will be killed.
|
||||
; Note: This value is mandatory.
|
||||
pm = ondemand
|
||||
|
||||
; The number of child processes to be created when pm is set to 'static' and the
|
||||
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
|
||||
; This value sets the limit on the number of simultaneous requests that will be
|
||||
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
|
||||
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
|
||||
; CGI. The below defaults are based on a server without much resources. Don't
|
||||
; forget to tweak pm.* to fit your needs.
|
||||
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
|
||||
; Note: This value is mandatory.
|
||||
pm.max_children = 5
|
||||
|
||||
; The number of child processes created on startup.
|
||||
; Note: Used only when pm is set to 'dynamic'
|
||||
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
|
||||
; pm.start_servers = 2
|
||||
|
||||
; The desired minimum number of idle server processes.
|
||||
; Note: Used only when pm is set to 'dynamic'
|
||||
; Note: Mandatory when pm is set to 'dynamic'
|
||||
; pm.min_spare_servers = 1
|
||||
|
||||
; The desired maximum number of idle server processes.
|
||||
; Note: Used only when pm is set to 'dynamic'
|
||||
; Note: Mandatory when pm is set to 'dynamic'
|
||||
; pm.max_spare_servers = 3
|
||||
|
||||
; This sets the maximum time in seconds a script is allowed to run before it is
|
||||
; terminated by the parser. This helps prevent poorly written scripts from tying up
|
||||
; the server. The default setting is 30s.
|
||||
; Note: Used only when pm is set to 'ondemand'
|
||||
pm.process_idle_timeout = 10s
|
||||
|
||||
; The number of requests each child process should execute before respawning.
|
||||
; This can be useful to work around memory leaks in 3rd party libraries. For endless
|
||||
; request processing specify '0'.
|
||||
; Equivalent to PHP_FCGI_MAX_REQUESTS. Default value: 0.
|
||||
; Noted: Used only when pm is set to 'ondemand'
|
||||
pm.max_requests = 200
|
||||
|
||||
; The ping URI to call the monitoring page of FPM. If this value is not set, no
|
||||
; URI will be recognized as a ping page. This could be used to test from outside
|
||||
; that FPM is alive and responding, or to
|
||||
; - create a graph of FPM availability (rrd or such);
|
||||
; - remove a server from a group if it is not responding (load balancing);
|
||||
; - trigger alerts for the operating team (24/7).
|
||||
; Note: The value must start with a leading slash (/). The value can be
|
||||
; anything, but it may not be a good idea to use the .php extension or it
|
||||
; may conflict with a real PHP file.
|
||||
; Default Value: not set
|
||||
ping.path = /ping
|
||||
|
||||
; This directive may be used to customize the response of a ping request. The
|
||||
; response is formatted as text/plain with a 200 response code.
|
||||
; Default Value: pong
|
||||
;ping.response = pong
|
@ -5,15 +5,14 @@ attachment_size_limit = {{ MAX_FILESIZE }}
|
||||
|
||||
[security]
|
||||
allow_admin_panel = Off
|
||||
openpgp = On
|
||||
|
||||
[labs]
|
||||
allow_gravatar = Off
|
||||
{% if WEB_WEBMAIL == '/' %}
|
||||
custom_login_link='sso.php'
|
||||
{% else %}
|
||||
custom_login_link='{{ WEB_WEBMAIL }}/sso.php'
|
||||
{% endif %}
|
||||
custom_logout_link='/sso/logout'
|
||||
image_exif_auto_rotate = On
|
||||
try_to_detect_hidden_images = On
|
||||
{% if WEB_WEBMAIL == '/' %}custom_login_link = "sso.php"{% else %}custom_login_link = "{{ WEB_WEBMAIL }}/sso.php"{% endif %}
|
||||
custom_logout_link = "/sso/logout"
|
||||
|
||||
[contacts]
|
||||
enable = On
|
||||
@ -21,3 +20,10 @@ allow_sync = On
|
||||
|
||||
[defaults]
|
||||
contacts_autosave = On
|
||||
|
||||
[cache]
|
||||
enable = On
|
||||
fast_cache_driver = "APCU"
|
||||
|
||||
[imap]
|
||||
use_move = On
|
||||
|
@ -1,15 +0,0 @@
|
||||
imap_host = "{{ FRONT_ADDRESS }}"
|
||||
imap_port = 10143
|
||||
imap_secure = "None"
|
||||
imap_short_login = Off
|
||||
sieve_use = On
|
||||
sieve_allow_raw = Off
|
||||
sieve_host = "{{ IMAP_ADDRESS }}"
|
||||
sieve_port = 4190
|
||||
sieve_secure = "None"
|
||||
smtp_host = "{{ FRONT_ADDRESS }}"
|
||||
smtp_port = 10025
|
||||
smtp_secure = "None"
|
||||
smtp_short_login = Off
|
||||
smtp_auth = On
|
||||
smtp_php_mail = Off
|
50
webmails/snappymail/defaults/default.json
Normal file
50
webmails/snappymail/defaults/default.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "*",
|
||||
"IMAP": {
|
||||
"host": "{{ FRONT_ADDRESS }}",
|
||||
"port": 10143,
|
||||
"secure": 0,
|
||||
"shortLogin": false,
|
||||
"ssl": {
|
||||
"verify_peer": false,
|
||||
"verify_peer_name": false,
|
||||
"allow_self_signed": false,
|
||||
"SNI_enabled": true,
|
||||
"disable_compression": true,
|
||||
"security_level": 1
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"host": "{{ FRONT_ADDRESS }}",
|
||||
"port": 10025,
|
||||
"secure": 0,
|
||||
"shortLogin": false,
|
||||
"ssl": {
|
||||
"verify_peer": false,
|
||||
"verify_peer_name": false,
|
||||
"allow_self_signed": false,
|
||||
"SNI_enabled": true,
|
||||
"disable_compression": true,
|
||||
"security_level": 1
|
||||
},
|
||||
"useAuth": true,
|
||||
"setSender": false,
|
||||
"usePhpMail": false
|
||||
},
|
||||
"Sieve": {
|
||||
"host": "{{ IMAP_ADDRESS }}",
|
||||
"port": 4190,
|
||||
"secure": 0,
|
||||
"shortLogin": false,
|
||||
"ssl": {
|
||||
"verify_peer": false,
|
||||
"verify_peer_name": false,
|
||||
"allow_self_signed": false,
|
||||
"SNI_enabled": true,
|
||||
"disable_compression": true,
|
||||
"security_level": 1
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"whiteList": ""
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
expose_php=Off
|
||||
date.timezone={{ TZ }}
|
||||
upload_max_filesize = {{ MAX_FILESIZE }}M
|
||||
post_max_size = {{ MAX_FILESIZE }}M
|
||||
|
@ -9,9 +9,9 @@ if (isset($_SERVER['HTTP_X_REMOTE_USER']) && isset($_SERVER['HTTP_X_REMOTE_USER_
|
||||
$ssoHash = \RainLoop\Api::CreateUserSsoHash($email, $password);
|
||||
|
||||
// redirect to webmail sso url
|
||||
header('Location: index.php?sso&hash='.$ssoHash);
|
||||
header('Location: index.php?sso&hash='.$ssoHash, 302);
|
||||
}
|
||||
else {
|
||||
header('HTTP/1.0 403 Forbidden');
|
||||
header('HTTP/1.0 403 Forbidden', 403);
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
11
webmails/snappymail/pubkey.asc
Normal file
11
webmails/snappymail/pubkey.asc
Normal file
@ -0,0 +1,11 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Hostname:
|
||||
Version: Hockeypuck 2.1.0-184-g50f1108
|
||||
|
||||
xjMEYg0atBYJKwYBBAHaRw8BAQdA2S2tvGavChACjtBastsKRThD3rsBW1LUZLmN
|
||||
Zbs4uaHNI1NuYXBweU1haWwgPHJlbGVhc2VzQHNuYXBweW1haWwuZXU+wpQEExYK
|
||||
ADwWIQQQFuRweRRVQvi6EzVIIIuhMpDz6wUCYg0atAIbAwULCQgHAgMiAgEGFQoJ
|
||||
CAsCBBYCAwECHgcCF4AACgkQSCCLoTKQ8+u9SAD/Q/IoAwjUkKDJBPq0RGwCFnl6
|
||||
FG/VHB97CvBSpGOxtIsBAMCwMhWlsaBHAEqbzxiN+cdlMYwV23+SWLUJ/XMFgukE
|
||||
=vC/h
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import logging as log
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
from socrate import system, conf
|
||||
|
||||
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
||||
|
||||
# Actual startup script
|
||||
os.environ["FRONT_ADDRESS"] = system.resolve_address(os.environ.get("HOST_FRONT", "front"))
|
||||
os.environ["IMAP_ADDRESS"] = system.resolve_address(os.environ.get("HOST_IMAP", "imap"))
|
||||
|
||||
os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT"))*0.66/1048576))
|
||||
|
||||
base = "/data/_data_/_default_/"
|
||||
shutil.rmtree(base + "domains/", ignore_errors=True)
|
||||
os.makedirs(base + "domains", exist_ok=True)
|
||||
os.makedirs(base + "configs", exist_ok=True)
|
||||
|
||||
conf.jinja("/defaults/default.ini", os.environ, "/data/_data_/_default_/domains/default.ini")
|
||||
conf.jinja("/defaults/application.ini", os.environ, "/data/_data_/_default_/configs/application.ini")
|
||||
conf.jinja("/defaults/php.ini", os.environ, "/etc/php81/php.ini")
|
||||
# Start the fastcgi process manager now that config files have been adjusted
|
||||
os.system("php-fpm81")
|
||||
|
||||
os.system("chown -R nginx:nginx /data")
|
||||
os.system("chmod -R a+rX /var/www/webmail/")
|
||||
|
||||
subprocess.call(["/config.py"])
|
||||
os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"])
|
@ -4,9 +4,10 @@ import os
|
||||
import logging
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import hmac
|
||||
|
||||
from socrate import conf
|
||||
from socrate import conf, system
|
||||
|
||||
env = os.environ
|
||||
|
||||
@ -17,6 +18,8 @@ context = {}
|
||||
context.update(env)
|
||||
|
||||
context["MAX_FILESIZE"] = str(int(int(env.get("MESSAGE_SIZE_LIMIT", "50000000")) * 0.66 / 1048576))
|
||||
context["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
|
||||
context["IMAP_ADDRESS"] = system.get_host_address_from_environment("IMAP", "imap")
|
||||
|
||||
db_flavor = env.get("ROUNDCUBE_DB_FLAVOR", "sqlite")
|
||||
if db_flavor == "sqlite":
|
||||
@ -52,7 +55,7 @@ context['SECRET_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUN
|
||||
|
||||
# roundcube plugins
|
||||
# (using "dict" because it is ordered and "set" is not)
|
||||
plugins = dict((p, None) for p in env.get("ROUNDCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/webmail/plugins", p)))
|
||||
plugins = dict((p, None) for p in env.get("ROUNDCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/roundcube/plugins", p)))
|
||||
if plugins:
|
||||
plugins["mailu"] = None
|
||||
else:
|
||||
@ -67,15 +70,14 @@ context["INCLUDES"] = sorted(inc for inc in os.listdir("/overrides") if inc.ends
|
||||
context["SESSION_TIMEOUT_MINUTES"] = max(int(env.get("SESSION_TIMEOUT", "3600")) // 60, 1)
|
||||
|
||||
# create config files
|
||||
conf.jinja("/conf/php.ini", context, "/etc/php81/php.ini")
|
||||
conf.jinja("/conf/config.inc.php", context, "/var/www/webmail/config/config.inc.php")
|
||||
conf.jinja("/conf/config.inc.php", context, "/var/www/roundcube/config/config.inc.php")
|
||||
|
||||
# create dirs
|
||||
os.system("mkdir -p /data/gpg")
|
||||
|
||||
print("Initializing database")
|
||||
try:
|
||||
result = subprocess.check_output(["/var/www/webmail/bin/initdb.sh", "--dir", "/var/www/webmail/SQL"],
|
||||
result = subprocess.check_output(["/var/www/roundcube/bin/initdb.sh", "--dir", "/var/www/roundcube/SQL"],
|
||||
stderr=subprocess.STDOUT)
|
||||
print(result.decode())
|
||||
except subprocess.CalledProcessError as exc:
|
||||
@ -88,22 +90,30 @@ except subprocess.CalledProcessError as exc:
|
||||
|
||||
print("Upgrading database")
|
||||
try:
|
||||
subprocess.check_call(["/var/www/webmail/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT)
|
||||
subprocess.check_call(["/var/www/roundcube/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
exit(4)
|
||||
else:
|
||||
print("Cleaning database")
|
||||
try:
|
||||
subprocess.check_call(["/var/www/webmail/bin/cleandb.sh"], stderr=subprocess.STDOUT)
|
||||
subprocess.check_call(["/var/www/roundcube/bin/cleandb.sh"], stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
exit(5)
|
||||
|
||||
base = "/data/_data_/_default_/"
|
||||
shutil.rmtree(base + "domains/", ignore_errors=True)
|
||||
os.makedirs(base + "domains", exist_ok=True)
|
||||
os.makedirs(base + "configs", exist_ok=True)
|
||||
|
||||
conf.jinja("/defaults/default.json", context, "/data/_data_/_default_/domains/default.json")
|
||||
conf.jinja("/defaults/application.ini", context, "/data/_data_/_default_/configs/application.ini")
|
||||
conf.jinja("/defaults/php.ini", context, "/etc/php81/php.ini")
|
||||
|
||||
# setup permissions
|
||||
os.system("chown -R nginx:nginx /data")
|
||||
os.system("chmod -R a+rX /var/www/webmail/")
|
||||
os.system("chown -R mailu:mailu /data")
|
||||
|
||||
# Configure nginx
|
||||
conf.jinja("/conf/nginx-roundcube.conf", context, "/etc/nginx/http.d/roundcube.conf")
|
||||
conf.jinja("/conf/nginx-webmail.conf", context, "/etc/nginx/http.d/webmail.conf")
|
||||
if os.path.exists("/var/run/nginx.pid"):
|
||||
os.system("nginx -s reload")
|
||||
|
Loading…
x
Reference in New Issue
Block a user