1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2026-03-25 19:17:22 +01:00

Merge branch 'master' into roundcubesqlitemod

This commit is contained in:
KiekerJan
2023-02-06 14:34:03 +01:00
committed by GitHub
89 changed files with 3087 additions and 569 deletions

54
setup/additionals.sh Normal file
View File

@@ -0,0 +1,54 @@
source /etc/mailinabox.conf
source setup/functions.sh
# Add additional packages
apt_install pflogsumm rkhunter
# Cleanup old spam and trash email
hide_output install -m 755 conf/cron/miab_clean_mail /etc/cron.weekly/
# Reduce logs by not logging mail output in syslog
sed -i "s/\*\.\*;auth,authpriv.none.*\-\/var\/log\/syslog/\*\.\*;mail,auth,authpriv.none \-\/var\/log\/syslog/g" /etc/rsyslog.d/50-default.conf
# Reduce logs by only logging ufw in ufw.log
sed -i "s/#\& stop/\& stop/g" /etc/rsyslog.d/20-ufw.conf
# Add nextcloud logging
hide_output install -m 644 conf/rsyslog/20-nextcloud.conf /etc/rsyslog.d/
restart_service rsyslog
# Create forward for root emails
cat > /root/.forward << EOF;
administrator@$PRIMARY_HOSTNAME
EOF
# Adapt rkhunter cron job to reduce log file production
sed -i "s/--cronjob --report-warnings-only --appendlog/--cronjob --report-warnings-only --no-verbose-logging --appendlog/g" /etc/cron.daily/rkhunter
# Install fake mail script
if [ ! -f /usr/local/bin/mail ]; then
hide_output install -m 755 tools/fake_mail /usr/local/bin
mv -f /usr/local/bin/fake_mail /usr/local/bin/mail
fi
# Adapt rkhunter configuration
tools/editconf.py /etc/rkhunter.conf \
UPDATE_MIRRORS=1 \
MIRRORS_MODE=0 \
WEB_CMD='""' \
APPEND_LOG=1 \
ALLOWHIDDENDIR=/etc/.java
# Check presence of whitelist
if ! grep -Fxq "SCRIPTWHITELIST=/usr/local/bin/mail" /etc/rkhunter.conf > /dev/null; then
echo "SCRIPTWHITELIST=/usr/local/bin/mail" >> /etc/rkhunter.conf
fi
tools/editconf.py /etc/default/rkhunter \
CRON_DAILY_RUN='"true"' \
CRON_DB_UPDATE='"true"' \
APT_AUTOGEN='"true"'
# Should be last, update expected output
rkhunter --propupd

View File

@@ -6,6 +6,8 @@
#
#########################################################
GITSRC=kj
if [ -z "$TAG" ]; then
# If a version to install isn't explicitly given as an environment
# variable, then install the latest version. But the latest version
@@ -19,11 +21,11 @@ if [ -z "$TAG" ]; then
# want to display in status checks.
#
# Allow point-release versions of the major releases, e.g. 22.04.1 is OK.
UBUNTU_VERSION=$( lsb_release -d | sed 's/.*:\s*//' | sed 's/\([0-9]*\.[0-9]*\)\.[0-9]/\1/' )
UBUNTU_VERSION=$( lsb_release -d | sed 's/.*:\s*//' | sed 's/\([0-9]*\.[0-9]*\)\.[0-9]/\1/' )"
if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then
# This machine is running Ubuntu 22.04, which is supported by
# Mail-in-a-Box versions 60 and later.
TAG=v60.1
TAG=v61.1
elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then
# This machine is running Ubuntu 18.04, which is supported by
# Mail-in-a-Box versions 0.40 through 5x.
@@ -32,6 +34,7 @@ if [ -z "$TAG" ]; then
echo "a new machine running Ubuntu 22.04. See:"
echo "https://mailinabox.email/maintenance.html#upgrade"
TAG=v57a
GITSRC=miab
elif [ "$UBUNTU_VERSION" == "Ubuntu 14.04 LTS" ]; then
# This machine is running Ubuntu 14.04, which is supported by
# Mail-in-a-Box versions 1 through v0.30.
@@ -60,12 +63,20 @@ if [ ! -d $HOME/mailinabox ]; then
fi
echo Downloading Mail-in-a-Box $TAG. . .
git clone \
-b $TAG --depth 1 \
https://github.com/mail-in-a-box/mailinabox \
$HOME/mailinabox \
< /dev/null 2> /dev/null
if [ "$GITSRC" == "miab" ]; then
git clone \
-b $TAG --depth 1 \
https://github.com/mail-in-a-box/mailinabox \
$HOME/mailinabox \
< /dev/null 2> /dev/null
else
git clone \
-b $TAG --depth 1 \
https://github.com/kiekerjan/mailinabox \
$HOME/mailinabox \
< /dev/null 2> /dev/null
fi
echo
fi
@@ -73,7 +84,7 @@ fi
cd $HOME/mailinabox
# Update it.
if [ "$TAG" != $(git describe) ]; then
if [ "$TAG" != $(git describe --tags) ]; then
echo Updating Mail-in-a-Box to $TAG . . .
git fetch --depth 1 --force --prune origin tag $TAG
if ! git checkout -q $TAG; then

View File

@@ -1,46 +1,43 @@
#!/bin/bash
# OpenDKIM
# DKIM
# --------
#
# OpenDKIM provides a service that puts a DKIM signature on outbound mail.
# DKIMpy provides a service that puts a DKIM signature on outbound mail.
#
# The DNS configuration for DKIM is done in the management daemon.
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# Install DKIM...
echo Installing OpenDKIM/OpenDMARC...
apt_install opendkim opendkim-tools opendmarc
# Remove openDKIM if present
apt-get purge -qq -y opendkim opendkim-tools
# Install DKIMpy-Milter
echo Installing DKIMpy/OpenDMARC...
apt_install dkimpy-milter python3-dkim opendmarc
# Make sure configuration directories exist.
mkdir -p /etc/opendkim;
mkdir -p /etc/dkim;
mkdir -p $STORAGE_ROOT/mail/dkim
# Used in InternalHosts and ExternalIgnoreList configuration directives.
# Not quite sure why.
echo "127.0.0.1" > /etc/opendkim/TrustedHosts
echo "127.0.0.1" > /etc/dkim/TrustedHosts
# We need to at least create these files, since we reference them later.
# Otherwise, opendkim startup will fail
touch /etc/opendkim/KeyTable
touch /etc/opendkim/SigningTable
touch /etc/dkim/KeyTable
touch /etc/dkim/SigningTable
if grep -q "ExternalIgnoreList" /etc/opendkim.conf; then
true # already done #NODOC
else
# Add various configuration options to the end of `opendkim.conf`.
cat >> /etc/opendkim.conf << EOF;
Canonicalization relaxed/simple
MinimumKeyBits 1024
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
Socket inet:8891@127.0.0.1
RequireSafeKeys false
EOF
fi
tools/editconf.py /etc/dkimpy-milter/dkimpy-milter.conf -s \
"MacroList=daemon_name|ORIGINATING" \
"MacroListVerify=daemon_name|VERIFYING" \
"Canonicalization=relaxed/simple" \
"MinimumKeyBits=1024" \
"InternalHosts=refile:/etc/dkim/TrustedHosts" \
"KeyTable=refile:/etc/dkim/KeyTable" \
"KeyTableEd25519=refile:/etc/dkim/KeyTableEd25519" \
"SigningTable=refile:/etc/dkim/SigningTable" \
"Socket=inet:8892@127.0.0.1"
# Create a new DKIM key. This creates mail.private and mail.txt
# in $STORAGE_ROOT/mail/dkim. The former is the private key and
@@ -48,16 +45,20 @@ fi
# in our DNS setup. Note that the files are named after the
# 'selector' of the key, which we can change later on to support
# key rotation.
#
# A 1024-bit key is seen as a minimum standard by several providers
# such as Google. But they and others use a 2048 bit key, so we'll
# do the same. Keys beyond 2048 bits may exceed DNS record limits.
if [ ! -f "$STORAGE_ROOT/mail/dkim/mail.private" ]; then
opendkim-genkey -b 2048 -r -s mail -D $STORAGE_ROOT/mail/dkim
if [ ! -f "$STORAGE_ROOT/mail/dkim/box-rsa.key" ]; then
# All defaults are supposed to be ok, default key for rsa is 2048 bit
dknewkey --ktype rsa $STORAGE_ROOT/mail/dkim/box-rsa
dknewkey --ktype ed25519 $STORAGE_ROOT/mail/dkim/box-ed25519
# Force them into the format dns_update.py expects
sed -i 's/v=DKIM1;/box-rsa._domainkey IN TXT ( "v=DKIM1; s=email;/' $STORAGE_ROOT/mail/dkim/box-rsa.dns
echo '" )' >> $STORAGE_ROOT/mail/dkim/box-rsa.dns
sed -i 's/v=DKIM1;/box-ed25519._domainkey IN TXT ( "v=DKIM1; s=email;/' $STORAGE_ROOT/mail/dkim/box-ed25519.dns
echo '" )' >> $STORAGE_ROOT/mail/dkim/box-ed25519.dns
fi
# Ensure files are owned by the opendkim user and are private otherwise.
chown -R opendkim:opendkim $STORAGE_ROOT/mail/dkim
# Ensure files are owned by the dkimpy-milter user and are private otherwise.
chown -R dkimpy-milter:dkimpy-milter $STORAGE_ROOT/mail/dkim
chmod go-rwx $STORAGE_ROOT/mail/dkim
tools/editconf.py /etc/opendmarc.conf -s \
@@ -88,29 +89,20 @@ tools/editconf.py /etc/opendmarc.conf -s \
tools/editconf.py /etc/opendmarc.conf -s \
"FailureReportsOnNone=true"
# AlwaysAddARHeader Adds an "Authentication-Results:" header field even to
# unsigned messages from domains with no "signs all" policy. The reported DKIM
# result will be "none" in such cases. Normally unsigned mail from non-strict
# domains does not cause the results header field to be added. This added header
# is used by spamassassin to evaluate the mail for spamminess.
tools/editconf.py /etc/opendkim.conf -s \
"AlwaysAddARHeader=true"
# Add OpenDKIM and OpenDMARC as milters to postfix, which is how OpenDKIM
# Add DKIMpy and OpenDMARC as milters to postfix, which is how DKIMpy
# intercepts outgoing mail to perform the signing (by adding a mail header)
# and how they both intercept incoming mail to add Authentication-Results
# headers. The order possibly/probably matters: OpenDMARC relies on the
# OpenDKIM Authentication-Results header already being present.
# DKIM Authentication-Results header already being present.
#
# Be careful. If we add other milters later, this needs to be concatenated
# on the smtpd_milters line.
#
# The OpenDMARC milter is skipped in the SMTP submission listener by
# configuring smtpd_milters there to only list the OpenDKIM milter
# configuring smtpd_milters there to only list the DKIMpy milter
# (see mail-postfix.sh).
tools/editconf.py /etc/postfix/main.cf \
"smtpd_milters=inet:127.0.0.1:8891 inet:127.0.0.1:8893"\
"smtpd_milters=inet:127.0.0.1:8892 inet:127.0.0.1:8893"\
non_smtpd_milters=\$smtpd_milters \
milter_default_action=accept
@@ -118,7 +110,7 @@ tools/editconf.py /etc/postfix/main.cf \
hide_output systemctl enable opendmarc
# Restart services.
restart_service opendkim
restart_service dkimpy-milter
restart_service opendmarc
restart_service postfix

