mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-12-25 07:47:05 +00:00
remove extra features from master branch
This commit is contained in:
parent
473d4616f2
commit
e04f358cc4
@ -1 +0,0 @@
|
|||||||
/usr/bin/doveadm fts rescan -A
|
|
@ -1,2 +0,0 @@
|
|||||||
*/1 * * * * root /usr/bin/curl http://127.0.0.1:8080/solr/update?commit=true &>/dev/null
|
|
||||||
30 3 * * * root /usr/bin/curl http://127.0.0.1:8080/solr/update?optimize=true &>/dev/null
|
|
@ -1,6 +1,5 @@
|
|||||||
## $HOSTNAME
|
## $HOSTNAME
|
||||||
|
|
||||||
#BEGIN_HTTP
|
|
||||||
# Redirect all HTTP to HTTPS *except* the ACME challenges (Let's Encrypt TLS certificate
|
# Redirect all HTTP to HTTPS *except* the ACME challenges (Let's Encrypt TLS certificate
|
||||||
# domain validation challenges) path, which must be served over HTTP per the ACME spec
|
# domain validation challenges) path, which must be served over HTTP per the ACME spec
|
||||||
# (due to some Apache vulnerability).
|
# (due to some Apache vulnerability).
|
||||||
@ -29,12 +28,11 @@ server {
|
|||||||
alias $STORAGE_ROOT/ssl/lets_encrypt/webroot/.well-known/acme-challenge/;
|
alias $STORAGE_ROOT/ssl/lets_encrypt/webroot/.well-known/acme-challenge/;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#END_HTTP
|
|
||||||
|
|
||||||
# The secure HTTPS server.
|
# The secure HTTPS server.
|
||||||
server {
|
server {
|
||||||
listen $HTTP_SSL_PORT ssl http2;
|
listen 443 ssl http2;
|
||||||
listen [::]:$HTTP_SSL_PORT ssl http2;
|
listen [::]:443 ssl http2;
|
||||||
|
|
||||||
server_name $HOSTNAME;
|
server_name $HOSTNAME;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class KeyAuthService:
|
|||||||
|
|
||||||
credentials = decode(credentials)
|
credentials = decode(credentials)
|
||||||
if ":" not in credentials:
|
if ":" not in credentials:
|
||||||
return credentials, None
|
return None, None
|
||||||
username, password = credentials.split(':', maxsplit=1)
|
username, password = credentials.split(':', maxsplit=1)
|
||||||
return username, password
|
return username, password
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import os, os.path, re, json, time
|
import os, os.path, re, json, time
|
||||||
import subprocess
|
import subprocess
|
||||||
import base64
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
@ -349,34 +347,6 @@ def dns_get_dump():
|
|||||||
from dns_update import build_recommended_dns
|
from dns_update import build_recommended_dns
|
||||||
return json_response(build_recommended_dns(env))
|
return json_response(build_recommended_dns(env))
|
||||||
|
|
||||||
@app.route('/letsencrypt/dns-auth/<domain>/<token>', methods=['GET'])
|
|
||||||
@authorized_personnel_only
|
|
||||||
def letsencrypt_dns_auth(domain, token):
|
|
||||||
from dns_update import do_dns_update, set_custom_dns_record
|
|
||||||
try:
|
|
||||||
qname = '_acme-challenge.' + domain
|
|
||||||
if set_custom_dns_record(qname, 'TXT', token, 'add', env):
|
|
||||||
if not do_dns_update(env):
|
|
||||||
return ("Error updating DNS", 400)
|
|
||||||
return "OK"
|
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
return (str(e), 400)
|
|
||||||
|
|
||||||
@app.route('/letsencrypt/dns-cleanup/<domain>', methods=['GET'])
|
|
||||||
@authorized_personnel_only
|
|
||||||
def letsencrypt_dns_cleanup(domain):
|
|
||||||
from dns_update import do_dns_update, set_custom_dns_record
|
|
||||||
try:
|
|
||||||
qname = '_acme-challenge.' + domain
|
|
||||||
if set_custom_dns_record(qname, 'TXT', None, 'remove', env):
|
|
||||||
if not do_dns_update(env):
|
|
||||||
return ("Error updating DNS", 400)
|
|
||||||
return "OK"
|
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
return (str(e), 400)
|
|
||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
|
|
||||||
@app.route('/ssl/status')
|
@app.route('/ssl/status')
|
||||||
@ -573,9 +543,6 @@ def privacy_status_set():
|
|||||||
utils.write_settings(config, env)
|
utils.write_settings(config, env)
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
# Quotas
|
|
||||||
|
|
||||||
@app.route('/system/default-quota', methods=["GET"])
|
@app.route('/system/default-quota', methods=["GET"])
|
||||||
@authorized_personnel_only
|
@authorized_personnel_only
|
||||||
def default_quota_get():
|
def default_quota_get():
|
||||||
@ -599,37 +566,6 @@ def default_quota_set():
|
|||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
# Mailgraph
|
|
||||||
|
|
||||||
@app.route('/mailgraph/image.cgi', methods=['GET'])
|
|
||||||
@authorized_personnel_only
|
|
||||||
def mailgraph():
|
|
||||||
if request.query_string:
|
|
||||||
query = request.query_string.decode('utf-8', 'ignore')
|
|
||||||
if '&' in query:
|
|
||||||
query = query.split('&')[0]
|
|
||||||
|
|
||||||
print("QUERY_STRING=%s" % query, file=sys.stderr)
|
|
||||||
|
|
||||||
code, bin_out = utils.shell(
|
|
||||||
"check_output",
|
|
||||||
["/usr/share/mailgraph/mailgraph.cgi"],
|
|
||||||
env={"QUERY_STRING": query},
|
|
||||||
return_bytes=True,
|
|
||||||
trap=True
|
|
||||||
)
|
|
||||||
|
|
||||||
if code != 0:
|
|
||||||
return ('Error generating mailgraph image: %s' % query, 500)
|
|
||||||
|
|
||||||
headers, image_bytes = bin_out.split(b'\n\n', 1)
|
|
||||||
|
|
||||||
return base64.b64encode(image_bytes)
|
|
||||||
|
|
||||||
return ('Mailgraph: no image requested', 500)
|
|
||||||
|
|
||||||
|
|
||||||
# MUNIN
|
# MUNIN
|
||||||
|
|
||||||
@app.route('/munin/')
|
@app.route('/munin/')
|
||||||
|
@ -313,7 +313,6 @@ def provision_certificates(env, limit_domains):
|
|||||||
webroot = os.path.join(account_path, 'webroot')
|
webroot = os.path.join(account_path, 'webroot')
|
||||||
os.makedirs(webroot, exist_ok=True)
|
os.makedirs(webroot, exist_ok=True)
|
||||||
with tempfile.TemporaryDirectory() as d:
|
with tempfile.TemporaryDirectory() as d:
|
||||||
miab_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
||||||
cert_file = os.path.join(d, 'cert_and_chain.pem')
|
cert_file = os.path.join(d, 'cert_and_chain.pem')
|
||||||
print("Provisioning TLS certificates for " + ", ".join(domain_list) + ".")
|
print("Provisioning TLS certificates for " + ", ".join(domain_list) + ".")
|
||||||
certbotret = subprocess.check_output([
|
certbotret = subprocess.check_output([
|
||||||
@ -329,10 +328,7 @@ def provision_certificates(env, limit_domains):
|
|||||||
"--chain-path", os.path.join(d, 'chain'), # we only use the full chain
|
"--chain-path", os.path.join(d, 'chain'), # we only use the full chain
|
||||||
"--fullchain-path", cert_file,
|
"--fullchain-path", cert_file,
|
||||||
|
|
||||||
"--manual",
|
"--webroot", "--webroot-path", webroot,
|
||||||
"--preferred-challenge", "dns",
|
|
||||||
"--manual-auth-hook", os.path.join(miab_dir, "tools/dns-auth.sh"),
|
|
||||||
"--manual-cleanup-hook", os.path.join(miab_dir, "tools/dns-cleanup.sh"),
|
|
||||||
|
|
||||||
"--config-dir", account_path,
|
"--config-dir", account_path,
|
||||||
#"--staging",
|
#"--staging",
|
||||||
|
@ -26,7 +26,6 @@ def get_services():
|
|||||||
{ "name": "Dovecot LMTP LDA", "port": 10026, "public": False, },
|
{ "name": "Dovecot LMTP LDA", "port": 10026, "public": False, },
|
||||||
{ "name": "Postgrey", "port": 10023, "public": False, },
|
{ "name": "Postgrey", "port": 10023, "public": False, },
|
||||||
{ "name": "Spamassassin", "port": 10025, "public": False, },
|
{ "name": "Spamassassin", "port": 10025, "public": False, },
|
||||||
{ "name": "IMAP Quota", "port": 12340, "public": False },
|
|
||||||
{ "name": "OpenDKIM", "port": 8891, "public": False, },
|
{ "name": "OpenDKIM", "port": 8891, "public": False, },
|
||||||
{ "name": "OpenDMARC", "port": 8893, "public": False, },
|
{ "name": "OpenDMARC", "port": 8893, "public": False, },
|
||||||
{ "name": "Mail-in-a-Box Management Daemon", "port": 10222, "public": False, },
|
{ "name": "Mail-in-a-Box Management Daemon", "port": 10222, "public": False, },
|
||||||
@ -39,7 +38,6 @@ def get_services():
|
|||||||
{ "name": "Mail Filters (Sieve/dovecot)", "port": 4190, "public": True, },
|
{ "name": "Mail Filters (Sieve/dovecot)", "port": 4190, "public": True, },
|
||||||
{ "name": "HTTP Web (nginx)", "port": 80, "public": True, },
|
{ "name": "HTTP Web (nginx)", "port": 80, "public": True, },
|
||||||
{ "name": "HTTPS Web (nginx)", "port": 443, "public": True, },
|
{ "name": "HTTPS Web (nginx)", "port": 443, "public": True, },
|
||||||
{ "name": "Solr Full Text Search (tomcat)", "port": 8080, "public": False, },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def run_checks(rounded_values, env, output, pool):
|
def run_checks(rounded_values, env, output, pool):
|
||||||
|
@ -102,7 +102,6 @@
|
|||||||
<li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li>
|
<li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li>
|
||||||
<li><a href="#users" onclick="return show_panel(this);">Users</a></li>
|
<li><a href="#users" onclick="return show_panel(this);">Users</a></li>
|
||||||
<li><a href="#aliases" onclick="return show_panel(this);">Aliases</a></li>
|
<li><a href="#aliases" onclick="return show_panel(this);">Aliases</a></li>
|
||||||
<li><a href="#mailgraph" onclick="return show_panel(this);">Mailgraph</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li>
|
<li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li>
|
||||||
@ -152,10 +151,6 @@
|
|||||||
{% include "sync-guide.html" %}
|
{% include "sync-guide.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="panel_mailgraph" class="admin_panel">
|
|
||||||
{% include "mailgraph.html" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="panel_web" class="admin_panel">
|
<div id="panel_web" class="admin_panel">
|
||||||
{% include "web.html" %}
|
{% include "web.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
<h2>Mail statistics</h2>
|
|
||||||
<ul id="jump">
|
|
||||||
<li><a href="#G0">Day</a> </li>
|
|
||||||
<li><a href="#G1">Week</a> </li>
|
|
||||||
<li><a href="#G2">Month</a> </li>
|
|
||||||
<li><a href="#G3">Year</a> </li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3 id="G0">Last Day</h3>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?0-n" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?0-e" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?0-g" alt="mailgraph"/></p>
|
|
||||||
|
|
||||||
<h3 id="G1">Last Week</h3>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?1-n" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?1-e" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?1-g" alt="mailgraph"/></p>
|
|
||||||
|
|
||||||
<h3 id="G2">Last Month</h3>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?2-n" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?2-e" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?2-g" alt="mailgraph"/></p>
|
|
||||||
|
|
||||||
<h3 id="G3">Last Year</h3>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?3-n" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?3-e" alt="mailgraph"/></p>
|
|
||||||
<p><img src="" data-src="/mailgraph/image.cgi?3-g" alt="mailgraph"/></p>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<p><a href="http://mailgraph.schweikert.ch/">Mailgraph</a> 1.14 by <a href="http://david.schweikert.ch/">David Schweikert</a>
|
|
||||||
(built on Tobi Oetiker's <a href="http://oss.oetiker.ch/rrdtool/">RRDtool</a>)</p>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
function show_mailgraph() {
|
|
||||||
$('[data-src]').each(function() {
|
|
||||||
var that = this;
|
|
||||||
api(
|
|
||||||
$(that).attr('data-src'),
|
|
||||||
'GET',
|
|
||||||
'',
|
|
||||||
function(data) {
|
|
||||||
$(that).attr('src', 'data:image/gif;base64,' + data);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -100,20 +100,6 @@ def do_web_update(env):
|
|||||||
# Add default 'www.' redirect.
|
# Add default 'www.' redirect.
|
||||||
nginx_conf += make_domain_config(domain, [template0, template3], ssl_certificates, env)
|
nginx_conf += make_domain_config(domain, [template0, template3], ssl_certificates, env)
|
||||||
|
|
||||||
if str(env['HTTP_SSL_PORT']) != "443":
|
|
||||||
in_http = False
|
|
||||||
new_conf = ''
|
|
||||||
for line in nginx_conf.split('\n'):
|
|
||||||
if line.strip() == '#BEGIN_HTTP':
|
|
||||||
in_http = True
|
|
||||||
elif line.strip() == '#END_HTTP':
|
|
||||||
in_http = False
|
|
||||||
|
|
||||||
if not in_http:
|
|
||||||
new_conf += line + '\n'
|
|
||||||
|
|
||||||
nginx_conf = new_conf
|
|
||||||
|
|
||||||
# Did the file change? If not, don't bother writing & restarting nginx.
|
# Did the file change? If not, don't bother writing & restarting nginx.
|
||||||
nginx_conf_fn = "/etc/nginx/conf.d/local.conf"
|
nginx_conf_fn = "/etc/nginx/conf.d/local.conf"
|
||||||
if os.path.exists(nginx_conf_fn):
|
if os.path.exists(nginx_conf_fn):
|
||||||
@ -198,12 +184,8 @@ def make_domain_config(domain, templates, ssl_certificates, env):
|
|||||||
nginx_conf = re.sub("[ \t]*# ADDITIONAL DIRECTIVES HERE *\n", t, nginx_conf)
|
nginx_conf = re.sub("[ \t]*# ADDITIONAL DIRECTIVES HERE *\n", t, nginx_conf)
|
||||||
|
|
||||||
# Replace substitution strings in the template & return.
|
# Replace substitution strings in the template & return.
|
||||||
if int(env['HTTP_SSL_PORT']) != 443:
|
|
||||||
# disable the regular HTTP server
|
|
||||||
nginx_conf = re.sub(r'#BEGIN_HTTP.*?#END_HTTP', repl='', string=nginx_conf, flags=re.MULTILINE)
|
|
||||||
nginx_conf = nginx_conf.replace("$STORAGE_ROOT", env['STORAGE_ROOT'])
|
nginx_conf = nginx_conf.replace("$STORAGE_ROOT", env['STORAGE_ROOT'])
|
||||||
nginx_conf = nginx_conf.replace("$HOSTNAME", domain)
|
nginx_conf = nginx_conf.replace("$HOSTNAME", domain)
|
||||||
nginx_conf = nginx_conf.replace("$HTTP_SSL_PORT", env['HTTP_SSL_PORT'])
|
|
||||||
nginx_conf = nginx_conf.replace("$ROOT", root)
|
nginx_conf = nginx_conf.replace("$ROOT", root)
|
||||||
nginx_conf = nginx_conf.replace("$SSL_KEY", tls_cert["private-key"])
|
nginx_conf = nginx_conf.replace("$SSL_KEY", tls_cert["private-key"])
|
||||||
nginx_conf = nginx_conf.replace("$SSL_CERTIFICATE", tls_cert["certificate"])
|
nginx_conf = nginx_conf.replace("$SSL_CERTIFICATE", tls_cert["certificate"])
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
rtyaml
|
|
||||||
email_validator>=1.0.0
|
|
||||||
exclusiveprocess
|
|
||||||
flask
|
|
||||||
dnspython
|
|
||||||
python-dateutil
|
|
||||||
idna>=2.0.0
|
|
||||||
cryptography==2.2.2
|
|
||||||
boto
|
|
||||||
psutil
|
|
||||||
npyscreen
|
|
@ -42,8 +42,7 @@ source /etc/mailinabox.conf # load global vars
|
|||||||
# * `ca-certificates`: A trust store used to squelch postfix warnings about
|
# * `ca-certificates`: A trust store used to squelch postfix warnings about
|
||||||
# untrusted opportunistically-encrypted connections.
|
# untrusted opportunistically-encrypted connections.
|
||||||
echo "Installing Postfix (SMTP server)..."
|
echo "Installing Postfix (SMTP server)..."
|
||||||
apt_install postfix postfix-sqlite postfix-pcre postgrey ca-certificates \
|
apt_install postfix postfix-sqlite postfix-pcre postgrey ca-certificates
|
||||||
postfix-policyd-spf-python postsrsd
|
|
||||||
|
|
||||||
# ### Basic Settings
|
# ### Basic Settings
|
||||||
|
|
||||||
@ -98,9 +97,7 @@ tools/editconf.py /etc/postfix/master.cf -s -w \
|
|||||||
-o cleanup_service_name=authclean" \
|
-o cleanup_service_name=authclean" \
|
||||||
"authclean=unix n - - - 0 cleanup
|
"authclean=unix n - - - 0 cleanup
|
||||||
-o header_checks=pcre:/etc/postfix/outgoing_mail_header_filters
|
-o header_checks=pcre:/etc/postfix/outgoing_mail_header_filters
|
||||||
-o nested_header_checks=" \
|
-o nested_header_checks="
|
||||||
"policy-spf=unix - n n - - spawn
|
|
||||||
user=nobody argv=/usr/bin/policyd-spf"
|
|
||||||
|
|
||||||
# Install the `outgoing_mail_header_filters` file required by the new 'authclean' service.
|
# Install the `outgoing_mail_header_filters` file required by the new 'authclean' service.
|
||||||
cp conf/postfix_outgoing_mail_header_filters /etc/postfix/outgoing_mail_header_filters
|
cp conf/postfix_outgoing_mail_header_filters /etc/postfix/outgoing_mail_header_filters
|
||||||
@ -199,23 +196,9 @@ tools/editconf.py /etc/postfix/main.cf lmtp_destination_recipient_limit=1
|
|||||||
# so these IPs get mail delivered quickly. But when an IP is not listed in the permit_dnswl_client list (i.e. it is not #NODOC
|
# so these IPs get mail delivered quickly. But when an IP is not listed in the permit_dnswl_client list (i.e. it is not #NODOC
|
||||||
# whitelisted) then postfix does a DEFER_IF_REJECT, which results in all "unknown user" sorts of messages turning into #NODOC
|
# whitelisted) then postfix does a DEFER_IF_REJECT, which results in all "unknown user" sorts of messages turning into #NODOC
|
||||||
# "450 4.7.1 Client host rejected: Service unavailable". This is a retry code, so the mail doesn't properly bounce. #NODOC
|
# "450 4.7.1 Client host rejected: Service unavailable". This is a retry code, so the mail doesn't properly bounce. #NODOC
|
||||||
|
tools/editconf.py /etc/postfix/main.cf \
|
||||||
postconf -e smtpd_sender_restrictions="reject_non_fqdn_sender,reject_unknown_sender_domain,reject_authenticated_sender_login_mismatch,reject_rhsbl_sender dbl.spamhaus.org"
|
smtpd_sender_restrictions="reject_non_fqdn_sender,reject_unknown_sender_domain,reject_authenticated_sender_login_mismatch,reject_rhsbl_sender dbl.spamhaus.org" \
|
||||||
|
smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,"reject_rbl_client zen.spamhaus.org",reject_unlisted_recipient,"check_policy_service inet:127.0.0.1:10023","check_policy_service inet:127.0.0.1:12340"
|
||||||
RECIPIENT_RESTRICTIONS="permit_sasl_authenticated,permit_mynetworks,reject_rbl_client zen.spamhaus.org,reject_unlisted_recipient"
|
|
||||||
|
|
||||||
if [ $POSTGREY == 1 ]; then
|
|
||||||
RECIPIENT_RESTRICTIONS="${RECIPIENT_RESTRICTIONS},check_policy_service inet:127.0.0.1:10023"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $POLICY_SPF == 1 ]; then
|
|
||||||
RECIPIENT_RESTRICTIONS="${RECIPIENT_RESTRICTIONS},check_policy_service unix:private/policy-spf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add quota check
|
|
||||||
RECIPIENT_RESTRICTIONS="${RECIPIENT_RESTRICTIONS},check_policy_service inet:127.0.0.1:12340"
|
|
||||||
|
|
||||||
postconf -e smtpd_recipient_restrictions="$RECIPIENT_RESTRICTIONS"
|
|
||||||
|
|
||||||
# Postfix connects to Postgrey on the 127.0.0.1 interface specifically. Ensure that
|
# Postfix connects to Postgrey on the 127.0.0.1 interface specifically. Ensure that
|
||||||
# Postgrey listens on the same interface (and not IPv6, for instance).
|
# Postgrey listens on the same interface (and not IPv6, for instance).
|
||||||
@ -259,29 +242,6 @@ chmod +x /etc/cron.daily/mailinabox-postgrey-whitelist
|
|||||||
tools/editconf.py /etc/postfix/main.cf \
|
tools/editconf.py /etc/postfix/main.cf \
|
||||||
message_size_limit=134217728
|
message_size_limit=134217728
|
||||||
|
|
||||||
if [ $POSTSRSD == 1 ]; then
|
|
||||||
# Setup SRS
|
|
||||||
postconf -e \
|
|
||||||
sender_canonical_maps=tcp:localhost:10001 \
|
|
||||||
sender_canonical_classes=envelope_sender \
|
|
||||||
recipient_canonical_maps=tcp:localhost:10002 \
|
|
||||||
recipient_canonical_classes=envelope_recipient,header_recipient
|
|
||||||
|
|
||||||
hide_output systemctl enable postsrsd
|
|
||||||
hide_output systemctl restart postsrsd
|
|
||||||
|
|
||||||
else
|
|
||||||
postconf -e \
|
|
||||||
sender_canonical_maps= \
|
|
||||||
sender_canonical_classes= \
|
|
||||||
recipient_canonical_maps= \
|
|
||||||
recipient_canonical_classes=
|
|
||||||
|
|
||||||
hide_output systemctl disable postsrsd
|
|
||||||
hide_output systemctl stop postsrsd
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Allow the two SMTP ports in the firewall.
|
# Allow the two SMTP ports in the firewall.
|
||||||
|
|
||||||
ufw_allow smtp
|
ufw_allow smtp
|
||||||
@ -290,11 +250,4 @@ ufw_allow submission
|
|||||||
# Restart services
|
# Restart services
|
||||||
|
|
||||||
restart_service postfix
|
restart_service postfix
|
||||||
|
restart_service postgrey
|
||||||
if [ $POSTGREY == 1 ]; then
|
|
||||||
hide_output systemctl enable postgrey
|
|
||||||
hide_output systemctl restart postgrey
|
|
||||||
else
|
|
||||||
hide_output systemctl disable postgrey
|
|
||||||
hide_output systemctl stop postgrey
|
|
||||||
fi
|
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
import npyscreen
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class OptionsApp(npyscreen.NPSApp):
|
|
||||||
def main(self):
|
|
||||||
# These lines create the form and populate it with widgets.
|
|
||||||
# A fairly complex screen in only 8 or so lines of code - a line for each control.
|
|
||||||
npyscreen.setTheme(npyscreen.Themes.BlackOnWhiteTheme)
|
|
||||||
|
|
||||||
form = npyscreen.Form(name = "Mail-in-a-Box Options",)
|
|
||||||
form.add(
|
|
||||||
npyscreen.TitleFixedText,
|
|
||||||
name="POSTGREY",
|
|
||||||
value="",
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
form.add(
|
|
||||||
npyscreen.MultiLineEdit,
|
|
||||||
value="The Postgrey service greylists incoming messages from unknown senders.\n"
|
|
||||||
"It can be useful for fighting spam but often causes message delivery\n"
|
|
||||||
"delays of several minutes.",
|
|
||||||
max_height=4,
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
form.add(
|
|
||||||
npyscreen.TitleFixedText,
|
|
||||||
name="POSTSRSD",
|
|
||||||
value="",
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
form.add(
|
|
||||||
npyscreen.MultiLineEdit,
|
|
||||||
value="The PostSRSd daemon performs return path rewriting using the SRS protocol.\n"
|
|
||||||
"Not that all messages, including locally delivered mail will have their return\n"
|
|
||||||
"paths rewritten",
|
|
||||||
max_height=4,
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
form.add(
|
|
||||||
npyscreen.TitleFixedText,
|
|
||||||
name="POLICY_SPF",
|
|
||||||
value="",
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
form.add(
|
|
||||||
npyscreen.MultiLineEdit,
|
|
||||||
value=""
|
|
||||||
"The policy SPF service checks the SPF of incoming mails and rejects those\n"
|
|
||||||
"that do not qualify. This helps to prevent spoofing, but if valid mail does\n"
|
|
||||||
"not have SPF configured properly it will be rejected.",
|
|
||||||
max_height=4,
|
|
||||||
editable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
init_values = []
|
|
||||||
if int(os.getenv('POSTGREY', 1)) == 1:
|
|
||||||
init_values.append(0)
|
|
||||||
|
|
||||||
if int(os.getenv('POSTSRSD', 0)) == 1:
|
|
||||||
init_values.append(1)
|
|
||||||
|
|
||||||
if int(os.getenv('POLICY_SPF', 0)) == 1:
|
|
||||||
init_values.append(2)
|
|
||||||
|
|
||||||
options = form.add(
|
|
||||||
npyscreen.TitleMultiSelect,
|
|
||||||
max_height=-2,
|
|
||||||
value=init_values,
|
|
||||||
name="Options",
|
|
||||||
values= ["POSTGREY","POSTSRSD","POLICY_SPF"],
|
|
||||||
scroll_exit=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# This lets the user interact with the Form.
|
|
||||||
form.edit()
|
|
||||||
|
|
||||||
with open('_options.sh', 'w') as output:
|
|
||||||
print('POSTGREY=%i' % (1 if 0 in options.value else 0), file=output)
|
|
||||||
print('POSTSRSD=%i' % (1 if 1 in options.value else 0), file=output)
|
|
||||||
print('POLICY_SPF=%i' % (1 if 2 in options.value else 0), file=output)
|
|
||||||
# print(npyscreen.ThemeManager.default_colors, file=output)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
App = OptionsApp()
|
|
||||||
App.run()
|
|
@ -16,7 +16,6 @@ if [ -z "${NONINTERACTIVE:-}" ]; then
|
|||||||
# we install it inside a virtualenv. In this script, we don't have the virtualenv yet
|
# we install it inside a virtualenv. In this script, we don't have the virtualenv yet
|
||||||
# so we install the python package globally.
|
# so we install the python package globally.
|
||||||
hide_output pip3 install "email_validator>=1.0.0" || exit 1
|
hide_output pip3 install "email_validator>=1.0.0" || exit 1
|
||||||
hide_output pip3 install npyscreen || exit 1
|
|
||||||
|
|
||||||
message_box "Mail-in-a-Box Installation" \
|
message_box "Mail-in-a-Box Installation" \
|
||||||
"Hello and thanks for deploying a Mail-in-a-Box!
|
"Hello and thanks for deploying a Mail-in-a-Box!
|
||||||
@ -194,16 +193,6 @@ if [ -z "${STORAGE_ROOT:-}" ]; then
|
|||||||
STORAGE_ROOT=$([[ -z "${DEFAULT_STORAGE_ROOT:-}" ]] && echo "/home/$STORAGE_USER" || echo "$DEFAULT_STORAGE_ROOT")
|
STORAGE_ROOT=$([[ -z "${DEFAULT_STORAGE_ROOT:-}" ]] && echo "/home/$STORAGE_USER" || echo "$DEFAULT_STORAGE_ROOT")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# export options variables so they are visible to the options program
|
|
||||||
export POSTGREY
|
|
||||||
export POSTSRSD
|
|
||||||
export POLICY_SPF
|
|
||||||
|
|
||||||
python3 setup/options-dialog.py
|
|
||||||
source ./_options.sh
|
|
||||||
rm _options.sh
|
|
||||||
|
|
||||||
|
|
||||||
# Show the configuration, since the user may have not entered it manually.
|
# Show the configuration, since the user may have not entered it manually.
|
||||||
echo
|
echo
|
||||||
echo "Primary Hostname: $PRIMARY_HOSTNAME"
|
echo "Primary Hostname: $PRIMARY_HOSTNAME"
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Inspired by the solr.sh from jkaberg (https://github.com/jkaberg/mailinabox-sogo)
|
|
||||||
# with some modifications
|
|
||||||
#
|
|
||||||
# IMAP search with lucene via solr
|
|
||||||
# --------------------------------
|
|
||||||
#
|
|
||||||
# By default dovecot uses its own Squat search index that has awful performance
|
|
||||||
# on large mailboxes. Dovecot 2.1+ has support for using Lucene internally but
|
|
||||||
# this didn't make it into the Ubuntu packages, so we use Solr instead to run
|
|
||||||
# Lucene for us.
|
|
||||||
#
|
|
||||||
# Solr runs as a tomcat process. The dovecot solr plugin talks to solr via its
|
|
||||||
# HTTP interface, causing mail to be indexed when searches occur, and getting
|
|
||||||
# results back.
|
|
||||||
|
|
||||||
source setup/functions.sh # load our functions
|
|
||||||
source /etc/mailinabox.conf # load global vars
|
|
||||||
|
|
||||||
# Install packages and basic configuation
|
|
||||||
# ---------------------------------------
|
|
||||||
|
|
||||||
echo "Installing Solr..."
|
|
||||||
|
|
||||||
# Install packages
|
|
||||||
apt_install solr-tomcat dovecot-solr
|
|
||||||
|
|
||||||
# Solr requires a schema to tell it how to index data, this is provided by dovecot
|
|
||||||
cp /usr/share/dovecot/solr-schema.xml /etc/solr/conf/schema.xml
|
|
||||||
|
|
||||||
# Update the dovecot plugin configuration
|
|
||||||
#
|
|
||||||
# Break-imap-search makes search work the way users expect, rather than the way
|
|
||||||
# the IMAP specification expects
|
|
||||||
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
|
|
||||||
mail_plugins="fts fts_solr"
|
|
||||||
|
|
||||||
cat > /etc/dovecot/conf.d/90-plugin-fts.conf << EOF;
|
|
||||||
plugin {
|
|
||||||
fts = solr
|
|
||||||
fts_autoindex = yes
|
|
||||||
fts_solr = break-imap-search url=http://127.0.0.1:8080/solr/
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Bump memory allocation for Solr.
|
|
||||||
# Not needed? I'll let it sit here for a while.
|
|
||||||
#echo 'export JAVA_OPTS=-Xms512M -Xmx1024M' > /usr/share/tomcat7/bin/setenv.sh
|
|
||||||
|
|
||||||
# Install cronjobs to keep FTS up to date
|
|
||||||
hide_output install -m 755 conf/cronjob/dovecot /etc/cron.daily/
|
|
||||||
hide_output install -m 644 conf/cronjob/solr /etc/cron.d/
|
|
||||||
|
|
||||||
# PERMISSIONS
|
|
||||||
|
|
||||||
# Ensure configuration files are owned by dovecot and not world readable.
|
|
||||||
chown -R mail:dovecot /etc/dovecot
|
|
||||||
chmod -R o-rwx /etc/dovecot
|
|
||||||
|
|
||||||
mkdir -p /etc/systemd/system/tomcat9.service.d
|
|
||||||
cat > /etc/systemd/system/tomcat9.service.d/solr-permissions.conf << EOF
|
|
||||||
[Service]
|
|
||||||
ReadWritePaths=/var/lib/solr/
|
|
||||||
ReadWritePaths=/var/lib/solr/data/
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Restart services to reload solr schema & dovecot plugins
|
|
||||||
restart_service tomcat9
|
|
||||||
restart_service dovecot
|
|
||||||
|
|
||||||
|
|
||||||
# Kickoff building the index
|
|
||||||
|
|
||||||
# Per doveadm-fts manpage: Scan what mails exist in the full text search index
|
|
||||||
# and compare those to what actually exist in mailboxes.
|
|
||||||
# This removes mails from the index that have already been expunged and makes
|
|
||||||
# sure that the next doveadm index will index all the missing mails (if any).
|
|
||||||
doveadm fts rescan -A
|
|
||||||
|
|
||||||
# Adds unindexed files to the fts database
|
|
||||||
# * `-q`: Queues the indexing to be run by indexer process. (will background the indexing)
|
|
||||||
# * `-A`: All users
|
|
||||||
# * `'*'`: All folders
|
|
||||||
doveadm index -q -A '*'
|
|
@ -42,22 +42,6 @@ else
|
|||||||
FIRST_TIME_SETUP=1
|
FIRST_TIME_SETUP=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${HTTP_SSL_PORT:-}" ]; then
|
|
||||||
HTTP_SSL_PORT=$([[ -z "${DEFAULT_HTTP_SSL_PORT:-}" ]] && echo "443" || echo "$DEFAULT_HTTP_SSL_PORT")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${POSTGREY:-}" ]; then
|
|
||||||
POSTGREY=$([[ -z "${DEFAULT_POSTGREY:-}" ]] && echo "1" || echo "$DEFAULT_POSTGREY")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${POSTSRSD:-}" ]; then
|
|
||||||
POSTSRSD=$([[ -z "${DEFAULT_POSTSRSD:-}" ]] && echo "0" || echo "$DEFAULT_POSTSRSD")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${POLICY_SPF:-}" ]; then
|
|
||||||
POLICY_SPF=$([[ -z "${DEFAULT_POLICY_SPF:-}" ]] && echo "0" || echo "$DEFAULT_POLICY_SPF")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Put a start script in a global location. We tell the user to run 'mailinabox'
|
# Put a start script in a global location. We tell the user to run 'mailinabox'
|
||||||
# in the first dialog prompt, so we should do this before that starts.
|
# in the first dialog prompt, so we should do this before that starts.
|
||||||
cat > /usr/local/bin/mailinabox << EOF;
|
cat > /usr/local/bin/mailinabox << EOF;
|
||||||
@ -109,10 +93,6 @@ PUBLIC_IP=$PUBLIC_IP
|
|||||||
PUBLIC_IPV6=$PUBLIC_IPV6
|
PUBLIC_IPV6=$PUBLIC_IPV6
|
||||||
PRIVATE_IP=$PRIVATE_IP
|
PRIVATE_IP=$PRIVATE_IP
|
||||||
PRIVATE_IPV6=$PRIVATE_IPV6
|
PRIVATE_IPV6=$PRIVATE_IPV6
|
||||||
HTTP_SSL_PORT=$HTTP_SSL_PORT
|
|
||||||
POSTGREY=$POSTGREY
|
|
||||||
POSTSRSD=$POSTSRSD
|
|
||||||
POLICY_SPF=$POLICY_SPF
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Start service configuration.
|
# Start service configuration.
|
||||||
@ -122,7 +102,6 @@ source setup/dns.sh
|
|||||||
source setup/mail-postfix.sh
|
source setup/mail-postfix.sh
|
||||||
source setup/mail-dovecot.sh
|
source setup/mail-dovecot.sh
|
||||||
source setup/mail-users.sh
|
source setup/mail-users.sh
|
||||||
source setup/solr.sh
|
|
||||||
source setup/dkim.sh
|
source setup/dkim.sh
|
||||||
source setup/spamassassin.sh
|
source setup/spamassassin.sh
|
||||||
source setup/web.sh
|
source setup/web.sh
|
||||||
|
17
setup/web.sh
17
setup/web.sh
@ -19,7 +19,7 @@ fi
|
|||||||
|
|
||||||
echo "Installing Nginx (web server)..."
|
echo "Installing Nginx (web server)..."
|
||||||
|
|
||||||
apt_install nginx php-cli php-fpm fcgiwrap mailgraph
|
apt_install nginx php-cli php-fpm
|
||||||
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
|
||||||
@ -48,12 +48,6 @@ tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
|
|||||||
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
|
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
|
||||||
default_charset="UTF-8"
|
default_charset="UTF-8"
|
||||||
|
|
||||||
# Set higher timeout since searches with Roundcube and Solr may take longer
|
|
||||||
# than the default 60 seconds. We will also match Roundcube's timeout to the
|
|
||||||
# same value
|
|
||||||
tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \
|
|
||||||
default_socket_timeout=180
|
|
||||||
|
|
||||||
# Switch from the dynamic process manager to the ondemand manager see #1216
|
# Switch from the dynamic process manager to the ondemand manager see #1216
|
||||||
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \
|
||||||
pm=ondemand
|
pm=ondemand
|
||||||
@ -102,9 +96,6 @@ restart_service nginx
|
|||||||
restart_service php7.2-fpm
|
restart_service php7.2-fpm
|
||||||
|
|
||||||
# Open ports.
|
# Open ports.
|
||||||
if [ $HTTP_SSL_PORT == 443 ]; then
|
ufw_allow http
|
||||||
ufw_allow http
|
ufw_allow https
|
||||||
ufw_allow https
|
|
||||||
else
|
|
||||||
ufw_allow $HTTP_SSL_PORT
|
|
||||||
fi
|
|
||||||
|
@ -108,7 +108,7 @@ cat > $RCM_CONFIG <<EOF;
|
|||||||
'verify_peer_name' => false,
|
'verify_peer_name' => false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
\$config['imap_timeout'] = 180;
|
\$config['imap_timeout'] = 15;
|
||||||
\$config['smtp_server'] = 'tls://127.0.0.1';
|
\$config['smtp_server'] = 'tls://127.0.0.1';
|
||||||
\$config['smtp_port'] = 587;
|
\$config['smtp_port'] = 587;
|
||||||
\$config['smtp_user'] = '%u';
|
\$config['smtp_user'] = '%u';
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# TODO: Make work with port other than 443
|
|
||||||
|
|
||||||
API_KEY=`cat /var/lib/mailinabox/api.key`
|
|
||||||
HOSTNAME=`hostname`
|
|
||||||
|
|
||||||
curl -s -X PUT -d "$CERTBOT_VALIDATION" --user "$API_KEY:" https://$HOSTNAME/admin/dns/custom/_acme-challenge.$CERTBOT_DOMAIN/TXT
|
|
||||||
|
|
||||||
sleep 15
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# TODO: Make work with port other than 443
|
|
||||||
|
|
||||||
API_KEY=`cat /var/lib/mailinabox/api.key`
|
|
||||||
HOSTNAME=`hostname`
|
|
||||||
|
|
||||||
curl -s -X DELETE --user "$API_KEY:" https://$HOSTNAME/admin/dns/custom/_acme-challenge.$CERTBOT_DOMAIN/TXT
|
|
Loading…
Reference in New Issue
Block a user