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:
54
setup/additionals.sh
Normal file
54
setup/additionals.sh
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
84
setup/dovecot-fts-xapian.sh
Executable 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 \*
|
||||
|
||||
@@ -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
41
setup/geoipfilter.sh
Normal 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
104
setup/geoiptoolssetup.sh
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -195,3 +195,4 @@ chmod 770 $STORAGE_ROOT/mail/spamassassin
|
||||
restart_service spampd
|
||||
restart_service dovecot
|
||||
|
||||
systemctl enable spamassassin.service
|
||||
17
setup/ssl.sh
17
setup/ssl.sh
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
145
setup/system.sh
145
setup/system.sh
@@ -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/
|
||||
|
||||
17
setup/web.sh
17
setup/web.sh
@@ -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
56
setup/webmail.sh
Executable file → Normal 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
|
||||
|
||||
107
setup/zpush.sh
107
setup/zpush.sh
@@ -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
|
||||
Reference in New Issue
Block a user