View File

@@ -12,7 +12,7 @@ source /etc/mailinabox.conf # load global vars
# Prepare nsd's configuration.
# We configure nsd before installation as we only want it to bind to some addresses
# and it otherwise will have port / bind conflicts with bind9 used as the local resolver
# and it otherwise will have port / bind conflicts with unbound used as the local resolver
mkdir -p /var/run/nsd
mkdir -p /etc/nsd
mkdir -p /etc/nsd/zones
@@ -38,7 +38,7 @@ server:
EOF
# Since we have bind9 listening on localhost for locally-generated
# Since we have unbound listening on localhost for locally-generated
# DNS queries that require a recursive nameserver, and the system
# might have other network interfaces for e.g. tunnelling, we have
# to be specific about the network interfaces that nsd binds to.

84
setup/dovecot-fts-xapian.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/bash
#
# IMAP search with xapian
# --------------------------------
#
# By default dovecot uses its own Squat search index that has awful performance
# on large mailboxes and is obsolete. Dovecot 2.1+ has support for using Lucene
# internally but this didn't make it into the Ubuntu packages. Solr uses too
# much memory. Same goes for elasticsearch. fts xapian might be a good match
# for mail-in-a-box. See https://github.com/grosjo/fts-xapian
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# Install packages and basic configuation
# ---------------------------------------
echo "Installing fts-xapian..."
apt_install dovecot-fts-xapian
# 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_xapian" \
mail_home="$STORAGE_ROOT/mail/homes/%d/%n"
# Install cronjobs to keep FTS up to date.
hide_output install -m 755 conf/cron/miab_dovecot /etc/cron.daily/
# Install files
if [ ! -f /usr/lib/dovecot/decode2text.sh ]; then
cp -f /usr/share/doc/dovecot-core/examples/decode2text.sh /usr/lib/dovecot
fi
# Create configuration file
cat > /etc/dovecot/conf.d/90-plugin-fts.conf << EOF;
plugin {
plugin = fts fts_xapian
fts = xapian
fts_xapian = partial=3 full=20 verbose=0
fts_autoindex = yes
fts_enforced = yes
fts_autoindex_exclude = \Trash
fts_autoindex_exclude2 = \Junk
fts_autoindex_exclude3 = \Spam
fts_decoder = decode2text
}
service indexer-worker {
vsz_limit = 2G
}
service decode2text {
executable = script /usr/lib/dovecot/decode2text.sh
user = dovecot
unix_listener decode2text {
mode = 0666
}
}
EOF
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).
hide_output 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 -A -q \*

View File

@@ -4,8 +4,6 @@
# -o pipefail: don't ignore errors in the non-last command in a pipeline
set -euo pipefail
PHP_VER=8.0
function hide_output {
# This function hides the output of a command unless the command fails
# and returns a non-zero exit code.
@@ -219,6 +217,13 @@ function git_clone {
rm -rf $TMPPATH $TARGETPATH
git clone -q $REPO $TMPPATH || exit 1
(cd $TMPPATH; git checkout -q $TREEISH;) || exit 1
rm -rf $TMPPATH/.git
mv $TMPPATH/$SUBDIR $TARGETPATH
rm -rf $TMPPATH
}
function php_version {
php --version | head -n 1 | cut -d " " -f 2 | cut -c 1-3
}
PHP_VER=$(php_version)

41
setup/geoipfilter.sh Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
CONFIG_FILE=/etc/geoiplookup.conf
GEOIPLOOKUP=/usr/local/bin/goiplookup
# Check existence of configuration
if [ -f "$CONFIG_FILE" ]; then
source $CONFIG_FILE
# Check required variable exists and is non-empty
if [ -z "$ALLOW_COUNTRIES" ]; then
echo "variable ALLOW_COUNTRIES is not set or empty. No countries are blocked."
exit 0
fi
else
echo "Configuration $CONFIG_FILE does not exist. No countries are blocked."
exit 0
fi
# Check existence of binary
if [ ! -x "$GEOIPLOOKUP" ]; then
echo "Geoip lookup binary $GEOIPLOOKUP does not exist. No countries are blocked."
exit 0
fi
if [ $# -ne 1 -a $# -ne 2 ]; then
echo "Usage: `basename $0` <ip>" 1>&2
exit 0 # return true in case of config issue
fi
COUNTRY=`$GEOIPLOOKUP $1 | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
[[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY"
logger "$RESPONSE geoipblocked connection from $1 ($COUNTRY) $2"
if [ $RESPONSE = "ALLOW" ]
then
exit 0
else
exit 1
fi

104
setup/geoiptoolssetup.sh Normal file
View File

@@ -0,0 +1,104 @@
#!/bin/bash
source setup/functions.sh
echo Installing geoip packages...
# geo ip filtering of ssh entries, based on https://www.axllent.org/docs/ssh-geoip/#disqus_thread
# Install geo ip lookup tool
gunzip -c tools/goiplookup.gz > /usr/local/bin/goiplookup
chmod +x /usr/local/bin/goiplookup
# check that GeoLite2-Country.mmdb is older then 2 months, to not hit the server too often
if [[ ! -d /usr/share/GeoIP || ! -f /usr/share/GeoIP/GeoLite2-Country.mmdb || $(find "/usr/share/GeoIP/GeoLite2-Country.mmdb" -mtime +60 -print) ]]; then
echo updating goiplookup database
goiplookup db-update
else
echo skipping goiplookup database update
fi
# Install geo ip filter script
cp -f setup/geoipfilter.sh /usr/local/bin/
chmod +x /usr/local/bin/geoipfilter.sh
# Install only if not yet exists, to keep user config
if [ ! -f /etc/geoiplookup.conf ]; then
cp -f conf/geoiplookup.conf /etc/
fi
# Add sshd entries for hosts.deny and hosts.allow
if grep -Fxq "sshd: ALL" /etc/hosts.deny
then
echo hosts.deny already configured
else
sed -i '/sshd: /d' /etc/hosts.deny
echo "sshd: ALL" >> /etc/hosts.deny
fi
if grep -Fxq "sshd: ALL: aclexec /usr/local/bin/geoipfilter.sh %a %s" /etc/hosts.allow
then
echo hosts.allow already configured
else
# Make sure all sshd lines are removed
sed -i '/sshd: /d' /etc/hosts.allow
echo "sshd: ALL: aclexec /usr/local/bin/geoipfilter.sh %a %s" >> /etc/hosts.allow
fi
# geo ip filtering of nginx access log, based on
# https://guides.wp-bullet.com/blocking-country-and-continent-with-nginx-geoip-on-ubuntu-18-04/
## Install geo ip lookup files
# check that GeoIP.dat is older then 2 months, to not hit the server too often
if [[ ! -d /usr/share/GeoIP || ! -f /usr/share/GeoIP/GeoIP.dat || $(find "/usr/share/GeoIP/GeoIP.dat" -mtime +60 -print) ]]; then
echo updating GeoIP database
# Move old file away if it exists
if [ -f "/usr/share/GeoIP/GeoIP.dat" ]; then
mv -f /usr/share/GeoIP/GeoIP.dat /usr/share/GeoIP/GeoIP.dat.bak
fi
hide_output wget -P /usr/share/GeoIP/ https://dl.miyuru.lk/geoip/maxmind/country/maxmind.dat.gz
if [ -f "/usr/share/GeoIP/maxmind.dat.gz" ]; then
gunzip -c /usr/share/GeoIP/maxmind.dat.gz > /usr/share/GeoIP/GeoIP.dat
rm -f /usr/share/GeoIP/maxmind.dat.gz
else
echo Did not correctly download maxmind geoip country database
fi
# If new file is not created, move the old file back
if [ ! -f "/usr/share/GeoIP/GeoIP.dat" ]; then
echo GeoIP.dat was not created
if [ -f "/usr/share/GeoIP/GeoIP.dat.bak" ]; then
mv /usr/share/GeoIP/GeoIP.dat.bak /usr/share/GeoIP/GeoIP.dat
fi
fi
# Move old file away if it exists
if [ -f "/usr/share/GeoIP/GeoIPCity.dat" ]; then
mv -f /usr/share/GeoIP/GeoIPCity.dat /usr/share/GeoIP/GeoIPCity.dat.bak
fi
hide_output wget -P /usr/share/GeoIP/ https://dl.miyuru.lk/geoip/maxmind/city/maxmind.dat.gz
if [ -f "/usr/share/GeoIP/maxmind.dat.gz" ]; then
gunzip -c /usr/share/GeoIP/maxmind.dat.gz > /usr/share/GeoIP/GeoIPCity.dat
rm -f /usr/share/GeoIP/maxmind.dat.gz
else
echo Did not correctly download maxmind geoip city database
fi
# If new file is not created, move the old file back
if [ ! -f "/usr/share/GeoIP/GeoIPCity.dat" ]; then
echo GeoIPCity.dat was not created
if [ -f "/usr/share/GeoIP/GeoIPCity.dat.bak" ]; then
mv /usr/share/GeoIP/GeoIPCity.dat.bak /usr/share/GeoIP/GeoIPCity.dat
fi
fi
else
echo skipping GeoIP database update
fi

View File

@@ -78,7 +78,7 @@ tools/editconf.py /etc/dovecot/conf.d/10-auth.conf \
"auth_mechanisms=plain login"
# Enable SSL, specify the location of the SSL certificate and private key files.
# Use Mozilla's "Intermediate" recommendations at https://ssl-config.mozilla.org/#server=dovecot&server-version=2.2.33&config=intermediate&openssl-version=1.1.1,
# Use Mozilla's "Intermediate" recommendations at https://ssl-config.mozilla.org/#server=dovecot&server-version=2.3.7.2&config=intermediate&openssl-version=1.1.1,
# except that the current version of Dovecot does not have a TLSv1.3 setting, so we only use TLSv1.2.
tools/editconf.py /etc/dovecot/conf.d/10-ssl.conf \
ssl=required \
@@ -86,9 +86,8 @@ tools/editconf.py /etc/dovecot/conf.d/10-ssl.conf \
"ssl_key=<$STORAGE_ROOT/ssl/ssl_private_key.pem" \
"ssl_min_protocol=TLSv1.2" \
"ssl_cipher_list=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" \
"ssl_prefer_server_ciphers=no" \
"ssl_dh_parameters_length=2048" \
"ssl_dh=<$STORAGE_ROOT/ssl/dh2048.pem"
"ssl_prefer_server_ciphers=yes" \
"ssl_dh=<$STORAGE_ROOT/ssl/dh4096.pem"
# Disable in-the-clear IMAP/POP because there is no reason for a user to transmit
# login credentials outside of an encrypted connection. Only the over-TLS versions
@@ -202,13 +201,15 @@ chmod -R o-rwx /etc/dovecot
# Ensure mailbox files have a directory that exists and are owned by the mail user.
mkdir -p $STORAGE_ROOT/mail/mailboxes
chown -R mail.mail $STORAGE_ROOT/mail/mailboxes
mkdir -p $STORAGE_ROOT/mail/homes
chown -R mail:mail $STORAGE_ROOT/mail/mailboxes
chown -R mail:mail $STORAGE_ROOT/mail/homes
# Same for the sieve scripts.
mkdir -p $STORAGE_ROOT/mail/sieve
mkdir -p $STORAGE_ROOT/mail/sieve/global_before
mkdir -p $STORAGE_ROOT/mail/sieve/global_after
chown -R mail.mail $STORAGE_ROOT/mail/sieve
chown -R mail:mail $STORAGE_ROOT/mail/sieve
# Allow the IMAP/POP ports in the firewall.
ufw_allow imaps

View File

@@ -91,12 +91,14 @@ tools/editconf.py /etc/postfix/master.cf -s -w \
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o syslog_name=postfix/submission
-o smtpd_milters=inet:127.0.0.1:8891
-o smtpd_milters=inet:127.0.0.1:8892
-o milter_macro_daemon_name=ORIGINATING
-o cleanup_service_name=authclean" \
"submission=inet n - - - - smtpd
-o smtpd_sasl_auth_enable=yes
-o syslog_name=postfix/submission
-o smtpd_milters=inet:127.0.0.1:8891
-o smtpd_milters=inet:127.0.0.1:8892
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_tls_security_level=encrypt
-o cleanup_service_name=authclean" \
"authclean=unix n - - - 0 cleanup
@@ -122,18 +124,18 @@ sed -i "s/PUBLIC_IP/$PUBLIC_IP/" /etc/postfix/outgoing_mail_header_filters
# the world are very far behind and if we disable too much, they may not be able to use TLS and
# won't fall back to cleartext. So we don't disable too much. smtpd_tls_exclude_ciphers applies to
# both port 25 and port 587, but because we override the cipher list for both, it probably isn't used.
# Use Mozilla's "Old" recommendations at https://ssl-config.mozilla.org/#server=postfix&server-version=3.3.0&config=old&openssl-version=1.1.1
# Use Mozilla's "Old" recommendations at https://ssl-config.mozilla.org/#server=postfix&server-version=3.4.13&config=old&openssl-version=1.1.1
tools/editconf.py /etc/postfix/main.cf \
smtpd_tls_security_level=may\
smtpd_tls_auth_only=yes \
smtpd_tls_cert_file=$STORAGE_ROOT/ssl/ssl_certificate.pem \
smtpd_tls_key_file=$STORAGE_ROOT/ssl/ssl_private_key.pem \
smtpd_tls_dh1024_param_file=$STORAGE_ROOT/ssl/dh2048.pem \
smtpd_tls_protocols="!SSLv2,!SSLv3" \
smtpd_tls_dh1024_param_file=$STORAGE_ROOT/ssl/dh4096.pem \
smtpd_tls_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \
smtpd_tls_ciphers=medium \
tls_medium_cipherlist=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA \
smtpd_tls_exclude_ciphers=aNULL,RC4 \
tls_preempt_cipherlist=no \
tls_medium_cipherlist=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 \
smtpd_tls_exclude_ciphers="MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL" \
tls_preempt_cipherlist=yes \
smtpd_tls_received_header=yes
# For ports 465/587 (via the 'mandatory' settings):
@@ -143,7 +145,15 @@ tools/editconf.py /etc/postfix/main.cf \
smtpd_tls_mandatory_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \
smtpd_tls_mandatory_ciphers=high \
tls_high_cipherlist=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 \
smtpd_tls_mandatory_exclude_ciphers=aNULL,DES,3DES,MD5,DES+MD5,RC4
smtpd_tls_mandatory_exclude_ciphers="MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL"
# Add block_root_external to block mail send to root@PRIMARY_HOSTNAME. This mail address is only supposed to be used for local
# mail delivery (cron etc)
cat > /etc/postfix/block_root_external << EOF;
root@$PRIMARY_HOSTNAME REJECT
EOF
postmap /etc/postfix/block_root_external
# Prevent non-authenticated users from sending mail that requires being
# relayed elsewhere. We don't want to be an "open relay". On outbound
@@ -152,9 +162,10 @@ tools/editconf.py /etc/postfix/main.cf \
# * `permit_sasl_authenticated`: Authenticated users (i.e. on port 465/587).
# * `permit_mynetworks`: Mail that originates locally.
# * `reject_unauth_destination`: No one else. (Permits mail whose destination is local and rejects other mail.)
# * `block_root_external`: Block mail addressed at root@PRIMARY_HOSTNAME. Root mail is only to receive mails locally send to root.
# permit_mynetworks will allow delivery of mail for root originating locally.
tools/editconf.py /etc/postfix/main.cf \
smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination,hash:/etc/postfix/block_root_external
# ### DANE
@@ -181,9 +192,10 @@ tools/editconf.py /etc/postfix/main.cf \
# even if we don't know if it's to the right party, than to not encrypt at all. Instead we'll
# now see notices about trusted certs. The CA file is provided by the package `ca-certificates`.
tools/editconf.py /etc/postfix/main.cf \
smtp_tls_protocols=\!SSLv2,\!SSLv3 \
smtp_tls_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \
smtp_tls_ciphers=medium \
smtp_tls_exclude_ciphers=aNULL,RC4 \
smtp_tls_exclude_ciphers="MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL" \
smtp_tls_mandatory_exclude_ciphers="MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL" \
smtp_tls_security_level=dane \
smtp_dns_support_level=dnssec \
smtp_tls_mandatory_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \
@@ -232,7 +244,7 @@ tools/editconf.py /etc/postfix/main.cf \
# A lot of legit mail servers try to resend before 300 seconds.
# As a matter of fact RFC is not strict about retry timer so postfix and
# other MTA have their own intervals. To fix the problem of receiving
# e-mails really latter, delay of greylisting has been set to
# e-mails really later, delay of greylisting has been set to
# 180 seconds (default is 300 seconds). We will move the postgrey database
# under $STORAGE_ROOT. This prevents a "warming up" that would have occured
# previously with a migrated or reinstalled OS. We will specify this new path
@@ -242,8 +254,9 @@ tools/editconf.py /etc/postfix/main.cf \
# (luckily $STORAGE_ROOT does not currently work with spaces), or it needs to be a
# symlink without spaces that can point to a folder with spaces). We'll just assume
# $STORAGE_ROOT won't have spaces to simplify things.
# Postgrey removes entries after 185 days of not being used.
tools/editconf.py /etc/default/postgrey \
POSTGREY_OPTS=\""--inet=127.0.0.1:10023 --delay=180 --dbdir=$STORAGE_ROOT/mail/postgrey/db"\"
POSTGREY_OPTS=\""--inet=127.0.0.1:10023 --delay=180 --max-age=185 --dbdir=$STORAGE_ROOT/mail/postgrey/db"\"
# If the $STORAGE_ROOT/mail/postgrey is empty, copy the postgrey database over from the old location

View File

@@ -51,7 +51,7 @@ driver = sqlite
connect = $db_path
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';
user_query = SELECT email AS user, "mail" as uid, "mail" as gid, "$STORAGE_ROOT/mail/mailboxes/%d/%n" as home FROM users WHERE email='%u';
user_query = SELECT email AS user, "mail" as uid, "mail" as gid, "$STORAGE_ROOT/mail/homes/%d/%n" as home FROM users WHERE email='%u';
iterate_query = SELECT email AS user FROM users;
EOF
chmod 0600 /etc/dovecot/dovecot-sql.conf.ext # per Dovecot instructions

View File

@@ -7,12 +7,15 @@ source /etc/mailinabox.conf # load global vars
# install Munin
echo "Installing Munin (system monitoring)..."
apt_install munin munin-node libcgi-fast-perl
apt_install munin munin-node libcgi-fast-perl munin-plugins-extra
# libcgi-fast-perl is needed by /usr/lib/munin/cgi/munin-cgi-graph
mkdir -p $STORAGE_ROOT/munin
chown munin:munin $STORAGE_ROOT/munin
# edit config
cat > /etc/munin/munin.conf <<EOF;
dbdir /var/lib/munin
dbdir $STORAGE_ROOT/munin
htmldir /var/cache/munin/www
logdir /var/log/munin
rundir /var/run/munin
@@ -23,19 +26,20 @@ includedir /etc/munin/munin-conf.d
# path dynazoom uses for requests
cgiurl_graph /admin/munin/cgi-graph
# send alerts to the following address
contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
contact.admin.always_send warning critical
# a simple host tree
[$PRIMARY_HOSTNAME]
address 127.0.0.1
# send alerts to the following address
contacts admin
contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
contact.admin.always_send warning critical
EOF
# The Debian installer touches these files and chowns them to www-data:adm for use with spawn-fcgi
chown munin. /var/log/munin/munin-cgi-html.log
chown munin. /var/log/munin/munin-cgi-graph.log
chown munin /var/log/munin/munin-cgi-html.log
chown munin /var/log/munin/munin-cgi-graph.log
# ensure munin-node knows the name of this machine
# and reduce logging level to warning
@@ -70,6 +74,23 @@ hide_output systemctl daemon-reload
hide_output systemctl unmask munin.service
hide_output systemctl enable munin.service
# Some more munin plugins
if [ -f /usr/share/munin/plugins/postfix_mailstats ] && [ ! -h /etc/munin/plugins/postfix_mailstats ]; then
ln -fs /usr/share/munin/plugins/postfix_mailstats /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/spamstats ] && [ ! -h /etc/munin/plugins/spamstats ]; then
ln -fs /usr/share/munin/plugins/spamstats /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/df_abs ] && [ ! -h /etc/munin/plugins/df_abs ]; then
ln -fs /usr/share/munin/plugins/df_abs /etc/munin/plugins/
fi
if [ -f /usr/share/munin/plugins/fail2ban ] && [ ! -h /etc/munin/plugins/fail2ban ]; then
ln -fs /usr/share/munin/plugins/fail2ban /etc/munin/plugins/
fi
# Restart services.
restart_service munin
restart_service munin-node

View File

@@ -21,38 +21,38 @@ echo "Installing Nextcloud (contacts/calendar)..."
# we automatically install intermediate versions as needed.
# * The hash is the SHA1 hash of the ZIP package, which you can find by just running this script and
# copying it from the error message when it doesn't match what is below.
nextcloud_ver=23.0.10
nextcloud_hash=8831c7862e39460fbb789bacac8729fab0ba02dd
nextcloud_ver=24.0.9
nextcloud_hash=e7e7e580f95772c4e390e3b656129282b3967a16
# Nextcloud apps
# --------------
# * Find the most recent tag that is compatible with the Nextcloud version above by
# consulting the <dependencies>...<nextcloud> node at:
# https://github.com/nextcloud-releases/contacts/blob/main/appinfo/info.xml
# https://github.com/nextcloud-releases/calendar/blob/main/appinfo/info.xml
# https://github.com/nextcloud-releases/contacts/blob/master/appinfo/info.xml
# https://github.com/nextcloud-releases/calendar/blob/master/appinfo/info.xml
# https://github.com/nextcloud/user_external/blob/master/appinfo/info.xml
# * The hash is the SHA1 hash of the ZIP package, which you can find by just running this script and
# copying it from the error message when it doesn't match what is below.
contacts_ver=4.2.2
contacts_hash=ca13d608ed8955aa374cb4f31b6026b57ef88887
calendar_ver=3.5.1
calendar_hash=c8136a3deb872a3ef73ce1155b58f3ab27ec7110
user_external_ver=3.0.0
user_external_hash=0df781b261f55bbde73d8c92da3f99397000972f
calendar_ver=3.5.5
calendar_hash=8505abcf7b3ab2f32d7ca1593b545e577cbeedb4
user_external_ver=3.1.0
user_external_hash=399fe1150b28a69aaf5bfcad3227e85706604a44
# Clear prior packages and install dependencies from apt.
apt-get purge -qq -y owncloud* # we used to use the package manager
apt_install curl php${PHP_VER} php${PHP_VER}-fpm \
php${PHP_VER}-cli php${PHP_VER}-sqlite3 php${PHP_VER}-gd php${PHP_VER}-imap php${PHP_VER}-curl \
php${PHP_VER}-dev php${PHP_VER}-gd php${PHP_VER}-xml php${PHP_VER}-mbstring php${PHP_VER}-zip php${PHP_VER}-apcu \
php${PHP_VER}-intl php${PHP_VER}-imagick php${PHP_VER}-gmp php${PHP_VER}-bcmath
apt_install php php-fpm \
php-cli php-sqlite3 php-gd php-imap php-curl php-pear curl \
php-dev php-xml php-mbstring php-zip php-apcu php-json \
php-intl php-imagick php-gmp php-bcmath
# Enable APC before Nextcloud tools are run.
tools/editconf.py /etc/php/$PHP_VER/mods-available/apcu.ini -c ';' \
apc.enabled=1 \
apc.enable_cli=1
apc.enabled=1 \
apc.enable_cli=1
InstallNextcloud() {
@@ -69,8 +69,8 @@ InstallNextcloud() {
echo "Upgrading to Nextcloud version $version"
echo
# Download and verify
wget_verify https://download.nextcloud.com/server/releases/nextcloud-$version.zip $hash /tmp/nextcloud.zip
# Download and verify
wget_verify https://download.nextcloud.com/server/releases/nextcloud-$version.zip $hash /tmp/nextcloud.zip
# Remove the current owncloud/Nextcloud
rm -rf /usr/local/lib/owncloud
@@ -80,6 +80,9 @@ InstallNextcloud() {
mv /usr/local/lib/nextcloud /usr/local/lib/owncloud
rm -f /tmp/nextcloud.zip
# Empty the skeleton dir to save some space for each new user
rm -rf /usr/local/lib/owncloud/core/skeleton/*
# The two apps we actually want are not in Nextcloud core. Download the releases from
# their github repositories.
mkdir -p /usr/local/lib/owncloud/apps
@@ -95,7 +98,7 @@ InstallNextcloud() {
# Starting with Nextcloud 15, the app user_external is no longer included in Nextcloud core,
# we will install from their github repository.
if [ -n "$version_user_external" ]; then
wget_verify https://github.com/nextcloud-releases/user_external/releases/download/v$version_user_external/user_external-v$version_user_external.tar.gz $hash_user_external /tmp/user_external.tgz
wget_verify https://github.com/nextcloud/user_external/archive/refs/tags/v$version_user_external.tar.gz $hash_user_external /tmp/user_external.tgz
tar -xf /tmp/user_external.tgz -C /usr/local/lib/owncloud/apps/
rm /tmp/user_external.tgz
fi
@@ -110,27 +113,27 @@ InstallNextcloud() {
# Make sure permissions are correct or the upgrade step won't run.
# $STORAGE_ROOT/owncloud may not yet exist, so use -f to suppress
# that error.
chown -f -R www-data.www-data $STORAGE_ROOT/owncloud /usr/local/lib/owncloud || /bin/true
chown -f -R www-data:www-data $STORAGE_ROOT/owncloud /usr/local/lib/owncloud || /bin/true
# If this isn't a new installation, immediately run the upgrade script.
# Then check for success (0=ok and 3=no upgrade needed, both are success).
if [ -e $STORAGE_ROOT/owncloud/owncloud.db ]; then
# ownCloud 8.1.1 broke upgrades. It may fail on the first attempt, but
# that can be OK.
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ upgrade
sudo -u www-data php /usr/local/lib/owncloud/occ upgrade
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then
echo "Trying ownCloud upgrade again to work around ownCloud upgrade bug..."
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ upgrade
sudo -u www-data php /usr/local/lib/owncloud/occ upgrade
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then exit 1; fi
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ maintenance:mode --off
sudo -u www-data php /usr/local/lib/owncloud/occ maintenance:mode --off
echo "...which seemed to work."
fi
# Add missing indices. NextCloud didn't include this in the normal upgrade because it might take some time.
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ db:add-missing-indices
sudo -u www-data php /usr/local/lib/owncloud/occ db:add-missing-indices
# Run conversion to BigInt identifiers, this process may take some time on large tables.
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ db:convert-filecache-bigint --no-interaction
sudo -u www-data php /usr/local/lib/owncloud/occ db:convert-filecache-bigint --no-interaction
fi
}
@@ -141,8 +144,26 @@ InstallNextcloud() {
# application version than the database.
# If config.php exists, get version number, otherwise CURRENT_NEXTCLOUD_VER is empty.
#
# Config unlocking, power-mailinabox#86
# If a configuration file already exists, remove the "readonly" tag before starting the upgrade. This is
# necessary (otherwise upgrades will fail).
#
# The lock will be re-applied further down the line when it's safe to do so.
CONFIG_TEMP=$(/bin/mktemp)
if [ -f "$STORAGE_ROOT/owncloud/config.php" ]; then
CURRENT_NEXTCLOUD_VER=$(php$PHP_VER -r "include(\"$STORAGE_ROOT/owncloud/config.php\"); echo(\$CONFIG['version']);")
CURRENT_NEXTCLOUD_VER=$(php -r "include(\"$STORAGE_ROOT/owncloud/config.php\"); echo(\$CONFIG['version']);")
# Unlock configuration directory for upgrades
php <<EOF > $CONFIG_TEMP && mv $CONFIG_TEMP $STORAGE_ROOT/owncloud/config.php;
<?php
include("$STORAGE_ROOT/owncloud/config.php");
\$CONFIG['config_is_read_only'] = false;
echo "<?php\n\\\$CONFIG = ";
var_export(\$CONFIG);
echo ";";
?>
EOF
else
CURRENT_NEXTCLOUD_VER=""
fi
@@ -184,15 +205,71 @@ if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextc
return 0
fi
if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^20 ]]; then
InstallNextcloud 21.0.7 f5c7079c5b56ce1e301c6a27c0d975d608bb01c9 4.0.7 45e7cf4bfe99cd8d03625cf9e5a1bb2e90549136 3.0.4 d0284b68135777ec9ca713c307216165b294d0fe
# Version 20 is the latest version from the 18.04 version of miab. To upgrade to version 21, install php8.0. This is
# not supported by version 20, but that does not matter, as the InstallNextcloud function only runs the version 21 code.
# Install the ppa
add-apt-repository --yes ppa:ondrej/php
# Prevent installation of old packages
apt-mark hold php7.0-apcu php7.1-apcu php7.2-apcu php7.3-apcu php7.4-apcu
# Install older php version
apt_install php8.0 php8.0-fpm php8.0-apcu php8.0-cli php8.0-sqlite3 php8.0-gd php8.0-imap \
php8.0-curl php8.0-dev php8.0-xml php8.0-mbstring php8.0-zip
# set older php version as default
update-alternatives --set php /usr/bin/php8.0
tools/editconf.py /etc/php/$(php_version)/mods-available/apcu.ini -c ';' \
apc.enabled=1 \
apc.enable_cli=1
# Install nextcloud, this also updates user_external to 2.1.0
InstallNextcloud 21.0.7 f5c7079c5b56ce1e301c6a27c0d975d608bb01c9 4.0.7 45e7cf4bfe99cd8d03625cf9e5a1bb2e90549136 3.0.4 d0284b68135777ec9ca713c307216165b294d0fe 2.1.0 41d4c57371bd085d68421b52ab232092d7dfc882
CURRENT_NEXTCLOUD_VER="21.0.7"
fi
if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^21 ]]; then
InstallNextcloud 22.2.6 9d39741f051a8da42ff7df46ceef2653a1dc70d9 4.1.0 697f6b4a664e928d72414ea2731cb2c9d1dc3077 3.2.2 ce4030ab57f523f33d5396c6a81396d440756f5f 3.0.0 0df781b261f55bbde73d8c92da3f99397000972f
CURRENT_NEXTCLOUD_VER="22.2.6"
InstallNextcloud 22.2.3 58d2d897ba22a057aa03d29c762c5306211fefd2 4.0.7 45e7cf4bfe99cd8d03625cf9e5a1bb2e90549136 3.0.4 d0284b68135777ec9ca713c307216165b294d0fe 2.1.0 41d4c57371bd085d68421b52ab232092d7dfc882
CURRENT_NEXTCLOUD_VER="22.2.3"
fi
if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^22 ]]; then
InstallNextcloud 23.0.2 645cba42cab57029ebe29fb93906f58f7abea5f8 4.0.8 fc626ec02732da13a4c600baae64ab40557afdca 3.0.6 e40d919b4b7988b46671a78cb32a43d8c7cba332 3.0.0 9e7aaf7288032bd463c480bc368ff91869122950
CURRENT_NEXTCLOUD_VER="23.0.2"
# Remove older php version
update-alternatives --auto php
apt-get purge -qq -y php8.0 php8.0-fpm php8.0-apcu php8.0-cli php8.0-sqlite3 php8.0-gd \
php8.0-imap php8.0-curl php8.0-dev php8.0-xml php8.0-mbstring php8.0-zip \
php8.0-common php8.0-opcache php8.0-readline
# Remove the ppa
add-apt-repository --yes --remove ppa:ondrej/php
fi
fi
# nextcloud version - supported php versions
# 20 - 7.2, 7.3, 7.4
# 21 - 7.3, 7.4, 8.0
# 22 - 7.3, 7.4, 8.0
# 23 - 7.3, 7.4, 8.0
# 24 - 7.4, 8.0, 8.1
#
# ubuntu 18.04 has php 7.2
# ubuntu 22.04 has php 8.1
#
# user_external 2.1.0 supports version 21-22
# user_external 2.1.0 supports version 22-24
#
# upgrade path
# - install ppa: sudo add-apt-repository ppa:ondrej/php
# - upgrade php to version 8.0 (nextcloud will no longer function)
# - upgrade nextcloud to 21 and user_external to 2.1.0
# - upgrade nextcloud to 22
# - upgrade nextcloud to 23 and user_external to 3.0.0
# - upgrade nextcloud to 24
InstallNextcloud $nextcloud_ver $nextcloud_hash $contacts_ver $contacts_hash $calendar_ver $calendar_hash $user_external_ver $user_external_hash
fi
@@ -220,9 +297,9 @@ if [ ! -f $STORAGE_ROOT/owncloud/owncloud.db ]; then
'user_backends' => array(
array(
'class' => '\OCA\UserExternal\IMAP',
'arguments' => array(
'arguments' => array(
'127.0.0.1', 143, null, null, false, false
),
),
),
),
'memcache.local' => '\OC\Memcache\APCu',
@@ -259,12 +336,12 @@ EOF
EOF
# Set permissions
chown -R www-data.www-data $STORAGE_ROOT/owncloud /usr/local/lib/owncloud
chown -R www-data:www-data $STORAGE_ROOT/owncloud /usr/local/lib/owncloud
# Execute Nextcloud's setup step, which creates the Nextcloud sqlite database.
# It also wipes it if it exists. And it updates config.php with database
# settings and deletes the autoconfig.php file.
(cd /usr/local/lib/owncloud; sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/index.php;)
(cd /usr/local/lib/owncloud; sudo -u www-data php /usr/local/lib/owncloud/index.php;)
fi
# Update config.php.
@@ -279,8 +356,7 @@ fi
# the correct domain name if the domain is being change from the previous setup.
# Use PHP to read the settings file, modify it, and write out the new settings array.
TIMEZONE=$(cat /etc/timezone)
CONFIG_TEMP=$(/bin/mktemp)
php$PHP_VER <<EOF > $CONFIG_TEMP && mv $CONFIG_TEMP $STORAGE_ROOT/owncloud/config.php;
php <<EOF > $CONFIG_TEMP && mv $CONFIG_TEMP $STORAGE_ROOT/owncloud/config.php;
<?php
include("$STORAGE_ROOT/owncloud/config.php");
@@ -294,6 +370,8 @@ include("$STORAGE_ROOT/owncloud/config.php");
\$CONFIG['logtimezone'] = '$TIMEZONE';
\$CONFIG['logdateformat'] = 'Y-m-d H:i:s';
\$CONFIG['log_type'] = 'syslog';
\$CONFIG['syslog_tag'] = 'Nextcloud';
\$CONFIG['mail_domain'] = '$PRIMARY_HOSTNAME';
@@ -311,28 +389,41 @@ var_export(\$CONFIG);
echo ";";
?>
EOF
chown www-data.www-data $STORAGE_ROOT/owncloud/config.php
chown www-data:www-data $STORAGE_ROOT/owncloud/config.php
# Enable/disable apps. Note that this must be done after the Nextcloud setup.
# The firstrunwizard gave Josh all sorts of problems, so disabling that.
# user_external is what allows Nextcloud to use IMAP for login. The contacts
# and calendar apps are the extensions we really care about here.
hide_output sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/console.php app:disable firstrunwizard
hide_output sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/console.php app:enable user_external
hide_output sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/console.php app:enable contacts
hide_output sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/console.php app:enable calendar
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:disable firstrunwizard
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:enable user_external
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:enable contacts
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:enable calendar
# When upgrading, run the upgrade script again now that apps are enabled. It seems like
# the first upgrade at the top won't work because apps may be disabled during upgrade?
# Check for success (0=ok, 3=no upgrade needed).
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ upgrade
sudo -u www-data php /usr/local/lib/owncloud/occ upgrade
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then exit 1; fi
# Disable default apps that we don't support
sudo -u www-data \
php$PHP_VER /usr/local/lib/owncloud/occ app:disable photos dashboard activity \
php /usr/local/lib/owncloud/occ app:disable photos dashboard activity \
| (grep -v "No such app enabled" || /bin/true)
# Install interesting apps
(sudo -u www-data php /usr/local/lib/owncloud/occ app:install notes) || true
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:enable notes
(sudo -u www-data php /usr/local/lib/owncloud/occ app:install twofactor_totp) || true
hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:enable twofactor_totp
# upgrade apps
sudo -u www-data php /usr/local/lib/owncloud/occ app:update --all
# Set PHP FPM values to support large file uploads
# (semicolon is the comment character in this file, hashes produce deprecation warnings)
tools/editconf.py /etc/php/$PHP_VER/fpm/php.ini -c ';' \
@@ -363,7 +454,7 @@ sqlite3 $STORAGE_ROOT/owncloud/owncloud.db "UPDATE oc_users_external SET backend
cat > /etc/cron.d/mailinabox-nextcloud << EOF;
#!/bin/bash
# Mail-in-a-Box
*/5 * * * * root sudo -u www-data php$PHP_VER -f /usr/local/lib/owncloud/cron.php
*/5 * * * * root sudo -u www-data php -f /usr/local/lib/owncloud/cron.php
EOF
chmod +x /etc/cron.d/mailinabox-nextcloud

View File

@@ -7,7 +7,7 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
# Check that we are running on Ubuntu 20.04 LTS (or 20.04.xx).
# Check that we are running on Ubuntu 22.04 LTS (or 22.04.xx).
if [ "$( lsb_release --id --short )" != "Ubuntu" ] || [ "$( lsb_release --release --short )" != "22.04" ]; then
echo "Mail-in-a-Box only supports being installed on Ubuntu 22.04, sorry. You are running:"
echo

View File

@@ -9,7 +9,7 @@ if [ -z "${NONINTERACTIVE:-}" ]; then
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
echo Installing packages needed for setup...
apt-get -q -q update
apt_get_quiet install dialog python3 python3-pip || exit 1
apt_get_quiet install dialog file python3 python3-pip || exit 1
fi
# Installing email_validator is repeated in setup/management.sh, but in setup/management.sh
@@ -119,6 +119,24 @@ if [ -z "${PUBLIC_IP:-}" ]; then
fi
fi
if [ -z "${ADMIN_HOME_IP:-}" ]; then
if [ -z "${DEFAULT_ADMIN_HOME_IP:-}" ]; then
input_box "Admin Home IP Address" \
"Enter the public IP address of the admin home, as given to you by your ISP.
This will be used to prevent banning of the administrator IP address.
\n\nAdmin Home IP address:" \
"" \
ADMIN_HOME_IP
else
ADMIN_HOME_IP=$DEFAULT_ADMIN_HOME_IP
fi
fi
if [ -z "${ADMIN_HOME_IP:-}" ]; then
ADMIN_HOME_IP=""
fi
# Same for IPv6. But it's optional. Also, if it looks like the system
# doesn't have an IPv6, don't ask for one.
if [ -z "${PUBLIC_IPV6:-}" ]; then
@@ -193,6 +211,11 @@ if [ -z "${STORAGE_ROOT:-}" ]; then
STORAGE_ROOT=$([[ -z "${DEFAULT_STORAGE_ROOT:-}" ]] && echo "/home/$STORAGE_USER" || echo "$DEFAULT_STORAGE_ROOT")
fi
# Set BACKUP_ROOT to default (empty) value, unless we've already got it from a previous run.
if [ -z "${BACKUP_ROOT:-}" ]; then
BACKUP_ROOT=""
fi
# Show the configuration, since the user may have not entered it manually.
echo
echo "Primary Hostname: $PRIMARY_HOSTNAME"
@@ -206,7 +229,10 @@ fi
if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then
echo "Private IPv6 Address: $PRIVATE_IPV6"
fi
if [ -n "$ADMIN_HOME_IP" ]; then
echo "Admin Home IP Address: $ADMIN_HOME_IP"
fi
if [ -f /usr/bin/git ] && [ -d .git ]; then
echo "Mail-in-a-Box Version: " $(git describe)
echo "Mail-in-a-Box Version: " $(git describe --tags)
fi
echo

View File

@@ -195,3 +195,4 @@ chmod 770 $STORAGE_ROOT/mail/spamassassin
restart_service spampd
restart_service dovecot
systemctl enable spamassassin.service

View File

@@ -28,7 +28,7 @@ source /etc/mailinabox.conf # load global vars
if [ ! -f /usr/bin/openssl ] \
|| [ ! -f $STORAGE_ROOT/ssl/ssl_private_key.pem ] \
|| [ ! -f $STORAGE_ROOT/ssl/ssl_certificate.pem ] \
|| [ ! -f $STORAGE_ROOT/ssl/dh2048.pem ]; then
|| [ ! -f $STORAGE_ROOT/ssl/dh4096.pem ]; then
echo "Creating initial SSL certificate and perfect forward secrecy Diffie-Hellman parameters..."
fi
@@ -40,6 +40,9 @@ apt_install openssl
mkdir -p $STORAGE_ROOT/ssl
# make directory readable
chmod 755 $STORAGE_ROOT/ssl
# Generate a new private key.
#
# The key is only as good as the entropy available to openssl so that it
@@ -63,7 +66,7 @@ mkdir -p $STORAGE_ROOT/ssl
if [ ! -f $STORAGE_ROOT/ssl/ssl_private_key.pem ]; then
# Set the umask so the key file is never world-readable.
(umask 077; hide_output \
openssl genrsa -out $STORAGE_ROOT/ssl/ssl_private_key.pem 2048)
openssl genrsa -out $STORAGE_ROOT/ssl/ssl_private_key.pem 4096)
fi
# Generate a self-signed SSL certificate because things like nginx, dovecot,
@@ -90,9 +93,7 @@ if [ ! -f $STORAGE_ROOT/ssl/ssl_certificate.pem ]; then
ln -s $CERT $STORAGE_ROOT/ssl/ssl_certificate.pem
fi
# Generate some Diffie-Hellman cipher bits.
# openssl's default bit length for this is 1024 bits, but we'll create
# 2048 bits of bits per the latest recommendations.
if [ ! -f $STORAGE_ROOT/ssl/dh2048.pem ]; then
openssl dhparam -out $STORAGE_ROOT/ssl/dh2048.pem 2048
fi
# We no longer generate Diffie-Hellman cipher bits. Following rfc7919 we use
# a predefined finite field group, in this case ffdhe4096 from
# https://raw.githubusercontent.com/internetstandards/dhe_groups/master/ffdhe4096.pem
cp -f conf/dh4096.pem $STORAGE_ROOT/ssl/

View File

@@ -14,9 +14,14 @@ source setup/preflight.sh
# Python may not be able to read/write files. This is also
# in the management daemon startup script and the cron script.
# Make sure we have locales at all (some images are THAT minimal)
apt_get_quiet install locales
if ! locale -a | grep en_US.utf8 > /dev/null; then
echo "Generating locales..."
# Generate locale if not exists
hide_output locale-gen en_US.UTF-8
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
hide_output locale-gen
fi
export LANGUAGE=en_US.UTF-8
@@ -53,8 +58,8 @@ chmod +x /usr/local/bin/mailinabox
# Ask the user for the PRIMARY_HOSTNAME, PUBLIC_IP, and PUBLIC_IPV6,
# if values have not already been set in environment variables. When running
# non-interactively, be sure to set values for all! Also sets STORAGE_USER and
# STORAGE_ROOT.
# non-interactively, be sure to set values for all! Also sets STORAGE_USER,
# STORAGE_ROOT and BACKUP_ROOT.
source setup/questions.sh
# Run some network checks to make sure setup on this machine makes sense.
@@ -85,7 +90,7 @@ f=$STORAGE_ROOT
while [[ $f != / ]]; do chmod a+rx "$f"; f=$(dirname "$f"); done;
if [ ! -f $STORAGE_ROOT/mailinabox.version ]; then
setup/migrate.py --current > $STORAGE_ROOT/mailinabox.version
chown $STORAGE_USER.$STORAGE_USER $STORAGE_ROOT/mailinabox.version
chown $STORAGE_USER:$STORAGE_USER $STORAGE_ROOT/mailinabox.version
fi
# Save the global options in /etc/mailinabox.conf so that standalone
@@ -95,29 +100,34 @@ fi
cat > /etc/mailinabox.conf << EOF;
STORAGE_USER=$STORAGE_USER
STORAGE_ROOT=$STORAGE_ROOT
BACKUP_ROOT=$BACKUP_ROOT
PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME
PUBLIC_IP=$PUBLIC_IP
PUBLIC_IPV6=$PUBLIC_IPV6
PRIVATE_IP=$PRIVATE_IP
PRIVATE_IPV6=$PRIVATE_IPV6
MTA_STS_MODE=${DEFAULT_MTA_STS_MODE:-enforce}
ADMIN_HOME_IP=$ADMIN_HOME_IP
ADMIN_HOME_IPV6=
EOF
# Start service configuration.
source setup/system.sh
source setup/geoiptoolssetup.sh
source setup/ssl.sh
source setup/dns.sh
source setup/mail-postfix.sh
source setup/mail-dovecot.sh
source setup/mail-users.sh
source setup/dovecot-fts-xapian.sh
source setup/dkim.sh
source setup/spamassassin.sh
source setup/web.sh
source setup/webmail.sh
source setup/nextcloud.sh
source setup/zpush.sh
source setup/management.sh
source setup/munin.sh
source setup/additionals.sh
# Wait for the management daemon to start...
until nc -z -w 4 127.0.0.1 10222
@@ -167,7 +177,7 @@ if management/status_checks.py --check-primary-hostname; then
echo "If you have a DNS problem put the box's IP address in the URL"
echo "(https://$PUBLIC_IP/admin) but then check the TLS fingerprint:"
openssl x509 -in $STORAGE_ROOT/ssl/ssl_certificate.pem -noout -fingerprint -sha256\
| sed "s/SHA256 Fingerprint=//"
| sed "s/SHA256 Fingerprint=//i"
else
echo https://$PUBLIC_IP/admin
echo
@@ -175,7 +185,7 @@ else
echo the certificate fingerprint matches:
echo
openssl x509 -in $STORAGE_ROOT/ssl/ssl_certificate.pem -noout -fingerprint -sha256\
| sed "s/SHA256 Fingerprint=//"
| sed "s/SHA256 Fingerprint=//i"
echo
echo Then you can confirm the security exception and continue.
echo

View File

@@ -82,6 +82,8 @@ fi
# (See https://discourse.mailinabox.email/t/journalctl-reclaim-space-on-small-mailinabox/6728/11.)
tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=10day
hide_output systemctl restart systemd-journald.service
# ### Add PPAs.
# We install some non-standard Ubuntu packages maintained by other
@@ -99,11 +101,6 @@ hide_output add-apt-repository -y universe
# Install the duplicity PPA.
hide_output add-apt-repository -y ppa:duplicity-team/duplicity-release-git
# Stock PHP is now 8.1, but we're transitioning through 8.0 because
# of Nextcloud.
hide_output add-apt-repository --y ppa:ondrej/php
# ### Update Packages
# Update system packages to make sure we have the latest upstream versions
@@ -124,6 +121,9 @@ apt_get_quiet autoremove
# Install basic utilities.
#
# * haveged: Provides extra entropy to /dev/random so it doesn't stall
# when generating random numbers for private keys (e.g. during
# ldns-keygen).
# * unattended-upgrades: Apt tool to install security updates automatically.
# * cron: Runs background processes periodically.
# * ntp: keeps the system time correct
@@ -137,9 +137,9 @@ apt_get_quiet autoremove
echo Installing system packages...
apt_install python3 python3-dev python3-pip python3-setuptools \
netcat-openbsd wget curl git sudo coreutils bc file \
pollinate openssh-client unzip \
unattended-upgrades cron ntp fail2ban rsyslog
netcat-openbsd wget curl git sudo coreutils bc \
haveged pollinate openssh-client unzip \
unattended-upgrades cron ntp fail2ban rsyslog file
# ### Suppress Upgrade Prompts
# When Ubuntu 20 comes out, we don't want users to be prompted to upgrade,
@@ -254,6 +254,21 @@ APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Verbose "0";
EOF
# Adjust apt update and upgrade timers such that they're always before daily status
# checks and thus never report upgrades unless user intervention is necessary.
mkdir -p /etc/systemd/system/apt-daily.timer.d
cat > /etc/systemd/system/apt-daily.timer.d/override.conf <<EOF;
[Timer]
RandomizedDelaySec=5h
EOF
mkdir -p /etc/systemd/system/apt-daily-upgrade.timer.d
cat > /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf <<EOF;
[Timer]
OnCalendar=
OnCalendar=*-*-* 23:30
EOF
# ### Firewall
# Various virtualized environments like Docker and some VPSs don't provide #NODOC
@@ -263,20 +278,21 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then
# Install `ufw` which provides a simple firewall configuration.
apt_install ufw
# Allow incoming connections to SSH.
ufw_limit ssh;
# ssh might be running on an alternate port. Use sshd -T to dump sshd's #NODOC
# settings, find the port it is supposedly running on, and open that port #NODOC
# too. #NODOC
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
if [ ! -z "$SSH_PORT" ]; then
if [ "$SSH_PORT" != "22" ]; then
echo Opening alternate SSH port $SSH_PORT. #NODOC
ufw_limit $SSH_PORT #NODOC
fi
if [ "$SSH_PORT" != "22" ]; then
echo Opening alternate SSH port $SSH_PORT. #NODOC
ufw_limit $SSH_PORT #NODOC
else
# Allow incoming connections to SSH.
ufw_limit ssh;
fi
else
# Allow incoming connections to SSH.
ufw_limit ssh;
fi
ufw --force enable;
@@ -314,45 +330,42 @@ fi #NODOC
# DNS server, which won't work for RBLs. So we really need a local recursive
# nameserver.
#
# We'll install `bind9`, which as packaged for Ubuntu, has DNSSEC enabled by default via "dnssec-validation auto".
# We'll install unbound, which as packaged for Ubuntu, has DNSSEC enabled by default.
# We'll have it be bound to 127.0.0.1 so that it does not interfere with
# the public, recursive nameserver `nsd` bound to the public ethernet interfaces.
#
# About the settings:
#
# * Adding -4 to OPTIONS will have `bind9` not listen on IPv6 addresses
# so that we're sure there's no conflict with nsd, our public domain
# name server, on IPV6.
# * The listen-on directive in named.conf.options restricts `bind9` to
# binding to the loopback interface instead of all interfaces.
# * The max-recursion-queries directive increases the maximum number of iterative queries.
# If more queries than specified are sent, bind9 returns SERVFAIL. After flushing the cache during system checks,
# we ran into the limit thus we are increasing it from 75 (default value) to 100.
apt_install bind9
tools/editconf.py /etc/default/named \
"OPTIONS=\"-u bind -4\""
if ! grep -q "listen-on " /etc/bind/named.conf.options; then
# Add a listen-on directive if it doesn't exist inside the options block.
sed -i "s/^}/\n\tlisten-on { 127.0.0.1; };\n}/" /etc/bind/named.conf.options
fi
if ! grep -q "max-recursion-queries " /etc/bind/named.conf.options; then
# Add a max-recursion-queries directive if it doesn't exist inside the options block.
sed -i "s/^}/\n\tmax-recursion-queries 100;\n}/" /etc/bind/named.conf.options
# remove bind9 in case it is still there
apt-get purge -qq -y bind9 bind9-utils
# Install unbound and dns utils (e.g. dig)
apt_install unbound python3-unbound bind9-dnsutils
# Configure unbound
cp -f conf/unbound.conf /etc/unbound/unbound.conf.d/miabunbound.conf
mkdir -p /etc/unbound/lists.d
systemctl restart unbound
unbound-control -q status
# Only reset the local dns settings if unbound server is running, otherwise we'll
# up with a system with an unusable internet connection
if [ $? -ne 0 ]; then
echo "Recursive DNS server not active"
exit 1
fi
# First we'll disable systemd-resolved's management of resolv.conf and its stub server.
# Breaking the symlink to /run/systemd/resolve/stub-resolv.conf means
# systemd-resolved will read it for DNS servers to use. Put in 127.0.0.1,
# which is where bind9 will be running. Obviously don't do this before
# installing bind9 or else apt won't be able to resolve a server to
# download bind9 from.
# Modify systemd settings
rm -f /etc/resolv.conf
tools/editconf.py /etc/systemd/resolved.conf DNSStubListener=no
tools/editconf.py /etc/systemd/resolved.conf \
DNS=127.0.0.1 \
DNSSEC=yes \
DNSStubListener=no
echo "nameserver 127.0.0.1" > /etc/resolv.conf
# Restart the DNS services.
restart_service bind9
systemctl restart systemd-resolved
# ### Fail2Ban Service
@@ -360,12 +373,41 @@ systemctl restart systemd-resolved
# Configure the Fail2Ban installation to prevent dumb bruce-force attacks against dovecot, postfix, ssh, etc.
rm -f /etc/fail2ban/jail.local # we used to use this file but don't anymore
rm -f /etc/fail2ban/jail.d/defaults-debian.conf # removes default config so we can manage all of fail2ban rules in one config
if [ ! -z "$ADMIN_HOME_IPV6" ]; then
ADMIN_HOME_IPV6_FB="${ADMIN_HOME_IPV6}/64"
else
ADMIN_HOME_IPV6_FB=""
fi
cat conf/fail2ban/jails.conf \
| sed "s/PUBLIC_IPV6/$PUBLIC_IPV6/g" \
| sed "s/PUBLIC_IPV6/$PUBLIC_IPV6/g" \
| sed "s/PUBLIC_IP/$PUBLIC_IP/g" \
| sed "s/ADMIN_HOME_IPV6/$ADMIN_HOME_IPV6_FB/g" \
| sed "s/ADMIN_HOME_IP/$ADMIN_HOME_IP/g" \
| sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \
> /etc/fail2ban/jail.d/mailinabox.conf
> /etc/fail2ban/jail.d/00-mailinabox.conf
cp -f conf/fail2ban/filter.d/* /etc/fail2ban/filter.d/
cp -f conf/fail2ban/jail.d/* /etc/fail2ban/jail.d/
# If SSH port is not default, add the not default to the ssh jail
if [ ! -z "$SSH_PORT" ]; then
# create backup copy
cp -f /etc/fail2ban/jail.conf /etc/fail2ban/jail.conf.miab_old
if [ "$SSH_PORT" != "22" ]; then
# Add alternative SSH port
sed -i "s/port[ ]\+=[ ]\+ssh$/port = ssh,$SSH_PORT/g" /etc/fail2ban/jail.conf
sed -i "s/port[ ]\+=[ ]\+ssh$/port = ssh,$SSH_PORT/g" /etc/fail2ban/jail.d/geoipblock.conf
else
# Set SSH port to default
sed -i "s/port[ ]\+=[ ]\+ssh/port = ssh/g" /etc/fail2ban/jail.conf
sed -i "s/port[ ]\+=[ ]\+ssh/port = ssh/g" /etc/fail2ban/jail.d/geoipblock.conf
fi
fi
# fail2ban should be able to look back far enough because we increased findtime of recidive jail
tools/editconf.py /etc/fail2ban/fail2ban.conf dbpurgeage=7d
# On first installation, the log files that the jails look at don't all exist.
# e.g., The roundcube error log isn't normally created until someone logs into
@@ -373,3 +415,8 @@ cp -f conf/fail2ban/filter.d/* /etc/fail2ban/filter.d/
# scripts will ensure the files exist and then fail2ban is given another
# restart at the very end of setup.
restart_service fail2ban
systemctl enable fail2ban
# Create a logrotate entry
cp -f conf/logrotate/mailinabox /etc/logrotate.d/

View File

@@ -19,7 +19,7 @@ fi
echo "Installing Nginx (web server)..."
apt_install nginx php${PHP_VER}-cli php${PHP_VER}-fpm idn2
apt_install nginx php-cli php-fpm idn2 libnginx-mod-http-geoip
rm -f /etc/nginx/sites-enabled/default
@@ -53,6 +53,12 @@ tools/editconf.py /etc/php/$PHP_VER/fpm/php.ini -c ';' \
tools/editconf.py /etc/php/$PHP_VER/fpm/php.ini -c ';' \
default_charset="UTF-8"
# Set higher timeout since fts searches with Roundcube may take longer
# than the default 60 seconds. We will also match Roundcube's timeout to the
# same value
tools/editconf.py /etc/php/$(php_version)/fpm/php.ini -c ';' \
default_socket_timeout=180
# Configure the path environment for php-fpm
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
env[PATH]=/usr/local/bin:/usr/bin:/bin \
@@ -145,6 +151,15 @@ if [ ! -f $STORAGE_ROOT/www/default/index.html ]; then
fi
chown -R $STORAGE_USER $STORAGE_ROOT/www
# Copy geoblock config file, but only if it does not exist to keep user config
if [ ! -f /etc/nginx/conf.d/10-geoblock.conf ]; then
cp -f conf/nginx/conf.d/10-geoblock.conf /etc/nginx/conf.d/
fi
# touch logfiles that might not exist
touch /var/log/nginx/geoipblock.log
chown www-data /var/log/nginx/geoipblock.log
# Start services.
restart_service nginx
restart_service php$PHP_VER-fpm

56
setup/webmail.sh Executable file → Normal file
View File

@@ -22,9 +22,9 @@ source /etc/mailinabox.conf # load global vars
echo "Installing Roundcube (webmail)..."
apt_install \
dbconfig-common \
php${PHP_VER}-cli php${PHP_VER}-sqlite3 php${PHP_VER}-intl php${PHP_VER}-common php${PHP_VER}-curl php${PHP_VER}-imap \
php${PHP_VER}-gd php${PHP_VER}-pspell php${PHP_VER}-mbstring libjs-jquery libjs-jquery-mousewheel libmagic1 \
sqlite3
php-cli php-sqlite3 php-intl php-json php-common php-curl php-imap \
php-gd php-pspell libjs-jquery libjs-jquery-mousewheel libmagic1 php-mbstring \
sqlite3
# Install Roundcube from source if it is not already present or if it is out of date.
# Combine the Roundcube version number with the commit hash of plugins to track
@@ -34,16 +34,20 @@ apt_install \
# https://github.com/mfreiholz/persistent_login/commits/master
# https://github.com/stremlau/html5_notifier/commits/master
# https://github.com/mstilkerich/rcmcarddav/releases
# https://github.com/johndoh/roundcube-contextmenu
# https://github.com/alexandregz/twofactor_gauthenticator
# The easiest way to get the package hashes is to run this script and get the hash from
# the error message.
VERSION=1.6.0
HASH=fd84b4fac74419bb73e7a3bcae1978d5589c52de
VERSION=1.6.1
HASH=0e1c771ab83ea03bde1fd0be6ab5d09e60b4f293
PERSISTENT_LOGIN_VERSION=bde7b6840c7d91de627ea14e81cf4133cbb3c07a # version 5.2
HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+
CARDDAV_VERSION=4.4.3
CARDDAV_HASH=74f8ba7aee33e78beb9de07f7f44b81f6071b644
HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+
CARDDAV_VERSION=4.4.6
CARDDAV_HASH=82c5428f7086a09c9a77576d8887d65bb24a1da4
CONTEXT_MENU_VERSION=dd13a92a9d8910cce7b2234f45a0b2158214956c # version 3.3.1
TWOFACT_COMMIT=06e21b0c03aeeb650ee4ad93538873185f776f8b # master @ 21-04-2022
UPDATE_KEY=$VERSION:$PERSISTENT_LOGIN_VERSION:$HTML5_NOTIFIER_VERSION:$CARDDAV_VERSION
UPDATE_KEY=$VERSION:$PERSISTENT_LOGIN_VERSION:$HTML5_NOTIFIER_VERSION:$CARDDAV_VERSION:$CONTEXT_MENU_VERSION:$TWOFACT_COMMIT
# paths that are often reused.
RCM_DIR=/usr/local/lib/roundcubemail
@@ -82,16 +86,22 @@ if [ $needs_update == 1 ]; then
# install roundcube html5_notifier plugin
git_clone https://github.com/kitist/html5_notifier.git $HTML5_NOTIFIER_VERSION '' ${RCM_PLUGIN_DIR}/html5_notifier
# download and verify the full release of the carddav plugin
# download and verify the full release of the carddav plugin. Can't use git_clone because repository does not include all dependencies
wget_verify \
https://github.com/mstilkerich/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-v${CARDDAV_VERSION}.tar.gz \
$CARDDAV_HASH \
/tmp/carddav.tar.gz
# unzip and cleanup
tar -C ${RCM_PLUGIN_DIR} -zxf /tmp/carddav.tar.gz
tar -C ${RCM_PLUGIN_DIR} --no-same-owner -zxf /tmp/carddav.tar.gz
rm -f /tmp/carddav.tar.gz
# install roundcube context menu plugin
git_clone https://github.com/johndoh/roundcube-contextmenu.git $CONTEXT_MENU_VERSION '' ${RCM_PLUGIN_DIR}/contextmenu
# install two factor totp authenticator
git_clone https://github.com/alexandregz/twofactor_gauthenticator.git $TWOFACT_COMMIT '' ${RCM_PLUGIN_DIR}/twofactor_gauthenticator
# record the version we've installed
echo $UPDATE_KEY > ${RCM_DIR}/version
fi
@@ -123,7 +133,7 @@ cat > $RCM_CONFIG <<EOF;
'verify_peer_name' => false,
),
);
\$config['imap_timeout'] = 15;
\$config['imap_timeout'] = 180;
\$config['smtp_host'] = 'tls://127.0.0.1';
\$config['smtp_conn_options'] = array(
'ssl' => array(
@@ -135,7 +145,7 @@ cat > $RCM_CONFIG <<EOF;
\$config['product_name'] = '$PRIMARY_HOSTNAME Webmail';
\$config['cipher_method'] = 'AES-256-CBC'; # persistent login cookie and potentially other things
\$config['des_key'] = '$SECRET_KEY'; # 37 characters -> ~256 bits for AES-256, see above
\$config['plugins'] = array('html5_notifier', 'archive', 'zipdownload', 'password', 'managesieve', 'jqueryui', 'persistent_login', 'carddav');
\$config['plugins'] = array('html5_notifier', 'archive', 'zipdownload', 'password', 'managesieve', 'jqueryui', 'persistent_login', 'carddav', 'markasjunk', 'contextmenu', 'twofactor_gauthenticator');
\$config['skin'] = 'elastic';
\$config['login_autocomplete'] = 2;
\$config['login_username_filter'] = 'email';
@@ -152,7 +162,7 @@ EOF
cat > ${RCM_PLUGIN_DIR}/carddav/config.inc.php <<EOF;
<?php
/* Do not edit. Written by Mail-in-a-Box. Regenerated on updates. */
\$prefs['_GLOBAL']['hide_preferences'] = true;
\$prefs['_GLOBAL']['hide_preferences'] = false;
\$prefs['_GLOBAL']['suppress_version_warning'] = true;
\$prefs['ownCloud'] = array(
'name' => 'ownCloud',
@@ -161,8 +171,8 @@ cat > ${RCM_PLUGIN_DIR}/carddav/config.inc.php <<EOF;
'url' => 'https://${PRIMARY_HOSTNAME}/cloud/remote.php/dav/addressbooks/users/%u/contacts/',
'active' => true,
'readonly' => false,
'refresh_time' => '02:00:00',
'fixed' => array('username','password'),
'refresh_time' => '00:30:00',
'fixed' => array('username'),
'preemptive_auth' => '1',
'hide' => false,
);
@@ -171,7 +181,7 @@ EOF
# Create writable directories.
mkdir -p /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundcube
chown -R www-data.www-data /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundcube
chown -R www-data:www-data /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundcube
# Ensure the log file monitored by fail2ban exists, or else fail2ban can't start.
sudo -u www-data touch /var/log/roundcubemail/errors.log
@@ -195,18 +205,18 @@ usermod -a -G dovecot www-data
# set permissions so that PHP can use users.sqlite
# could use dovecot instead of www-data, but not sure it matters
chown root.www-data $STORAGE_ROOT/mail
chown root:www-data $STORAGE_ROOT/mail
chmod 775 $STORAGE_ROOT/mail
chown root.www-data $STORAGE_ROOT/mail/users.sqlite
chown root:www-data $STORAGE_ROOT/mail/users.sqlite
chmod 664 $STORAGE_ROOT/mail/users.sqlite
# Fix Carddav permissions:
chown -f -R root.www-data ${RCM_PLUGIN_DIR}/carddav
# root.www-data need all permissions, others only read
chown -f -R root:www-data ${RCM_PLUGIN_DIR}/carddav
# root:www-data need all permissions, others only read
chmod -R 774 ${RCM_PLUGIN_DIR}/carddav
# Run Roundcube database migration script (database is created if it does not exist)
php$PHP_VER ${RCM_DIR}/bin/updatedb.sh --dir ${RCM_DIR}/SQL --package roundcube
${RCM_DIR}/bin/updatedb.sh --dir ${RCM_DIR}/SQL --package roundcube
chown www-data:www-data $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
chmod 664 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
@@ -221,5 +231,5 @@ sed -i.miabold 's/^[^#]\+.\+PRAGMA journal_mode = WAL.\+$/#&/' \
sqlite3 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite 'PRAGMA journal_mode=WAL;'
# Enable PHP modules.
phpenmod -v $PHP_VER imap
phpenmod -v php imap
restart_service php$PHP_VER-fpm

View File

@@ -1,107 +0,0 @@
#!/bin/bash
#
# Z-Push: The Microsoft Exchange protocol server
# ----------------------------------------------
#
# Mostly for use on iOS which doesn't support IMAP IDLE.
#
# Although Ubuntu ships Z-Push (as d-push) it has a dependency on Apache
# so we won't install it that way.
#
# Thanks to http://frontender.ch/publikationen/push-mail-server-using-nginx-and-z-push.html.
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# Prereqs.
echo "Installing Z-Push (Exchange/ActiveSync server)..."
apt_install \
php${PHP_VER}-soap php${PHP_VER}-imap libawl-php php$PHP_VER-xml
phpenmod -v $PHP_VER imap
# Copy Z-Push into place.
VERSION=2.6.2
TARGETHASH=f0e8091a8030e5b851f5ba1f9f0e1a05b8762d80
needs_update=0 #NODOC
if [ ! -f /usr/local/lib/z-push/version ]; then
needs_update=1 #NODOC
elif [[ $VERSION != $(cat /usr/local/lib/z-push/version) ]]; then
# checks if the version
needs_update=1 #NODOC
fi
if [ $needs_update == 1 ]; then
# Download
wget_verify "https://github.com/Z-Hub/Z-Push/archive/refs/tags/$VERSION.zip" $TARGETHASH /tmp/z-push.zip
# Extract into place.
rm -rf /usr/local/lib/z-push /tmp/z-push
unzip -q /tmp/z-push.zip -d /tmp/z-push
mv /tmp/z-push/*/src /usr/local/lib/z-push
rm -rf /tmp/z-push.zip /tmp/z-push
rm -f /usr/sbin/z-push-{admin,top}
echo $VERSION > /usr/local/lib/z-push/version
fi
# Configure default config.
sed -i "s^define('TIMEZONE', .*^define('TIMEZONE', '$(cat /etc/timezone)');^" /usr/local/lib/z-push/config.php
sed -i "s/define('BACKEND_PROVIDER', .*/define('BACKEND_PROVIDER', 'BackendCombined');/" /usr/local/lib/z-push/config.php
sed -i "s/define('USE_FULLEMAIL_FOR_LOGIN', .*/define('USE_FULLEMAIL_FOR_LOGIN', true);/" /usr/local/lib/z-push/config.php
sed -i "s/define('LOG_MEMORY_PROFILER', .*/define('LOG_MEMORY_PROFILER', false);/" /usr/local/lib/z-push/config.php
sed -i "s/define('BUG68532FIXED', .*/define('BUG68532FIXED', false);/" /usr/local/lib/z-push/config.php
sed -i "s/define('LOGLEVEL', .*/define('LOGLEVEL', LOGLEVEL_ERROR);/" /usr/local/lib/z-push/config.php
# Configure BACKEND
rm -f /usr/local/lib/z-push/backend/combined/config.php
cp conf/zpush/backend_combined.php /usr/local/lib/z-push/backend/combined/config.php
# Configure IMAP
rm -f /usr/local/lib/z-push/backend/imap/config.php
cp conf/zpush/backend_imap.php /usr/local/lib/z-push/backend/imap/config.php
sed -i "s%STORAGE_ROOT%$STORAGE_ROOT%" /usr/local/lib/z-push/backend/imap/config.php
# Configure CardDav
rm -f /usr/local/lib/z-push/backend/carddav/config.php
cp conf/zpush/backend_carddav.php /usr/local/lib/z-push/backend/carddav/config.php
# Configure CalDav
rm -f /usr/local/lib/z-push/backend/caldav/config.php
cp conf/zpush/backend_caldav.php /usr/local/lib/z-push/backend/caldav/config.php
# Configure Autodiscover
rm -f /usr/local/lib/z-push/autodiscover/config.php
cp conf/zpush/autodiscover_config.php /usr/local/lib/z-push/autodiscover/config.php
sed -i "s/PRIMARY_HOSTNAME/$PRIMARY_HOSTNAME/" /usr/local/lib/z-push/autodiscover/config.php
sed -i "s^define('TIMEZONE', .*^define('TIMEZONE', '$(cat /etc/timezone)');^" /usr/local/lib/z-push/autodiscover/config.php
# Some directories it will use.
mkdir -p /var/log/z-push
mkdir -p /var/lib/z-push
chmod 750 /var/log/z-push
chmod 750 /var/lib/z-push
chown www-data:www-data /var/log/z-push
chown www-data:www-data /var/lib/z-push
# Add log rotation
cat > /etc/logrotate.d/z-push <<EOF;
/var/log/z-push/*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
}
EOF
# Restart service.
restart_service php$PHP_VER-fpm
# Fix states after upgrade
hide_output php$PHP_VER /usr/local/lib/z-push/z-push-admin.php -a fixstates