Compare commits
1 Commits
7c09b7c73e
...
9d7a892355
Author | SHA1 | Date |
---|---|---|
Michael Meidlinger | 9d7a892355 |
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -1,31 +1,6 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Version 68 (April 1, 2024)
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Package updates:
|
|
||||||
|
|
||||||
* Roundcube updated to version 1.6.6.
|
|
||||||
* Nextcloud is updated to version 26.0.12.
|
|
||||||
|
|
||||||
Mail:
|
|
||||||
|
|
||||||
* Updated postfix's configuration to guard against SMTP smuggling to the long-term fix (https://www.postfix.org/smtp-smuggling.html).
|
|
||||||
|
|
||||||
Control Panel:
|
|
||||||
|
|
||||||
* Improved reporting of Spamhaus response codes.
|
|
||||||
* Improved detection of SSH port.
|
|
||||||
* Fixed an error if last saved status check results were corrupted.
|
|
||||||
* Other minor fixes.
|
|
||||||
|
|
||||||
Other:
|
|
||||||
|
|
||||||
* fail2ban is updated to see "HTTP/2.0" requests to munin also.
|
|
||||||
* Internal improvements to the code to make it more reliable and readable.
|
|
||||||
|
|
||||||
|
|
||||||
Version 67 (December 22, 2023)
|
Version 67 (December 22, 2023)
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ Clone this repository and checkout the tag corresponding to the most recent rele
|
||||||
|
|
||||||
$ git clone https://github.com/mail-in-a-box/mailinabox
|
$ git clone https://github.com/mail-in-a-box/mailinabox
|
||||||
$ cd mailinabox
|
$ cd mailinabox
|
||||||
$ git checkout v68
|
$ git checkout v67
|
||||||
|
|
||||||
Begin the installation.
|
Begin the installation.
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export LC_TYPE=en_US.UTF-8
|
||||||
|
|
||||||
# On Mondays, i.e. once a week, send the administrator a report of total emails
|
# On Mondays, i.e. once a week, send the administrator a report of total emails
|
||||||
# sent and received so the admin might notice server abuse.
|
# sent and received so the admin might notice server abuse.
|
||||||
if [ "$(date "+%u")" -eq 1 ]; then
|
if [ `date "+%u"` -eq 1 ]; then
|
||||||
management/mail_log.py -t week | management/email_administrator.py "Mail-in-a-Box Usage Report"
|
management/mail_log.py -t week | management/email_administrator.py "Mail-in-a-Box Usage Report"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ipaddress
|
||||||
import rtyaml
|
import rtyaml
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
|
|
||||||
from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains, get_ssh_port
|
from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains
|
||||||
from ssl_certificates import get_ssl_certificates, check_certificate
|
from ssl_certificates import get_ssl_certificates, check_certificate
|
||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
|
@ -448,11 +448,14 @@ def build_sshfp_records():
|
||||||
# if SSH has been configured to listen on a nonstandard port, we must
|
# if SSH has been configured to listen on a nonstandard port, we must
|
||||||
# specify that port to sshkeyscan.
|
# specify that port to sshkeyscan.
|
||||||
|
|
||||||
port = get_ssh_port()
|
port = 22
|
||||||
|
with open('/etc/ssh/sshd_config', encoding="utf-8") as f:
|
||||||
# If nothing returned, SSH is probably not installed.
|
for line in f:
|
||||||
if not port:
|
s = line.rstrip().split()
|
||||||
return
|
if len(s) == 2 and s[0] == 'Port':
|
||||||
|
with contextlib.suppress(ValueError):
|
||||||
|
port = int(s[1])
|
||||||
|
break
|
||||||
|
|
||||||
keys = shell("check_output", ["ssh-keyscan", "-4", "-t", "rsa,dsa,ecdsa,ed25519", "-p", str(port), "localhost"])
|
keys = shell("check_output", ["ssh-keyscan", "-4", "-t", "rsa,dsa,ecdsa,ed25519", "-p", str(port), "localhost"])
|
||||||
keys = sorted(keys.split("\n"))
|
keys = sorted(keys.split("\n"))
|
||||||
|
|
|
@ -17,7 +17,7 @@ from web_update import get_web_domains, get_domains_with_a_records
|
||||||
from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate
|
from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate
|
||||||
from mailconfig import get_mail_domains, get_mail_aliases
|
from mailconfig import get_mail_domains, get_mail_aliases
|
||||||
|
|
||||||
from utils import shell, sort_domains, load_env_vars_from_file, load_settings, get_ssh_port, get_ssh_config_value
|
from utils import shell, sort_domains, load_env_vars_from_file, load_settings
|
||||||
|
|
||||||
def get_services():
|
def get_services():
|
||||||
return [
|
return [
|
||||||
|
@ -65,6 +65,24 @@ def run_checks(rounded_values, env, output, pool, domains_to_check=None):
|
||||||
run_network_checks(env, output)
|
run_network_checks(env, output)
|
||||||
run_domain_checks(rounded_values, env, output, pool, domains_to_check=domains_to_check)
|
run_domain_checks(rounded_values, env, output, pool, domains_to_check=domains_to_check)
|
||||||
|
|
||||||
|
def get_ssh_port():
|
||||||
|
# Returns ssh port
|
||||||
|
try:
|
||||||
|
output = shell('check_output', ['sshd', '-T'])
|
||||||
|
except FileNotFoundError:
|
||||||
|
# sshd is not installed. That's ok.
|
||||||
|
return None
|
||||||
|
|
||||||
|
returnNext = False
|
||||||
|
for e in output.split():
|
||||||
|
if returnNext:
|
||||||
|
return int(e)
|
||||||
|
if e == "port":
|
||||||
|
returnNext = True
|
||||||
|
|
||||||
|
# Did not find port!
|
||||||
|
return None
|
||||||
|
|
||||||
def run_services_checks(env, output, pool):
|
def run_services_checks(env, output, pool):
|
||||||
# Check that system services are running.
|
# Check that system services are running.
|
||||||
all_running = True
|
all_running = True
|
||||||
|
@ -188,15 +206,21 @@ def is_port_allowed(ufw, port):
|
||||||
return any(re.match(str(port) +"[/ \t].*", item) for item in ufw)
|
return any(re.match(str(port) +"[/ \t].*", item) for item in ufw)
|
||||||
|
|
||||||
def check_ssh_password(env, output):
|
def check_ssh_password(env, output):
|
||||||
config_value = get_ssh_config_value("passwordauthentication")
|
# Check that SSH login with password is disabled. The openssh-server
|
||||||
if config_value:
|
# package may not be installed so check that before trying to access
|
||||||
if config_value == "no":
|
# the configuration file.
|
||||||
output.print_ok("SSH disallows password-based login.")
|
if not os.path.exists("/etc/ssh/sshd_config"):
|
||||||
else:
|
return
|
||||||
|
with open("/etc/ssh/sshd_config", encoding="utf-8") as f:
|
||||||
|
sshd = f.read()
|
||||||
|
if re.search("\nPasswordAuthentication\\s+yes", sshd) \
|
||||||
|
or not re.search("\nPasswordAuthentication\\s+no", sshd):
|
||||||
output.print_error("""The SSH server on this machine permits password-based login. A more secure
|
output.print_error("""The SSH server on this machine permits password-based login. A more secure
|
||||||
way to log in is using a public key. Add your SSH public key to $HOME/.ssh/authorized_keys, check
|
way to log in is using a public key. Add your SSH public key to $HOME/.ssh/authorized_keys, check
|
||||||
that you can log in without a password, set the option 'PasswordAuthentication no' in
|
that you can log in without a password, set the option 'PasswordAuthentication no' in
|
||||||
/etc/ssh/sshd_config, and then restart the openssh via 'sudo service ssh restart'.""")
|
/etc/ssh/sshd_config, and then restart the openssh via 'sudo service ssh restart'.""")
|
||||||
|
else:
|
||||||
|
output.print_ok("SSH disallows password-based login.")
|
||||||
|
|
||||||
def is_reboot_needed_due_to_package_installation():
|
def is_reboot_needed_due_to_package_installation():
|
||||||
return os.path.exists("/var/run/reboot-required")
|
return os.path.exists("/var/run/reboot-required")
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
<h4>Automatic configuration</h4>
|
<h4>Automatic configuration</h4>
|
||||||
|
|
||||||
<p>iOS and macOS only: Open <a style="font-weight: bold" href="https://{{hostname}}/mailinabox.mobileconfig">this configuration link</a> on your iOS device or on your Mac desktop to easily set up mail (IMAP/SMTP), Contacts, and Calendar. Your username is your whole email address.</p>
|
<p>iOS and OS X only: Open <a style="font-weight: bold" href="https://{{hostname}}/mailinabox.mobileconfig">this configuration link</a> on your iOS device or on your Mac desktop to easily set up mail (IMAP/SMTP), Contacts, and Calendar. Your username is your whole email address.</p>
|
||||||
|
|
||||||
<h4>Manual configuration</h4>
|
<h4>Manual configuration</h4>
|
||||||
|
|
||||||
|
|
|
@ -179,34 +179,6 @@ def wait_for_service(port, public, env, timeout):
|
||||||
return False
|
return False
|
||||||
time.sleep(min(timeout/4, 1))
|
time.sleep(min(timeout/4, 1))
|
||||||
|
|
||||||
def get_ssh_port():
|
|
||||||
port_value = get_ssh_config_value("port")
|
|
||||||
|
|
||||||
if port_value:
|
|
||||||
return int(port_value)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_ssh_config_value(parameter_name):
|
|
||||||
# Returns ssh configuration value for the provided parameter
|
|
||||||
try:
|
|
||||||
output = shell('check_output', ['sshd', '-T'])
|
|
||||||
except FileNotFoundError:
|
|
||||||
# sshd is not installed. That's ok.
|
|
||||||
return None
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
# error while calling shell command
|
|
||||||
return None
|
|
||||||
|
|
||||||
for line in output.split("\n"):
|
|
||||||
if " " not in line: continue # there's a blank line at the end
|
|
||||||
key, values = line.split(" ", 1)
|
|
||||||
if key == parameter_name:
|
|
||||||
return values # space-delimited if there are multiple values
|
|
||||||
|
|
||||||
# Did not find the parameter!
|
|
||||||
return None
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from web_update import get_web_domains
|
from web_update import get_web_domains
|
||||||
env = load_environment()
|
env = load_environment()
|
||||||
|
|
|
@ -23,7 +23,7 @@ if [ -z "$TAG" ]; then
|
||||||
if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then
|
if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then
|
||||||
# This machine is running Ubuntu 22.04, which is supported by
|
# This machine is running Ubuntu 22.04, which is supported by
|
||||||
# Mail-in-a-Box versions 60 and later.
|
# Mail-in-a-Box versions 60 and later.
|
||||||
TAG=v68
|
TAG=v67
|
||||||
elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then
|
elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then
|
||||||
# This machine is running Ubuntu 18.04, which is supported by
|
# This machine is running Ubuntu 18.04, which is supported by
|
||||||
# Mail-in-a-Box versions 0.40 through 5x.
|
# Mail-in-a-Box versions 0.40 through 5x.
|
||||||
|
@ -51,9 +51,9 @@ if [[ $EUID -ne 0 ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clone the Mail-in-a-Box repository if it doesn't exist.
|
# Clone the Mail-in-a-Box repository if it doesn't exist.
|
||||||
if [ ! -d "$HOME/mailinabox" ]; then
|
if [ ! -d $HOME/mailinabox ]; then
|
||||||
if [ ! -f /usr/bin/git ]; then
|
if [ ! -f /usr/bin/git ]; then
|
||||||
echo "Installing git . . ."
|
echo Installing git . . .
|
||||||
apt-get -q -q update
|
apt-get -q -q update
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get -q -q install -y git < /dev/null
|
DEBIAN_FRONTEND=noninteractive apt-get -q -q install -y git < /dev/null
|
||||||
echo
|
echo
|
||||||
|
@ -63,25 +63,25 @@ if [ ! -d "$HOME/mailinabox" ]; then
|
||||||
SOURCE=https://github.com/mail-in-a-box/mailinabox
|
SOURCE=https://github.com/mail-in-a-box/mailinabox
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Downloading Mail-in-a-Box $TAG. . ."
|
echo Downloading Mail-in-a-Box $TAG. . .
|
||||||
git clone \
|
git clone \
|
||||||
-b "$TAG" --depth 1 \
|
-b $TAG --depth 1 \
|
||||||
"$SOURCE" \
|
$SOURCE \
|
||||||
"$HOME/mailinabox" \
|
$HOME/mailinabox \
|
||||||
< /dev/null 2> /dev/null
|
< /dev/null 2> /dev/null
|
||||||
|
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Change directory to it.
|
# Change directory to it.
|
||||||
cd "$HOME/mailinabox" || exit
|
cd $HOME/mailinabox
|
||||||
|
|
||||||
# Update it.
|
# Update it.
|
||||||
if [ "$TAG" != "$(git describe --always)" ]; then
|
if [ "$TAG" != $(git describe --always) ]; then
|
||||||
echo "Updating Mail-in-a-Box to $TAG . . ."
|
echo Updating Mail-in-a-Box to $TAG . . .
|
||||||
git fetch --depth 1 --force --prune origin tag "$TAG"
|
git fetch --depth 1 --force --prune origin tag $TAG
|
||||||
if ! git checkout -q "$TAG"; then
|
if ! git checkout -q $TAG; then
|
||||||
echo "Update failed. Did you modify something in $PWD?"
|
echo "Update failed. Did you modify something in $(pwd)?"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -10,12 +10,12 @@ source setup/functions.sh # load our functions
|
||||||
source /etc/mailinabox.conf # load global vars
|
source /etc/mailinabox.conf # load global vars
|
||||||
|
|
||||||
# Install DKIM...
|
# Install DKIM...
|
||||||
echo "Installing OpenDKIM/OpenDMARC..."
|
echo Installing OpenDKIM/OpenDMARC...
|
||||||
apt_install opendkim opendkim-tools opendmarc
|
apt_install opendkim opendkim-tools opendmarc
|
||||||
|
|
||||||
# Make sure configuration directories exist.
|
# Make sure configuration directories exist.
|
||||||
mkdir -p /etc/opendkim;
|
mkdir -p /etc/opendkim;
|
||||||
mkdir -p "$STORAGE_ROOT/mail/dkim"
|
mkdir -p $STORAGE_ROOT/mail/dkim
|
||||||
|
|
||||||
# Used in InternalHosts and ExternalIgnoreList configuration directives.
|
# Used in InternalHosts and ExternalIgnoreList configuration directives.
|
||||||
# Not quite sure why.
|
# Not quite sure why.
|
||||||
|
@ -53,12 +53,12 @@ fi
|
||||||
# such as Google. But they and others use a 2048 bit key, so we'll
|
# 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.
|
# do the same. Keys beyond 2048 bits may exceed DNS record limits.
|
||||||
if [ ! -f "$STORAGE_ROOT/mail/dkim/mail.private" ]; then
|
if [ ! -f "$STORAGE_ROOT/mail/dkim/mail.private" ]; then
|
||||||
opendkim-genkey -b 2048 -r -s mail -D "$STORAGE_ROOT/mail/dkim"
|
opendkim-genkey -b 2048 -r -s mail -D $STORAGE_ROOT/mail/dkim
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure files are owned by the opendkim user and are private otherwise.
|
# Ensure files are owned by the opendkim user and are private otherwise.
|
||||||
chown -R opendkim:opendkim "$STORAGE_ROOT/mail/dkim"
|
chown -R opendkim:opendkim $STORAGE_ROOT/mail/dkim
|
||||||
chmod go-rwx "$STORAGE_ROOT/mail/dkim"
|
chmod go-rwx $STORAGE_ROOT/mail/dkim
|
||||||
|
|
||||||
tools/editconf.py /etc/opendmarc.conf -s \
|
tools/editconf.py /etc/opendmarc.conf -s \
|
||||||
"Syslog=true" \
|
"Syslog=true" \
|
||||||
|
|
|
@ -106,7 +106,7 @@ if [ ! -f "$STORAGE_ROOT/dns/dnssec/$algo.conf" ]; then
|
||||||
# (This previously used -b 2048 but it's unclear if this setting makes sense
|
# (This previously used -b 2048 but it's unclear if this setting makes sense
|
||||||
# for non-RSA keys, so it's removed. The RSA-based keys are not recommended
|
# for non-RSA keys, so it's removed. The RSA-based keys are not recommended
|
||||||
# anymore anyway.)
|
# anymore anyway.)
|
||||||
KSK=$(umask 077; cd "$STORAGE_ROOT/dns/dnssec"; ldns-keygen -r /dev/urandom -a $algo -k _domain_);
|
KSK=$(umask 077; cd $STORAGE_ROOT/dns/dnssec; ldns-keygen -r /dev/urandom -a $algo -k _domain_);
|
||||||
|
|
||||||
# Now create a Zone-Signing Key (ZSK) which is expected to be
|
# Now create a Zone-Signing Key (ZSK) which is expected to be
|
||||||
# rotated more often than a KSK, although we have no plans to
|
# rotated more often than a KSK, although we have no plans to
|
||||||
|
@ -114,7 +114,7 @@ if [ ! -f "$STORAGE_ROOT/dns/dnssec/$algo.conf" ]; then
|
||||||
# disturbing DNS availability.) Omit `-k`.
|
# disturbing DNS availability.) Omit `-k`.
|
||||||
# (This previously used -b 1024 but it's unclear if this setting makes sense
|
# (This previously used -b 1024 but it's unclear if this setting makes sense
|
||||||
# for non-RSA keys, so it's removed.)
|
# for non-RSA keys, so it's removed.)
|
||||||
ZSK=$(umask 077; cd "$STORAGE_ROOT/dns/dnssec"; ldns-keygen -r /dev/urandom -a $algo _domain_);
|
ZSK=$(umask 077; cd $STORAGE_ROOT/dns/dnssec; ldns-keygen -r /dev/urandom -a $algo _domain_);
|
||||||
|
|
||||||
# These generate two sets of files like:
|
# These generate two sets of files like:
|
||||||
#
|
#
|
||||||
|
@ -126,7 +126,7 @@ if [ ! -f "$STORAGE_ROOT/dns/dnssec/$algo.conf" ]; then
|
||||||
# options. So we'll store the names of the files we just generated.
|
# options. So we'll store the names of the files we just generated.
|
||||||
# We might have multiple keys down the road. This will identify
|
# We might have multiple keys down the road. This will identify
|
||||||
# what keys are the current keys.
|
# what keys are the current keys.
|
||||||
cat > "$STORAGE_ROOT/dns/dnssec/$algo.conf" << EOF;
|
cat > $STORAGE_ROOT/dns/dnssec/$algo.conf << EOF;
|
||||||
KSK=$KSK
|
KSK=$KSK
|
||||||
ZSK=$ZSK
|
ZSK=$ZSK
|
||||||
EOF
|
EOF
|
||||||
|
@ -142,7 +142,7 @@ cat > /etc/cron.daily/mailinabox-dnssec << EOF;
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Mail-in-a-Box
|
# Mail-in-a-Box
|
||||||
# Re-sign any DNS zones with DNSSEC because the signatures expire periodically.
|
# Re-sign any DNS zones with DNSSEC because the signatures expire periodically.
|
||||||
$PWD/tools/dns_update
|
$(pwd)/tools/dns_update
|
||||||
EOF
|
EOF
|
||||||
chmod +x /etc/cron.daily/mailinabox-dnssec
|
chmod +x /etc/cron.daily/mailinabox-dnssec
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/bin/bash
|
|
||||||
# If there aren't any mail users yet, create one.
|
# If there aren't any mail users yet, create one.
|
||||||
if [ -z "$(management/cli.py user)" ]; then
|
if [ -z "$(management/cli.py user)" ]; then
|
||||||
# The outut of "management/cli.py user" is a list of mail users. If there
|
# The outut of "management/cli.py user" is a list of mail users. If there
|
||||||
|
@ -11,7 +10,7 @@ if [ -z "$(management/cli.py user)" ]; then
|
||||||
input_box "Mail Account" \
|
input_box "Mail Account" \
|
||||||
"Let's create your first mail account.
|
"Let's create your first mail account.
|
||||||
\n\nWhat email address do you want?" \
|
\n\nWhat email address do you want?" \
|
||||||
"me@$(get_default_hostname)" \
|
me@$(get_default_hostname) \
|
||||||
EMAIL_ADDR
|
EMAIL_ADDR
|
||||||
|
|
||||||
if [ -z "$EMAIL_ADDR" ]; then
|
if [ -z "$EMAIL_ADDR" ]; then
|
||||||
|
@ -23,7 +22,7 @@ if [ -z "$(management/cli.py user)" ]; then
|
||||||
input_box "Mail Account" \
|
input_box "Mail Account" \
|
||||||
"That's not a valid email address.
|
"That's not a valid email address.
|
||||||
\n\nWhat email address do you want?" \
|
\n\nWhat email address do you want?" \
|
||||||
"$EMAIL_ADDR" \
|
$EMAIL_ADDR \
|
||||||
EMAIL_ADDR
|
EMAIL_ADDR
|
||||||
if [ -z "$EMAIL_ADDR" ]; then
|
if [ -z "$EMAIL_ADDR" ]; then
|
||||||
# user hit ESC/cancel
|
# user hit ESC/cancel
|
||||||
|
@ -48,11 +47,11 @@ if [ -z "$(management/cli.py user)" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the user's mail account. This will ask for a password if none was given above.
|
# Create the user's mail account. This will ask for a password if none was given above.
|
||||||
management/cli.py user add "$EMAIL_ADDR" "${EMAIL_PW:-}"
|
management/cli.py user add $EMAIL_ADDR ${EMAIL_PW:-}
|
||||||
|
|
||||||
# Make it an admin.
|
# Make it an admin.
|
||||||
hide_output management/cli.py user make-admin "$EMAIL_ADDR"
|
hide_output management/cli.py user make-admin $EMAIL_ADDR
|
||||||
|
|
||||||
# Create an alias to which we'll direct all automatically-created administrative aliases.
|
# Create an alias to which we'll direct all automatically-created administrative aliases.
|
||||||
management/cli.py alias add "administrator@$PRIMARY_HOSTNAME" "$EMAIL_ADDR" > /dev/null
|
management/cli.py alias add administrator@$PRIMARY_HOSTNAME $EMAIL_ADDR > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/bin/bash
|
|
||||||
# Turn on "strict mode." See http://redsymbol.net/articles/unofficial-bash-strict-mode/.
|
# Turn on "strict mode." See http://redsymbol.net/articles/unofficial-bash-strict-mode/.
|
||||||
# -e: exit if any command unexpectedly fails.
|
# -e: exit if any command unexpectedly fails.
|
||||||
# -u: exit if we have a variable typo.
|
# -u: exit if we have a variable typo.
|
||||||
|
@ -17,7 +16,7 @@ function hide_output {
|
||||||
# Execute command, redirecting stderr/stdout to the temporary file. Since we
|
# Execute command, redirecting stderr/stdout to the temporary file. Since we
|
||||||
# check the return code ourselves, disable 'set -e' temporarily.
|
# check the return code ourselves, disable 'set -e' temporarily.
|
||||||
set +e
|
set +e
|
||||||
"$@" &> "$OUTPUT"
|
"$@" &> $OUTPUT
|
||||||
E=$?
|
E=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
@ -25,15 +24,15 @@ function hide_output {
|
||||||
if [ $E != 0 ]; then
|
if [ $E != 0 ]; then
|
||||||
# Something failed.
|
# Something failed.
|
||||||
echo
|
echo
|
||||||
echo "FAILED: $*"
|
echo FAILED: "$@"
|
||||||
echo -----------------------------------------
|
echo -----------------------------------------
|
||||||
cat "$OUTPUT"
|
cat $OUTPUT
|
||||||
echo -----------------------------------------
|
echo -----------------------------------------
|
||||||
exit $E
|
exit $E
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove temporary file.
|
# Remove temporary file.
|
||||||
rm -f "$OUTPUT"
|
rm -f $OUTPUT
|
||||||
}
|
}
|
||||||
|
|
||||||
function apt_get_quiet {
|
function apt_get_quiet {
|
||||||
|
@ -63,9 +62,9 @@ function get_default_hostname {
|
||||||
# Guess the machine's hostname. It should be a fully qualified
|
# Guess the machine's hostname. It should be a fully qualified
|
||||||
# domain name suitable for DNS. None of these calls may provide
|
# domain name suitable for DNS. None of these calls may provide
|
||||||
# the right value, but it's the best guess we can make.
|
# the right value, but it's the best guess we can make.
|
||||||
set -- "$(hostname --fqdn 2>/dev/null ||
|
set -- $(hostname --fqdn 2>/dev/null ||
|
||||||
hostname --all-fqdns 2>/dev/null ||
|
hostname --all-fqdns 2>/dev/null ||
|
||||||
hostname 2>/dev/null)"
|
hostname 2>/dev/null)
|
||||||
printf '%s\n' "$1" # return this value
|
printf '%s\n' "$1" # return this value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ function get_publicip_from_web_service {
|
||||||
#
|
#
|
||||||
# Pass '4' or '6' as an argument to this function to specify
|
# Pass '4' or '6' as an argument to this function to specify
|
||||||
# what type of address to get (IPv4, IPv6).
|
# what type of address to get (IPv4, IPv6).
|
||||||
curl -"$1" --fail --silent --max-time 15 icanhazip.com 2>/dev/null || /bin/true
|
curl -$1 --fail --silent --max-time 15 icanhazip.com 2>/dev/null || /bin/true
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_default_privateip {
|
function get_default_privateip {
|
||||||
|
@ -120,19 +119,19 @@ function get_default_privateip {
|
||||||
if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi
|
if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi
|
||||||
|
|
||||||
# Get the route information.
|
# Get the route information.
|
||||||
route=$(ip -"$1" -o route get $target 2>/dev/null | grep -v unreachable)
|
route=$(ip -$1 -o route get $target 2>/dev/null | grep -v unreachable)
|
||||||
|
|
||||||
# Parse the address out of the route information.
|
# Parse the address out of the route information.
|
||||||
address=$(echo "$route" | sed "s/.* src \([^ ]*\).*/\1/")
|
address=$(echo $route | sed "s/.* src \([^ ]*\).*/\1/")
|
||||||
|
|
||||||
if [[ "$1" == "6" && $address == fe80:* ]]; then
|
if [[ "$1" == "6" && $address == fe80:* ]]; then
|
||||||
# For IPv6 link-local addresses, parse the interface out
|
# For IPv6 link-local addresses, parse the interface out
|
||||||
# of the route information and append it with a '%'.
|
# of the route information and append it with a '%'.
|
||||||
interface=$(echo "$route" | sed "s/.* dev \([^ ]*\).*/\1/")
|
interface=$(echo $route | sed "s/.* dev \([^ ]*\).*/\1/")
|
||||||
address=$address%$interface
|
address=$address%$interface
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$address"
|
echo $address
|
||||||
}
|
}
|
||||||
|
|
||||||
function ufw_allow {
|
function ufw_allow {
|
||||||
|
@ -150,7 +149,7 @@ function ufw_limit {
|
||||||
}
|
}
|
||||||
|
|
||||||
function restart_service {
|
function restart_service {
|
||||||
hide_output service "$1" restart
|
hide_output service $1 restart
|
||||||
}
|
}
|
||||||
|
|
||||||
## Dialog Functions ##
|
## Dialog Functions ##
|
||||||
|
@ -179,7 +178,7 @@ function input_menu {
|
||||||
declare -n result_code=$4_EXITCODE
|
declare -n result_code=$4_EXITCODE
|
||||||
local IFS=^$'\n'
|
local IFS=^$'\n'
|
||||||
set +e
|
set +e
|
||||||
result=$(dialog --stdout --title "$1" --menu "$2" 0 0 0 "$3")
|
result=$(dialog --stdout --title "$1" --menu "$2" 0 0 0 $3)
|
||||||
result_code=$?
|
result_code=$?
|
||||||
set -e
|
set -e
|
||||||
}
|
}
|
||||||
|
@ -191,17 +190,17 @@ function wget_verify {
|
||||||
HASH=$2
|
HASH=$2
|
||||||
DEST=$3
|
DEST=$3
|
||||||
CHECKSUM="$HASH $DEST"
|
CHECKSUM="$HASH $DEST"
|
||||||
rm -f "$DEST"
|
rm -f $DEST
|
||||||
hide_output wget -O "$DEST" "$URL"
|
hide_output wget -O $DEST $URL
|
||||||
if ! echo "$CHECKSUM" | sha1sum --check --strict > /dev/null; then
|
if ! echo "$CHECKSUM" | sha1sum --check --strict > /dev/null; then
|
||||||
echo "------------------------------------------------------------"
|
echo "------------------------------------------------------------"
|
||||||
echo "Download of $URL did not match expected checksum."
|
echo "Download of $URL did not match expected checksum."
|
||||||
echo "Found:"
|
echo "Found:"
|
||||||
sha1sum "$DEST"
|
sha1sum $DEST
|
||||||
echo
|
echo
|
||||||
echo "Expected:"
|
echo "Expected:"
|
||||||
echo "$CHECKSUM"
|
echo "$CHECKSUM"
|
||||||
rm -f "$DEST"
|
rm -f $DEST
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -217,9 +216,9 @@ function git_clone {
|
||||||
SUBDIR=$3
|
SUBDIR=$3
|
||||||
TARGETPATH=$4
|
TARGETPATH=$4
|
||||||
TMPPATH=/tmp/git-clone-$$
|
TMPPATH=/tmp/git-clone-$$
|
||||||
rm -rf $TMPPATH "$TARGETPATH"
|
rm -rf $TMPPATH $TARGETPATH
|
||||||
git clone -q "$REPO" $TMPPATH || exit 1
|
git clone -q $REPO $TMPPATH || exit 1
|
||||||
(cd $TMPPATH; git checkout -q "$TREEISH";) || exit 1
|
(cd $TMPPATH; git checkout -q $TREEISH;) || exit 1
|
||||||
mv $TMPPATH/"$SUBDIR" "$TARGETPATH"
|
mv $TMPPATH/$SUBDIR $TARGETPATH
|
||||||
rm -rf $TMPPATH
|
rm -rf $TMPPATH
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ apt_install \
|
||||||
# - https://www.dovecot.org/list/dovecot/2012-August/137569.html
|
# - https://www.dovecot.org/list/dovecot/2012-August/137569.html
|
||||||
# - https://www.dovecot.org/list/dovecot/2011-December/132455.html
|
# - https://www.dovecot.org/list/dovecot/2011-December/132455.html
|
||||||
tools/editconf.py /etc/dovecot/conf.d/10-master.conf \
|
tools/editconf.py /etc/dovecot/conf.d/10-master.conf \
|
||||||
default_process_limit="$(($(nproc) * 250))" \
|
default_process_limit=$(echo "$(nproc) * 250" | bc) \
|
||||||
default_vsz_limit="$(($(free -tm | tail -1 | awk '{print $2}') / 3))M" \
|
default_vsz_limit=$(echo "$(free -tm | tail -1 | awk '{print $2}') / 3" | bc)M \
|
||||||
log_path=/var/log/mail.log
|
log_path=/var/log/mail.log
|
||||||
|
|
||||||
# The inotify `max_user_instances` default is 128, which constrains
|
# The inotify `max_user_instances` default is 128, which constrains
|
||||||
|
@ -61,7 +61,7 @@ tools/editconf.py /etc/sysctl.conf \
|
||||||
# username part of the user's email address. We'll ensure that no bad domains or email addresses
|
# username part of the user's email address. We'll ensure that no bad domains or email addresses
|
||||||
# are created within the management daemon.
|
# are created within the management daemon.
|
||||||
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
|
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
|
||||||
mail_location="maildir:$STORAGE_ROOT/mail/mailboxes/%d/%n" \
|
mail_location=maildir:$STORAGE_ROOT/mail/mailboxes/%d/%n \
|
||||||
mail_privileged_group=mail \
|
mail_privileged_group=mail \
|
||||||
first_valid_uid=0
|
first_valid_uid=0
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ EOF
|
||||||
# Setting a `postmaster_address` is required or LMTP won't start. An alias
|
# Setting a `postmaster_address` is required or LMTP won't start. An alias
|
||||||
# will be created automatically by our management daemon.
|
# will be created automatically by our management daemon.
|
||||||
tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
|
tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
|
||||||
"postmaster_address=postmaster@$PRIMARY_HOSTNAME"
|
postmaster_address=postmaster@$PRIMARY_HOSTNAME
|
||||||
|
|
||||||
# ### Sieve
|
# ### Sieve
|
||||||
|
|
||||||
|
@ -201,14 +201,14 @@ chown -R mail:dovecot /etc/dovecot
|
||||||
chmod -R o-rwx /etc/dovecot
|
chmod -R o-rwx /etc/dovecot
|
||||||
|
|
||||||
# Ensure mailbox files have a directory that exists and are owned by the mail user.
|
# Ensure mailbox files have a directory that exists and are owned by the mail user.
|
||||||
mkdir -p "$STORAGE_ROOT/mail/mailboxes"
|
mkdir -p $STORAGE_ROOT/mail/mailboxes
|
||||||
chown -R mail:mail "$STORAGE_ROOT/mail/mailboxes"
|
chown -R mail:mail $STORAGE_ROOT/mail/mailboxes
|
||||||
|
|
||||||
# Same for the sieve scripts.
|
# Same for the sieve scripts.
|
||||||
mkdir -p "$STORAGE_ROOT/mail/sieve"
|
mkdir -p $STORAGE_ROOT/mail/sieve
|
||||||
mkdir -p "$STORAGE_ROOT/mail/sieve/global_before"
|
mkdir -p $STORAGE_ROOT/mail/sieve/global_before
|
||||||
mkdir -p "$STORAGE_ROOT/mail/sieve/global_after"
|
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.
|
# Allow the IMAP/POP ports in the firewall.
|
||||||
ufw_allow imaps
|
ufw_allow imaps
|
||||||
|
|
|
@ -55,9 +55,9 @@ apt_install postfix postfix-sqlite postfix-pcre postgrey ca-certificates
|
||||||
# * Set the SMTP banner (which must have the hostname first, then anything).
|
# * Set the SMTP banner (which must have the hostname first, then anything).
|
||||||
tools/editconf.py /etc/postfix/main.cf \
|
tools/editconf.py /etc/postfix/main.cf \
|
||||||
inet_interfaces=all \
|
inet_interfaces=all \
|
||||||
smtp_bind_address="$PRIVATE_IP" \
|
smtp_bind_address=$PRIVATE_IP \
|
||||||
smtp_bind_address6="$PRIVATE_IPV6" \
|
smtp_bind_address6=$PRIVATE_IPV6 \
|
||||||
myhostname="$PRIMARY_HOSTNAME"\
|
myhostname=$PRIMARY_HOSTNAME\
|
||||||
smtpd_banner="\$myhostname ESMTP Hi, I'm a Mail-in-a-Box (Ubuntu/Postfix; see https://mailinabox.email/)" \
|
smtpd_banner="\$myhostname ESMTP Hi, I'm a Mail-in-a-Box (Ubuntu/Postfix; see https://mailinabox.email/)" \
|
||||||
mydestination=localhost
|
mydestination=localhost
|
||||||
|
|
||||||
|
@ -70,16 +70,10 @@ tools/editconf.py /etc/postfix/main.cf \
|
||||||
bounce_queue_lifetime=1d
|
bounce_queue_lifetime=1d
|
||||||
|
|
||||||
# Guard against SMTP smuggling
|
# Guard against SMTP smuggling
|
||||||
# This "long-term" fix is recommended at https://www.postfix.org/smtp-smuggling.html.
|
# This short-term workaround is recommended at https://www.postfix.org/smtp-smuggling.html
|
||||||
# This beecame supported in a backported fix in package version 3.6.4-1ubuntu1.3. It is
|
|
||||||
# unnecessary in Postfix 3.9+ where this is the default. The "short-term" workarounds
|
|
||||||
# that we previously had are reverted to postfix defaults (though smtpd_discard_ehlo_keywords
|
|
||||||
# was never included in a released version of Mail-in-a-Box).
|
|
||||||
tools/editconf.py /etc/postfix/main.cf -e \
|
|
||||||
smtpd_data_restrictions= \
|
|
||||||
smtpd_discard_ehlo_keywords=
|
|
||||||
tools/editconf.py /etc/postfix/main.cf \
|
tools/editconf.py /etc/postfix/main.cf \
|
||||||
smtpd_forbid_bare_newline=normalize
|
smtpd_data_restrictions=reject_unauth_pipelining \
|
||||||
|
smtpd_discard_ehlo_keywords="chunking, silent-discard"
|
||||||
|
|
||||||
# ### Outgoing Mail
|
# ### Outgoing Mail
|
||||||
|
|
||||||
|
@ -138,9 +132,9 @@ sed -i "s/PUBLIC_IP/$PUBLIC_IP/" /etc/postfix/outgoing_mail_header_filters
|
||||||
tools/editconf.py /etc/postfix/main.cf \
|
tools/editconf.py /etc/postfix/main.cf \
|
||||||
smtpd_tls_security_level=may\
|
smtpd_tls_security_level=may\
|
||||||
smtpd_tls_auth_only=yes \
|
smtpd_tls_auth_only=yes \
|
||||||
smtpd_tls_cert_file="$STORAGE_ROOT/ssl/ssl_certificate.pem" \
|
smtpd_tls_cert_file=$STORAGE_ROOT/ssl/ssl_certificate.pem \
|
||||||
smtpd_tls_key_file="$STORAGE_ROOT/ssl/ssl_private_key.pem" \
|
smtpd_tls_key_file=$STORAGE_ROOT/ssl/ssl_private_key.pem \
|
||||||
smtpd_tls_dh1024_param_file="$STORAGE_ROOT/ssl/dh2048.pem" \
|
smtpd_tls_dh1024_param_file=$STORAGE_ROOT/ssl/dh2048.pem \
|
||||||
smtpd_tls_protocols="!SSLv2,!SSLv3" \
|
smtpd_tls_protocols="!SSLv2,!SSLv3" \
|
||||||
smtpd_tls_ciphers=medium \
|
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 \
|
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 \
|
||||||
|
@ -260,17 +254,17 @@ tools/editconf.py /etc/default/postgrey \
|
||||||
|
|
||||||
|
|
||||||
# If the $STORAGE_ROOT/mail/postgrey is empty, copy the postgrey database over from the old location
|
# If the $STORAGE_ROOT/mail/postgrey is empty, copy the postgrey database over from the old location
|
||||||
if [ ! -d "$STORAGE_ROOT/mail/postgrey/db" ]; then
|
if [ ! -d $STORAGE_ROOT/mail/postgrey/db ]; then
|
||||||
# Stop the service
|
# Stop the service
|
||||||
service postgrey stop
|
service postgrey stop
|
||||||
# Ensure the new paths for postgrey db exists
|
# Ensure the new paths for postgrey db exists
|
||||||
mkdir -p "$STORAGE_ROOT/mail/postgrey/db"
|
mkdir -p $STORAGE_ROOT/mail/postgrey/db
|
||||||
# Move over database files
|
# Move over database files
|
||||||
mv /var/lib/postgrey/* "$STORAGE_ROOT/mail/postgrey/db/" || true
|
mv /var/lib/postgrey/* $STORAGE_ROOT/mail/postgrey/db/ || true
|
||||||
fi
|
fi
|
||||||
# Ensure permissions are set
|
# Ensure permissions are set
|
||||||
chown -R postgrey:postgrey "$STORAGE_ROOT/mail/postgrey/"
|
chown -R postgrey:postgrey $STORAGE_ROOT/mail/postgrey/
|
||||||
chmod 700 "$STORAGE_ROOT/mail/postgrey/"{,db}
|
chmod 700 $STORAGE_ROOT/mail/postgrey/{,db}
|
||||||
|
|
||||||
# We are going to setup a newer whitelist for postgrey, the version included in the distribution is old
|
# We are going to setup a newer whitelist for postgrey, the version included in the distribution is old
|
||||||
cat > /etc/cron.daily/mailinabox-postgrey-whitelist << EOF;
|
cat > /etc/cron.daily/mailinabox-postgrey-whitelist << EOF;
|
||||||
|
|
|
@ -18,12 +18,12 @@ source /etc/mailinabox.conf # load global vars
|
||||||
db_path=$STORAGE_ROOT/mail/users.sqlite
|
db_path=$STORAGE_ROOT/mail/users.sqlite
|
||||||
|
|
||||||
# Create an empty database if it doesn't yet exist.
|
# Create an empty database if it doesn't yet exist.
|
||||||
if [ ! -f "$db_path" ]; then
|
if [ ! -f $db_path ]; then
|
||||||
echo "Creating new user database: $db_path";
|
echo Creating new user database: $db_path;
|
||||||
echo "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, extra, privileges TEXT NOT NULL DEFAULT '');" | sqlite3 "$db_path";
|
echo "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, extra, privileges TEXT NOT NULL DEFAULT '');" | sqlite3 $db_path;
|
||||||
echo "CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL, permitted_senders TEXT);" | sqlite3 "$db_path";
|
echo "CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL, permitted_senders TEXT);" | sqlite3 $db_path;
|
||||||
echo "CREATE TABLE mfa (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, type TEXT NOT NULL, secret TEXT NOT NULL, mru_token TEXT, label TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE);" | sqlite3 "$db_path";
|
echo "CREATE TABLE mfa (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, type TEXT NOT NULL, secret TEXT NOT NULL, mru_token TEXT, label TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE);" | sqlite3 $db_path;
|
||||||
echo "CREATE TABLE auto_aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL, permitted_senders TEXT);" | sqlite3 "$db_path";
|
echo "CREATE TABLE auto_aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL, permitted_senders TEXT);" | sqlite3 $db_path;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ### User Authentication
|
# ### User Authentication
|
||||||
|
|
|
@ -52,9 +52,9 @@ hide_output $venv/bin/pip install --upgrade \
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
# Create a backup directory and a random key for encrypting backups.
|
# Create a backup directory and a random key for encrypting backups.
|
||||||
mkdir -p "$STORAGE_ROOT/backup"
|
mkdir -p $STORAGE_ROOT/backup
|
||||||
if [ ! -f "$STORAGE_ROOT/backup/secret_key.txt" ]; then
|
if [ ! -f $STORAGE_ROOT/backup/secret_key.txt ]; then
|
||||||
umask 077; openssl rand -base64 2048 > "$STORAGE_ROOT/backup/secret_key.txt"
|
$(umask 077; openssl rand -base64 2048 > $STORAGE_ROOT/backup/secret_key.txt)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ tr -cd '[:xdigit:]' < /dev/urandom | head -c 32 > /var/lib/mailinabox/api.key
|
||||||
chmod 640 /var/lib/mailinabox/api.key
|
chmod 640 /var/lib/mailinabox/api.key
|
||||||
|
|
||||||
source $venv/bin/activate
|
source $venv/bin/activate
|
||||||
export PYTHONPATH=$PWD/management
|
export PYTHONPATH=$(pwd)/management
|
||||||
exec gunicorn -b localhost:10222 -w 1 --timeout 630 wsgi:app
|
exec gunicorn -b localhost:10222 -w 1 --timeout 630 wsgi:app
|
||||||
EOF
|
EOF
|
||||||
chmod +x $inst_dir/start
|
chmod +x $inst_dir/start
|
||||||
|
@ -116,7 +116,7 @@ minute=$((RANDOM % 60)) # avoid overloading mailinabox.email
|
||||||
cat > /etc/cron.d/mailinabox-nightly << EOF;
|
cat > /etc/cron.d/mailinabox-nightly << EOF;
|
||||||
# Mail-in-a-Box --- Do not edit / will be overwritten on update.
|
# Mail-in-a-Box --- Do not edit / will be overwritten on update.
|
||||||
# Run nightly tasks: backup, status checks.
|
# Run nightly tasks: backup, status checks.
|
||||||
$minute 3 * * * root (cd $PWD && management/daily_tasks.sh)
|
$minute 3 * * * root (cd $(pwd) && management/daily_tasks.sh)
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Start the management server.
|
# Start the management server.
|
||||||
|
|
|
@ -40,7 +40,7 @@ chown munin /var/log/munin/munin-cgi-graph.log
|
||||||
# ensure munin-node knows the name of this machine
|
# ensure munin-node knows the name of this machine
|
||||||
# and reduce logging level to warning
|
# and reduce logging level to warning
|
||||||
tools/editconf.py /etc/munin/munin-node.conf -s \
|
tools/editconf.py /etc/munin/munin-node.conf -s \
|
||||||
host_name="$PRIMARY_HOSTNAME" \
|
host_name=$PRIMARY_HOSTNAME \
|
||||||
log_level=1
|
log_level=1
|
||||||
|
|
||||||
# Update the activated plugins through munin's autoconfiguration.
|
# Update the activated plugins through munin's autoconfiguration.
|
||||||
|
@ -52,9 +52,9 @@ find /etc/munin/plugins/ -lname /usr/share/munin/plugins/ntp_ -print0 | xargs -0
|
||||||
|
|
||||||
# Deactivate monitoring of network interfaces that are not up. Otherwise we can get a lot of empty charts.
|
# Deactivate monitoring of network interfaces that are not up. Otherwise we can get a lot of empty charts.
|
||||||
for f in $(find /etc/munin/plugins/ \( -lname /usr/share/munin/plugins/if_ -o -lname /usr/share/munin/plugins/if_err_ -o -lname /usr/share/munin/plugins/bonding_err_ \)); do
|
for f in $(find /etc/munin/plugins/ \( -lname /usr/share/munin/plugins/if_ -o -lname /usr/share/munin/plugins/if_err_ -o -lname /usr/share/munin/plugins/bonding_err_ \)); do
|
||||||
IF=$(echo "$f" | sed s/.*_//);
|
IF=$(echo $f | sed s/.*_//);
|
||||||
if ! grep -qFx up "/sys/class/net/$IF/operstate" 2>/dev/null; then
|
if ! grep -qFx up /sys/class/net/$IF/operstate 2>/dev/null; then
|
||||||
rm "$f";
|
rm $f;
|
||||||
fi;
|
fi;
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ done
|
||||||
mkdir -p /var/lib/munin-node/plugin-state/
|
mkdir -p /var/lib/munin-node/plugin-state/
|
||||||
|
|
||||||
# Create a systemd service for munin.
|
# Create a systemd service for munin.
|
||||||
ln -sf "$PWD/management/munin_start.sh" /usr/local/lib/mailinabox/munin_start.sh
|
ln -sf $(pwd)/management/munin_start.sh /usr/local/lib/mailinabox/munin_start.sh
|
||||||
chmod 0744 /usr/local/lib/mailinabox/munin_start.sh
|
chmod 0744 /usr/local/lib/mailinabox/munin_start.sh
|
||||||
cp --remove-destination conf/munin.service /lib/systemd/system/munin.service # target was previously a symlink so remove first
|
cp --remove-destination conf/munin.service /lib/systemd/system/munin.service # target was previously a symlink so remove first
|
||||||
hide_output systemctl link -f /lib/systemd/system/munin.service
|
hide_output systemctl link -f /lib/systemd/system/munin.service
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/bin/bash
|
|
||||||
# Install the 'host', 'sed', and and 'nc' tools. This script is run before
|
# Install the 'host', 'sed', and and 'nc' tools. This script is run before
|
||||||
# the rest of the system setup so we may not yet have things installed.
|
# the rest of the system setup so we may not yet have things installed.
|
||||||
apt_get_quiet install bind9-host sed netcat-openbsd
|
apt_get_quiet install bind9-host sed netcat-openbsd
|
||||||
|
@ -7,7 +6,7 @@ apt_get_quiet install bind9-host sed netcat-openbsd
|
||||||
# The user might have chosen a name that was previously in use by a spammer
|
# The user might have chosen a name that was previously in use by a spammer
|
||||||
# and will not be able to reliably send mail. Do this after any automatic
|
# and will not be able to reliably send mail. Do this after any automatic
|
||||||
# choices made above.
|
# choices made above.
|
||||||
if host "$PRIMARY_HOSTNAME.dbl.spamhaus.org" > /dev/null; then
|
if host $PRIMARY_HOSTNAME.dbl.spamhaus.org > /dev/null; then
|
||||||
echo
|
echo
|
||||||
echo "The hostname you chose '$PRIMARY_HOSTNAME' is listed in the"
|
echo "The hostname you chose '$PRIMARY_HOSTNAME' is listed in the"
|
||||||
echo "Spamhaus Domain Block List. See http://www.spamhaus.org/dbl/"
|
echo "Spamhaus Domain Block List. See http://www.spamhaus.org/dbl/"
|
||||||
|
@ -23,8 +22,8 @@ fi
|
||||||
# The user might have ended up on an IP address that was previously in use
|
# The user might have ended up on an IP address that was previously in use
|
||||||
# by a spammer, or the user may be deploying on a residential network. We
|
# by a spammer, or the user may be deploying on a residential network. We
|
||||||
# will not be able to reliably send mail in these cases.
|
# will not be able to reliably send mail in these cases.
|
||||||
REVERSED_IPV4=$(echo "$PUBLIC_IP" | sed "s/\([0-9]*\).\([0-9]*\).\([0-9]*\).\([0-9]*\)/\4.\3.\2.\1/")
|
REVERSED_IPV4=$(echo $PUBLIC_IP | sed "s/\([0-9]*\).\([0-9]*\).\([0-9]*\).\([0-9]*\)/\4.\3.\2.\1/")
|
||||||
if host "$REVERSED_IPV4.zen.spamhaus.org" > /dev/null; then
|
if host $REVERSED_IPV4.zen.spamhaus.org > /dev/null; then
|
||||||
echo
|
echo
|
||||||
echo "The IP address $PUBLIC_IP is listed in the Spamhaus Block List."
|
echo "The IP address $PUBLIC_IP is listed in the Spamhaus Block List."
|
||||||
echo "See http://www.spamhaus.org/query/ip/$PUBLIC_IP."
|
echo "See http://www.spamhaus.org/query/ip/$PUBLIC_IP."
|
||||||
|
|
|
@ -65,13 +65,13 @@ user_external_hash=a494073dcdecbbbc79a9c77f72524ac9994d2eec
|
||||||
# Clear prior packages and install dependencies from apt.
|
# Clear prior packages and install dependencies from apt.
|
||||||
apt-get purge -qq -y owncloud* # we used to use the package manager
|
apt-get purge -qq -y owncloud* # we used to use the package manager
|
||||||
|
|
||||||
apt_install curl php"${PHP_VER}" php"${PHP_VER}"-fpm \
|
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}-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}-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
|
php${PHP_VER}-intl php${PHP_VER}-imagick php${PHP_VER}-gmp php${PHP_VER}-bcmath
|
||||||
|
|
||||||
# Enable APC before Nextcloud tools are run.
|
# Enable APC before Nextcloud tools are run.
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/mods-available/apcu.ini -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/mods-available/apcu.ini -c ';' \
|
||||||
apc.enabled=1 \
|
apc.enabled=1 \
|
||||||
apc.enable_cli=1
|
apc.enable_cli=1
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ InstallNextcloud() {
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Download and verify
|
# Download and verify
|
||||||
wget_verify "https://download.nextcloud.com/server/releases/nextcloud-$version.zip" "$hash" /tmp/nextcloud.zip
|
wget_verify https://download.nextcloud.com/server/releases/nextcloud-$version.zip $hash /tmp/nextcloud.zip
|
||||||
|
|
||||||
# Remove the current owncloud/Nextcloud
|
# Remove the current owncloud/Nextcloud
|
||||||
rm -rf /usr/local/lib/owncloud
|
rm -rf /usr/local/lib/owncloud
|
||||||
|
@ -105,18 +105,18 @@ InstallNextcloud() {
|
||||||
# their github repositories.
|
# their github repositories.
|
||||||
mkdir -p /usr/local/lib/owncloud/apps
|
mkdir -p /usr/local/lib/owncloud/apps
|
||||||
|
|
||||||
wget_verify "https://github.com/nextcloud-releases/contacts/archive/refs/tags/v$version_contacts.tar.gz" "$hash_contacts" /tmp/contacts.tgz
|
wget_verify https://github.com/nextcloud-releases/contacts/archive/refs/tags/v$version_contacts.tar.gz $hash_contacts /tmp/contacts.tgz
|
||||||
tar xf /tmp/contacts.tgz -C /usr/local/lib/owncloud/apps/
|
tar xf /tmp/contacts.tgz -C /usr/local/lib/owncloud/apps/
|
||||||
rm /tmp/contacts.tgz
|
rm /tmp/contacts.tgz
|
||||||
|
|
||||||
wget_verify "https://github.com/nextcloud-releases/calendar/archive/refs/tags/v$version_calendar.tar.gz" "$hash_calendar" /tmp/calendar.tgz
|
wget_verify https://github.com/nextcloud-releases/calendar/archive/refs/tags/v$version_calendar.tar.gz $hash_calendar /tmp/calendar.tgz
|
||||||
tar xf /tmp/calendar.tgz -C /usr/local/lib/owncloud/apps/
|
tar xf /tmp/calendar.tgz -C /usr/local/lib/owncloud/apps/
|
||||||
rm /tmp/calendar.tgz
|
rm /tmp/calendar.tgz
|
||||||
|
|
||||||
# Starting with Nextcloud 15, the app user_external is no longer included in Nextcloud core,
|
# Starting with Nextcloud 15, the app user_external is no longer included in Nextcloud core,
|
||||||
# we will install from their github repository.
|
# we will install from their github repository.
|
||||||
if [ -n "$version_user_external" ]; then
|
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-releases/user_external/releases/download/v$version_user_external/user_external-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/
|
tar -xf /tmp/user_external.tgz -C /usr/local/lib/owncloud/apps/
|
||||||
rm /tmp/user_external.tgz
|
rm /tmp/user_external.tgz
|
||||||
fi
|
fi
|
||||||
|
@ -126,35 +126,33 @@ InstallNextcloud() {
|
||||||
|
|
||||||
# Create a symlink to the config.php in STORAGE_ROOT (for upgrades we're restoring the symlink we previously
|
# Create a symlink to the config.php in STORAGE_ROOT (for upgrades we're restoring the symlink we previously
|
||||||
# put in, and in new installs we're creating a symlink and will create the actual config later).
|
# put in, and in new installs we're creating a symlink and will create the actual config later).
|
||||||
ln -sf "$STORAGE_ROOT/owncloud/config.php" /usr/local/lib/owncloud/config/config.php
|
ln -sf $STORAGE_ROOT/owncloud/config.php /usr/local/lib/owncloud/config/config.php
|
||||||
|
|
||||||
# Make sure permissions are correct or the upgrade step won't run.
|
# Make sure permissions are correct or the upgrade step won't run.
|
||||||
# $STORAGE_ROOT/owncloud may not yet exist, so use -f to suppress
|
# $STORAGE_ROOT/owncloud may not yet exist, so use -f to suppress
|
||||||
# that error.
|
# 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.
|
# 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).
|
# Then check for success (0=ok and 3=no upgrade needed, both are success).
|
||||||
if [ -e "$STORAGE_ROOT/owncloud/owncloud.db" ]; then
|
if [ -e $STORAGE_ROOT/owncloud/owncloud.db ]; then
|
||||||
# ownCloud 8.1.1 broke upgrades. It may fail on the first attempt, but
|
# ownCloud 8.1.1 broke upgrades. It may fail on the first attempt, but
|
||||||
# that can be OK.
|
# that can be OK.
|
||||||
sudo -u www-data php"$PHP_VER" /usr/local/lib/owncloud/occ upgrade
|
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ upgrade
|
||||||
E=$?
|
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then
|
||||||
if [ $E -ne 0 ] && [ $E -ne 3 ]; then
|
|
||||||
echo "Trying ownCloud upgrade again to work around ownCloud upgrade bug..."
|
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$PHP_VER /usr/local/lib/owncloud/occ upgrade
|
||||||
E=$?
|
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then exit 1; fi
|
||||||
if [ $E -ne 0 ] && [ $E -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"$PHP_VER" /usr/local/lib/owncloud/occ maintenance:mode --off
|
|
||||||
echo "...which seemed to work."
|
echo "...which seemed to work."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add missing indices. NextCloud didn't include this in the normal upgrade because it might take some time.
|
# 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$PHP_VER /usr/local/lib/owncloud/occ db:add-missing-indices
|
||||||
sudo -u www-data php"$PHP_VER" /usr/local/lib/owncloud/occ db:add-missing-primary-keys
|
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ db:add-missing-primary-keys
|
||||||
|
|
||||||
# Run conversion to BigInt identifiers, this process may take some time on large tables.
|
# 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$PHP_VER /usr/local/lib/owncloud/occ db:convert-filecache-bigint --no-interaction
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +164,7 @@ InstallNextcloud() {
|
||||||
|
|
||||||
# If config.php exists, get version number, otherwise CURRENT_NEXTCLOUD_VER is empty.
|
# If config.php exists, get version number, otherwise CURRENT_NEXTCLOUD_VER is empty.
|
||||||
if [ -f "$STORAGE_ROOT/owncloud/config.php" ]; then
|
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$PHP_VER -r "include(\"$STORAGE_ROOT/owncloud/config.php\"); echo(\$CONFIG['version']);")
|
||||||
else
|
else
|
||||||
CURRENT_NEXTCLOUD_VER=""
|
CURRENT_NEXTCLOUD_VER=""
|
||||||
fi
|
fi
|
||||||
|
@ -176,7 +174,7 @@ fi
|
||||||
if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextcloud_ver ]]; then
|
if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextcloud_ver ]]; then
|
||||||
|
|
||||||
# Stop php-fpm if running. If they are not running (which happens on a previously failed install), dont bail.
|
# Stop php-fpm if running. If they are not running (which happens on a previously failed install), dont bail.
|
||||||
service php"$PHP_VER"-fpm stop &> /dev/null || /bin/true
|
service php$PHP_VER-fpm stop &> /dev/null || /bin/true
|
||||||
|
|
||||||
# Backup the existing ownCloud/Nextcloud.
|
# Backup the existing ownCloud/Nextcloud.
|
||||||
# Create a backup directory to store the current installation and database to
|
# Create a backup directory to store the current installation and database to
|
||||||
|
@ -186,21 +184,21 @@ if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextc
|
||||||
echo "Upgrading Nextcloud --- backing up existing installation, configuration, and database to directory to $BACKUP_DIRECTORY..."
|
echo "Upgrading Nextcloud --- backing up existing installation, configuration, and database to directory to $BACKUP_DIRECTORY..."
|
||||||
cp -r /usr/local/lib/owncloud "$BACKUP_DIRECTORY/owncloud-install"
|
cp -r /usr/local/lib/owncloud "$BACKUP_DIRECTORY/owncloud-install"
|
||||||
fi
|
fi
|
||||||
if [ -e "$STORAGE_ROOT/owncloud/owncloud.db" ]; then
|
if [ -e $STORAGE_ROOT/owncloud/owncloud.db ]; then
|
||||||
cp "$STORAGE_ROOT/owncloud/owncloud.db" "$BACKUP_DIRECTORY"
|
cp $STORAGE_ROOT/owncloud/owncloud.db $BACKUP_DIRECTORY
|
||||||
fi
|
fi
|
||||||
if [ -e "$STORAGE_ROOT/owncloud/config.php" ]; then
|
if [ -e $STORAGE_ROOT/owncloud/config.php ]; then
|
||||||
cp "$STORAGE_ROOT/owncloud/config.php" "$BACKUP_DIRECTORY"
|
cp $STORAGE_ROOT/owncloud/config.php $BACKUP_DIRECTORY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If ownCloud or Nextcloud was previously installed....
|
# If ownCloud or Nextcloud was previously installed....
|
||||||
if [ -n "${CURRENT_NEXTCLOUD_VER}" ]; then
|
if [ ! -z ${CURRENT_NEXTCLOUD_VER} ]; then
|
||||||
# Database migrations from ownCloud are no longer possible because ownCloud cannot be run under
|
# Database migrations from ownCloud are no longer possible because ownCloud cannot be run under
|
||||||
# PHP 7.
|
# PHP 7.
|
||||||
|
|
||||||
if [ -e "$STORAGE_ROOT/owncloud/config.php" ]; then
|
if [ -e $STORAGE_ROOT/owncloud/config.php ]; then
|
||||||
# Remove the read-onlyness of the config, which is needed for migrations, especially for v24
|
# Remove the read-onlyness of the config, which is needed for migrations, especially for v24
|
||||||
sed -i -e '/config_is_read_only/d' "$STORAGE_ROOT/owncloud/config.php"
|
sed -i -e '/config_is_read_only/d' $STORAGE_ROOT/owncloud/config.php
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^[89] ]]; then
|
if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^[89] ]]; then
|
||||||
|
@ -248,13 +246,13 @@ fi
|
||||||
|
|
||||||
# Setup Nextcloud if the Nextcloud database does not yet exist. Running setup when
|
# Setup Nextcloud if the Nextcloud database does not yet exist. Running setup when
|
||||||
# the database does exist wipes the database and user data.
|
# the database does exist wipes the database and user data.
|
||||||
if [ ! -f "$STORAGE_ROOT/owncloud/owncloud.db" ]; then
|
if [ ! -f $STORAGE_ROOT/owncloud/owncloud.db ]; then
|
||||||
# Create user data directory
|
# Create user data directory
|
||||||
mkdir -p "$STORAGE_ROOT/owncloud"
|
mkdir -p $STORAGE_ROOT/owncloud
|
||||||
|
|
||||||
# Create an initial configuration file.
|
# Create an initial configuration file.
|
||||||
instanceid=oc$(echo "$PRIMARY_HOSTNAME" | sha1sum | fold -w 10 | head -n 1)
|
instanceid=oc$(echo $PRIMARY_HOSTNAME | sha1sum | fold -w 10 | head -n 1)
|
||||||
cat > "$STORAGE_ROOT/owncloud/config.php" <<EOF;
|
cat > $STORAGE_ROOT/owncloud/config.php <<EOF;
|
||||||
<?php
|
<?php
|
||||||
\$CONFIG = array (
|
\$CONFIG = array (
|
||||||
'datadirectory' => '$STORAGE_ROOT/owncloud',
|
'datadirectory' => '$STORAGE_ROOT/owncloud',
|
||||||
|
@ -307,12 +305,12 @@ EOF
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Set permissions
|
# 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.
|
# 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
|
# It also wipes it if it exists. And it updates config.php with database
|
||||||
# settings and deletes the autoconfig.php file.
|
# settings and deletes the autoconfig.php file.
|
||||||
(cd /usr/local/lib/owncloud || exit; sudo -u www-data php"$PHP_VER" /usr/local/lib/owncloud/index.php;)
|
(cd /usr/local/lib/owncloud; sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/index.php;)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update config.php.
|
# Update config.php.
|
||||||
|
@ -328,7 +326,7 @@ fi
|
||||||
# Use PHP to read the settings file, modify it, and write out the new settings array.
|
# Use PHP to read the settings file, modify it, and write out the new settings array.
|
||||||
TIMEZONE=$(cat /etc/timezone)
|
TIMEZONE=$(cat /etc/timezone)
|
||||||
CONFIG_TEMP=$(/bin/mktemp)
|
CONFIG_TEMP=$(/bin/mktemp)
|
||||||
php"$PHP_VER" <<EOF > "$CONFIG_TEMP" && mv "$CONFIG_TEMP" "$STORAGE_ROOT/owncloud/config.php";
|
php$PHP_VER <<EOF > $CONFIG_TEMP && mv $CONFIG_TEMP $STORAGE_ROOT/owncloud/config.php;
|
||||||
<?php
|
<?php
|
||||||
include("$STORAGE_ROOT/owncloud/config.php");
|
include("$STORAGE_ROOT/owncloud/config.php");
|
||||||
|
|
||||||
|
@ -359,32 +357,31 @@ var_export(\$CONFIG);
|
||||||
echo ";";
|
echo ";";
|
||||||
?>
|
?>
|
||||||
EOF
|
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.
|
# Enable/disable apps. Note that this must be done after the Nextcloud setup.
|
||||||
# The firstrunwizard gave Josh all sorts of problems, so disabling that.
|
# The firstrunwizard gave Josh all sorts of problems, so disabling that.
|
||||||
# user_external is what allows Nextcloud to use IMAP for login. The contacts
|
# user_external is what allows Nextcloud to use IMAP for login. The contacts
|
||||||
# and calendar apps are the extensions we really care about here.
|
# 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: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 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 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$PHP_VER /usr/local/lib/owncloud/console.php app:enable calendar
|
||||||
|
|
||||||
# When upgrading, run the upgrade script again now that apps are enabled. It seems like
|
# 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?
|
# 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).
|
# 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$PHP_VER /usr/local/lib/owncloud/occ upgrade
|
||||||
E=$?
|
if [ \( $? -ne 0 \) -a \( $? -ne 3 \) ]; then exit 1; fi
|
||||||
if [ $E -ne 0 ] && [ $E -ne 3 ]; then exit 1; fi
|
|
||||||
|
|
||||||
# Disable default apps that we don't support
|
# Disable default apps that we don't support
|
||||||
sudo -u www-data \
|
sudo -u www-data \
|
||||||
php"$PHP_VER" /usr/local/lib/owncloud/occ app:disable photos dashboard activity \
|
php$PHP_VER /usr/local/lib/owncloud/occ app:disable photos dashboard activity \
|
||||||
| (grep -v "No such app enabled" || /bin/true)
|
| (grep -v "No such app enabled" || /bin/true)
|
||||||
|
|
||||||
# Set PHP FPM values to support large file uploads
|
# Set PHP FPM values to support large file uploads
|
||||||
# (semicolon is the comment character in this file, hashes produce deprecation warnings)
|
# (semicolon is the comment character in this file, hashes produce deprecation warnings)
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/php.ini -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/php.ini -c ';' \
|
||||||
upload_max_filesize=16G \
|
upload_max_filesize=16G \
|
||||||
post_max_size=16G \
|
post_max_size=16G \
|
||||||
output_buffering=16384 \
|
output_buffering=16384 \
|
||||||
|
@ -393,7 +390,7 @@ tools/editconf.py /etc/php/"$PHP_VER"/fpm/php.ini -c ';' \
|
||||||
short_open_tag=On
|
short_open_tag=On
|
||||||
|
|
||||||
# Set Nextcloud recommended opcache settings
|
# Set Nextcloud recommended opcache settings
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/cli/conf.d/10-opcache.ini -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/cli/conf.d/10-opcache.ini -c ';' \
|
||||||
opcache.enable=1 \
|
opcache.enable=1 \
|
||||||
opcache.enable_cli=1 \
|
opcache.enable_cli=1 \
|
||||||
opcache.interned_strings_buffer=8 \
|
opcache.interned_strings_buffer=8 \
|
||||||
|
@ -407,7 +404,7 @@ tools/editconf.py /etc/php/"$PHP_VER"/cli/conf.d/10-opcache.ini -c ';' \
|
||||||
# This version was probably in use in Mail-in-a-Box v0.41 (February 26, 2019) and earlier.
|
# This version was probably in use in Mail-in-a-Box v0.41 (February 26, 2019) and earlier.
|
||||||
# We moved to v0.6.3 in 193763f8. Ignore errors - maybe there are duplicated users with the
|
# We moved to v0.6.3 in 193763f8. Ignore errors - maybe there are duplicated users with the
|
||||||
# correct backend already.
|
# correct backend already.
|
||||||
sqlite3 "$STORAGE_ROOT/owncloud/owncloud.db" "UPDATE oc_users_external SET backend='127.0.0.1';" || /bin/true
|
sqlite3 $STORAGE_ROOT/owncloud/owncloud.db "UPDATE oc_users_external SET backend='127.0.0.1';" || /bin/true
|
||||||
|
|
||||||
# Set up a general cron job for Nextcloud.
|
# Set up a general cron job for Nextcloud.
|
||||||
# Also add another job for Calendar updates, per advice in the Nextcloud docs
|
# Also add another job for Calendar updates, per advice in the Nextcloud docs
|
||||||
|
@ -422,11 +419,11 @@ chmod +x /etc/cron.d/mailinabox-nextcloud
|
||||||
|
|
||||||
# We also need to change the sending mode from background-job to occ.
|
# We also need to change the sending mode from background-job to occ.
|
||||||
# Or else the reminders will just be sent as soon as possible when the background jobs run.
|
# Or else the reminders will just be sent as soon as possible when the background jobs run.
|
||||||
hide_output sudo -u www-data php"$PHP_VER" -f /usr/local/lib/owncloud/occ config:app:set dav sendEventRemindersMode --value occ
|
hide_output sudo -u www-data php$PHP_VER -f /usr/local/lib/owncloud/occ config:app:set dav sendEventRemindersMode --value occ
|
||||||
|
|
||||||
# Now set the config to read-only.
|
# Now set the config to read-only.
|
||||||
# Do this only at the very bottom when no further occ commands are needed.
|
# Do this only at the very bottom when no further occ commands are needed.
|
||||||
sed -i'' "s/'config_is_read_only'\s*=>\s*false/'config_is_read_only' => true/" "$STORAGE_ROOT/owncloud/config.php"
|
sed -i'' "s/'config_is_read_only'\s*=>\s*false/'config_is_read_only' => true/" $STORAGE_ROOT/owncloud/config.php
|
||||||
|
|
||||||
# Rotate the nextcloud.log file
|
# Rotate the nextcloud.log file
|
||||||
cat > /etc/logrotate.d/nextcloud <<EOF
|
cat > /etc/logrotate.d/nextcloud <<EOF
|
||||||
|
@ -451,4 +448,4 @@ EOF
|
||||||
# ```
|
# ```
|
||||||
|
|
||||||
# Enable PHP modules and restart PHP.
|
# Enable PHP modules and restart PHP.
|
||||||
restart_service php"$PHP_VER"-fpm
|
restart_service php$PHP_VER-fpm
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/bin/bash
|
|
||||||
if [ -z "${NONINTERACTIVE:-}" ]; then
|
if [ -z "${NONINTERACTIVE:-}" ]; then
|
||||||
# Install 'dialog' so we can ask the user questions. The original motivation for
|
# Install 'dialog' so we can ask the user questions. The original motivation for
|
||||||
# this was being able to ask the user for input even if stdin has been redirected,
|
# this was being able to ask the user for input even if stdin has been redirected,
|
||||||
|
@ -8,7 +7,7 @@ if [ -z "${NONINTERACTIVE:-}" ]; then
|
||||||
#
|
#
|
||||||
# Also install dependencies needed to validate the email address.
|
# Also install dependencies needed to validate the email address.
|
||||||
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
|
if [ ! -f /usr/bin/dialog ] || [ ! -f /usr/bin/python3 ] || [ ! -f /usr/bin/pip3 ]; then
|
||||||
echo "Installing packages needed for setup..."
|
echo Installing packages needed for setup...
|
||||||
apt-get -q -q update
|
apt-get -q -q update
|
||||||
apt_get_quiet install dialog python3 python3-pip || exit 1
|
apt_get_quiet install dialog python3 python3-pip || exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -32,7 +31,7 @@ if [ -z "${PRIMARY_HOSTNAME:-}" ]; then
|
||||||
# domain the user possibly wants to use is example.com then.
|
# domain the user possibly wants to use is example.com then.
|
||||||
# We strip the string "box." from the hostname to get the mail
|
# We strip the string "box." from the hostname to get the mail
|
||||||
# domain. If the hostname differs, nothing happens here.
|
# domain. If the hostname differs, nothing happens here.
|
||||||
DEFAULT_DOMAIN_GUESS=$(get_default_hostname | sed -e 's/^box\.//')
|
DEFAULT_DOMAIN_GUESS=$(echo $(get_default_hostname) | sed -e 's/^box\.//')
|
||||||
|
|
||||||
# This is the first run. Ask the user for his email address so we can
|
# This is the first run. Ask the user for his email address so we can
|
||||||
# provide the best default for the box's hostname.
|
# provide the best default for the box's hostname.
|
||||||
|
@ -56,7 +55,7 @@ you really want.
|
||||||
do
|
do
|
||||||
input_box "Your Email Address" \
|
input_box "Your Email Address" \
|
||||||
"That's not a valid email address.\n\nWhat email address are you setting this box up to manage?" \
|
"That's not a valid email address.\n\nWhat email address are you setting this box up to manage?" \
|
||||||
"$EMAIL_ADDR" \
|
$EMAIL_ADDR \
|
||||||
EMAIL_ADDR
|
EMAIL_ADDR
|
||||||
if [ -z "$EMAIL_ADDR" ]; then
|
if [ -z "$EMAIL_ADDR" ]; then
|
||||||
# user hit ESC/cancel
|
# user hit ESC/cancel
|
||||||
|
@ -66,7 +65,7 @@ you really want.
|
||||||
|
|
||||||
# Take the part after the @-sign as the user's domain name, and add
|
# Take the part after the @-sign as the user's domain name, and add
|
||||||
# 'box.' to the beginning to create a default hostname for this machine.
|
# 'box.' to the beginning to create a default hostname for this machine.
|
||||||
DEFAULT_PRIMARY_HOSTNAME=box.$(echo "$EMAIL_ADDR" | sed 's/.*@//')
|
DEFAULT_PRIMARY_HOSTNAME=box.$(echo $EMAIL_ADDR | sed 's/.*@//')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
input_box "Hostname" \
|
input_box "Hostname" \
|
||||||
|
@ -75,7 +74,7 @@ you really want.
|
||||||
address, so we're suggesting $DEFAULT_PRIMARY_HOSTNAME.
|
address, so we're suggesting $DEFAULT_PRIMARY_HOSTNAME.
|
||||||
\n\nYou can change it, but we recommend you don't.
|
\n\nYou can change it, but we recommend you don't.
|
||||||
\n\nHostname:" \
|
\n\nHostname:" \
|
||||||
"$DEFAULT_PRIMARY_HOSTNAME" \
|
$DEFAULT_PRIMARY_HOSTNAME \
|
||||||
PRIMARY_HOSTNAME
|
PRIMARY_HOSTNAME
|
||||||
|
|
||||||
if [ -z "$PRIMARY_HOSTNAME" ]; then
|
if [ -z "$PRIMARY_HOSTNAME" ]; then
|
||||||
|
@ -93,7 +92,7 @@ if [ -z "${PUBLIC_IP:-}" ]; then
|
||||||
|
|
||||||
# On the first run, if we got an answer from the Internet then don't
|
# On the first run, if we got an answer from the Internet then don't
|
||||||
# ask the user.
|
# ask the user.
|
||||||
if [[ -z "${DEFAULT_PUBLIC_IP:-}" && -n "$GUESSED_IP" ]]; then
|
if [[ -z "${DEFAULT_PUBLIC_IP:-}" && ! -z "$GUESSED_IP" ]]; then
|
||||||
PUBLIC_IP=$GUESSED_IP
|
PUBLIC_IP=$GUESSED_IP
|
||||||
|
|
||||||
# Otherwise on the first run at least provide a default.
|
# Otherwise on the first run at least provide a default.
|
||||||
|
@ -110,7 +109,7 @@ if [ -z "${PUBLIC_IP:-}" ]; then
|
||||||
input_box "Public IP Address" \
|
input_box "Public IP Address" \
|
||||||
"Enter the public IP address of this machine, as given to you by your ISP.
|
"Enter the public IP address of this machine, as given to you by your ISP.
|
||||||
\n\nPublic IP address:" \
|
\n\nPublic IP address:" \
|
||||||
"${DEFAULT_PUBLIC_IP:-}" \
|
${DEFAULT_PUBLIC_IP:-} \
|
||||||
PUBLIC_IP
|
PUBLIC_IP
|
||||||
|
|
||||||
if [ -z "$PUBLIC_IP" ]; then
|
if [ -z "$PUBLIC_IP" ]; then
|
||||||
|
@ -126,7 +125,7 @@ if [ -z "${PUBLIC_IPV6:-}" ]; then
|
||||||
# Ask the Internet.
|
# Ask the Internet.
|
||||||
GUESSED_IP=$(get_publicip_from_web_service 6)
|
GUESSED_IP=$(get_publicip_from_web_service 6)
|
||||||
MATCHED=0
|
MATCHED=0
|
||||||
if [[ -z "${DEFAULT_PUBLIC_IPV6:-}" && -n "$GUESSED_IP" ]]; then
|
if [[ -z "${DEFAULT_PUBLIC_IPV6:-}" && ! -z "$GUESSED_IP" ]]; then
|
||||||
PUBLIC_IPV6=$GUESSED_IP
|
PUBLIC_IPV6=$GUESSED_IP
|
||||||
elif [[ "${DEFAULT_PUBLIC_IPV6:-}" == "$GUESSED_IP" ]]; then
|
elif [[ "${DEFAULT_PUBLIC_IPV6:-}" == "$GUESSED_IP" ]]; then
|
||||||
# No IPv6 entered and machine seems to have none, or what
|
# No IPv6 entered and machine seems to have none, or what
|
||||||
|
@ -142,10 +141,10 @@ if [ -z "${PUBLIC_IPV6:-}" ]; then
|
||||||
"Enter the public IPv6 address of this machine, as given to you by your ISP.
|
"Enter the public IPv6 address of this machine, as given to you by your ISP.
|
||||||
\n\nLeave blank if the machine does not have an IPv6 address.
|
\n\nLeave blank if the machine does not have an IPv6 address.
|
||||||
\n\nPublic IPv6 address:" \
|
\n\nPublic IPv6 address:" \
|
||||||
"${DEFAULT_PUBLIC_IPV6:-}" \
|
${DEFAULT_PUBLIC_IPV6:-} \
|
||||||
PUBLIC_IPV6
|
PUBLIC_IPV6
|
||||||
|
|
||||||
if [ ! -n "$PUBLIC_IPV6_EXITCODE" ]; then
|
if [ ! $PUBLIC_IPV6_EXITCODE ]; then
|
||||||
# user hit ESC/cancel
|
# user hit ESC/cancel
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
@ -198,7 +197,7 @@ fi
|
||||||
echo
|
echo
|
||||||
echo "Primary Hostname: $PRIMARY_HOSTNAME"
|
echo "Primary Hostname: $PRIMARY_HOSTNAME"
|
||||||
echo "Public IP Address: $PUBLIC_IP"
|
echo "Public IP Address: $PUBLIC_IP"
|
||||||
if [ -n "$PUBLIC_IPV6" ]; then
|
if [ ! -z "$PUBLIC_IPV6" ]; then
|
||||||
echo "Public IPv6 Address: $PUBLIC_IPV6"
|
echo "Public IPv6 Address: $PUBLIC_IPV6"
|
||||||
fi
|
fi
|
||||||
if [ "$PRIVATE_IP" != "$PUBLIC_IP" ]; then
|
if [ "$PRIVATE_IP" != "$PUBLIC_IP" ]; then
|
||||||
|
@ -208,6 +207,6 @@ if [ "$PRIVATE_IPV6" != "$PUBLIC_IPV6" ]; then
|
||||||
echo "Private IPv6 Address: $PRIVATE_IPV6"
|
echo "Private IPv6 Address: $PRIVATE_IPV6"
|
||||||
fi
|
fi
|
||||||
if [ -f /usr/bin/git ] && [ -d .git ]; then
|
if [ -f /usr/bin/git ] && [ -d .git ]; then
|
||||||
echo "Mail-in-a-Box Version: $(git describe --always)"
|
echo "Mail-in-a-Box Version: " $(git describe --always)
|
||||||
fi
|
fi
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -135,11 +135,11 @@ EOF
|
||||||
# the filemode in the config file.
|
# the filemode in the config file.
|
||||||
|
|
||||||
tools/editconf.py /etc/spamassassin/local.cf -s \
|
tools/editconf.py /etc/spamassassin/local.cf -s \
|
||||||
bayes_path="$STORAGE_ROOT/mail/spamassassin/bayes" \
|
bayes_path=$STORAGE_ROOT/mail/spamassassin/bayes \
|
||||||
bayes_file_mode=0666
|
bayes_file_mode=0666
|
||||||
|
|
||||||
mkdir -p "$STORAGE_ROOT/mail/spamassassin"
|
mkdir -p $STORAGE_ROOT/mail/spamassassin
|
||||||
chown -R spampd:spampd "$STORAGE_ROOT/mail/spamassassin"
|
chown -R spampd:spampd $STORAGE_ROOT/mail/spamassassin
|
||||||
|
|
||||||
# To mark mail as spam or ham, just drag it in or out of the Spam folder. We'll
|
# To mark mail as spam or ham, just drag it in or out of the Spam folder. We'll
|
||||||
# use the Dovecot antispam plugin to detect the message move operation and execute
|
# use the Dovecot antispam plugin to detect the message move operation and execute
|
||||||
|
@ -184,8 +184,8 @@ chmod a+x /usr/local/bin/sa-learn-pipe.sh
|
||||||
# Create empty bayes training data (if it doesn't exist). Once the files exist,
|
# Create empty bayes training data (if it doesn't exist). Once the files exist,
|
||||||
# ensure they are group-writable so that the Dovecot process has access.
|
# ensure they are group-writable so that the Dovecot process has access.
|
||||||
sudo -u spampd /usr/bin/sa-learn --sync 2>/dev/null
|
sudo -u spampd /usr/bin/sa-learn --sync 2>/dev/null
|
||||||
chmod -R 660 "$STORAGE_ROOT/mail/spamassassin"
|
chmod -R 660 $STORAGE_ROOT/mail/spamassassin
|
||||||
chmod 770 "$STORAGE_ROOT/mail/spamassassin"
|
chmod 770 $STORAGE_ROOT/mail/spamassassin
|
||||||
|
|
||||||
# Initial training?
|
# Initial training?
|
||||||
# sa-learn --ham storage/mail/mailboxes/*/*/cur/
|
# sa-learn --ham storage/mail/mailboxes/*/*/cur/
|
||||||
|
|
24
setup/ssl.sh
24
setup/ssl.sh
|
@ -26,9 +26,9 @@ source /etc/mailinabox.conf # load global vars
|
||||||
|
|
||||||
# Show a status line if we are going to take any action in this file.
|
# Show a status line if we are going to take any action in this file.
|
||||||
if [ ! -f /usr/bin/openssl ] \
|
if [ ! -f /usr/bin/openssl ] \
|
||||||
|| [ ! -f "$STORAGE_ROOT/ssl/ssl_private_key.pem" ] \
|
|| [ ! -f $STORAGE_ROOT/ssl/ssl_private_key.pem ] \
|
||||||
|| [ ! -f "$STORAGE_ROOT/ssl/ssl_certificate.pem" ] \
|
|| [ ! -f $STORAGE_ROOT/ssl/ssl_certificate.pem ] \
|
||||||
|| [ ! -f "$STORAGE_ROOT/ssl/dh2048.pem" ]; then
|
|| [ ! -f $STORAGE_ROOT/ssl/dh2048.pem ]; then
|
||||||
echo "Creating initial SSL certificate and perfect forward secrecy Diffie-Hellman parameters..."
|
echo "Creating initial SSL certificate and perfect forward secrecy Diffie-Hellman parameters..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ apt_install openssl
|
||||||
|
|
||||||
# Create a directory to store TLS-related things like "SSL" certificates.
|
# Create a directory to store TLS-related things like "SSL" certificates.
|
||||||
|
|
||||||
mkdir -p "$STORAGE_ROOT/ssl"
|
mkdir -p $STORAGE_ROOT/ssl
|
||||||
|
|
||||||
# Generate a new private key.
|
# Generate a new private key.
|
||||||
#
|
#
|
||||||
|
@ -60,39 +60,39 @@ mkdir -p "$STORAGE_ROOT/ssl"
|
||||||
#
|
#
|
||||||
# Since we properly seed /dev/urandom in system.sh we should be fine, but I leave
|
# Since we properly seed /dev/urandom in system.sh we should be fine, but I leave
|
||||||
# in the rest of the notes in case that ever changes.
|
# in the rest of the notes in case that ever changes.
|
||||||
if [ ! -f "$STORAGE_ROOT/ssl/ssl_private_key.pem" ]; then
|
if [ ! -f $STORAGE_ROOT/ssl/ssl_private_key.pem ]; then
|
||||||
# Set the umask so the key file is never world-readable.
|
# Set the umask so the key file is never world-readable.
|
||||||
(umask 077; hide_output \
|
(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 2048)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate a self-signed SSL certificate because things like nginx, dovecot,
|
# Generate a self-signed SSL certificate because things like nginx, dovecot,
|
||||||
# etc. won't even start without some certificate in place, and we need nginx
|
# etc. won't even start without some certificate in place, and we need nginx
|
||||||
# so we can offer the user a control panel to install a better certificate.
|
# so we can offer the user a control panel to install a better certificate.
|
||||||
if [ ! -f "$STORAGE_ROOT/ssl/ssl_certificate.pem" ]; then
|
if [ ! -f $STORAGE_ROOT/ssl/ssl_certificate.pem ]; then
|
||||||
# Generate a certificate signing request.
|
# Generate a certificate signing request.
|
||||||
CSR=/tmp/ssl_cert_sign_req-$$.csr
|
CSR=/tmp/ssl_cert_sign_req-$$.csr
|
||||||
hide_output \
|
hide_output \
|
||||||
openssl req -new -key "$STORAGE_ROOT/ssl/ssl_private_key.pem" -out $CSR \
|
openssl req -new -key $STORAGE_ROOT/ssl/ssl_private_key.pem -out $CSR \
|
||||||
-sha256 -subj "/CN=$PRIMARY_HOSTNAME"
|
-sha256 -subj "/CN=$PRIMARY_HOSTNAME"
|
||||||
|
|
||||||
# Generate the self-signed certificate.
|
# Generate the self-signed certificate.
|
||||||
CERT=$STORAGE_ROOT/ssl/$PRIMARY_HOSTNAME-selfsigned-$(date --rfc-3339=date | sed s/-//g).pem
|
CERT=$STORAGE_ROOT/ssl/$PRIMARY_HOSTNAME-selfsigned-$(date --rfc-3339=date | sed s/-//g).pem
|
||||||
hide_output \
|
hide_output \
|
||||||
openssl x509 -req -days 365 \
|
openssl x509 -req -days 365 \
|
||||||
-in $CSR -signkey "$STORAGE_ROOT/ssl/ssl_private_key.pem" -out "$CERT"
|
-in $CSR -signkey $STORAGE_ROOT/ssl/ssl_private_key.pem -out $CERT
|
||||||
|
|
||||||
# Delete the certificate signing request because it has no other purpose.
|
# Delete the certificate signing request because it has no other purpose.
|
||||||
rm -f $CSR
|
rm -f $CSR
|
||||||
|
|
||||||
# Symlink the certificate into the system certificate path, so system services
|
# Symlink the certificate into the system certificate path, so system services
|
||||||
# can find it.
|
# can find it.
|
||||||
ln -s "$CERT" "$STORAGE_ROOT/ssl/ssl_certificate.pem"
|
ln -s $CERT $STORAGE_ROOT/ssl/ssl_certificate.pem
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate some Diffie-Hellman cipher bits.
|
# Generate some Diffie-Hellman cipher bits.
|
||||||
# openssl's default bit length for this is 1024 bits, but we'll create
|
# openssl's default bit length for this is 1024 bits, but we'll create
|
||||||
# 2048 bits of bits per the latest recommendations.
|
# 2048 bits of bits per the latest recommendations.
|
||||||
if [ ! -f "$STORAGE_ROOT/ssl/dh2048.pem" ]; then
|
if [ ! -f $STORAGE_ROOT/ssl/dh2048.pem ]; then
|
||||||
openssl dhparam -out "$STORAGE_ROOT/ssl/dh2048.pem" 2048
|
openssl dhparam -out $STORAGE_ROOT/ssl/dh2048.pem 2048
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -46,7 +46,7 @@ fi
|
||||||
# in the first dialog prompt, so we should do this before that starts.
|
# in the first dialog prompt, so we should do this before that starts.
|
||||||
cat > /usr/local/bin/mailinabox << EOF;
|
cat > /usr/local/bin/mailinabox << EOF;
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd $PWD
|
cd $(pwd)
|
||||||
source setup/start.sh
|
source setup/start.sh
|
||||||
EOF
|
EOF
|
||||||
chmod +x /usr/local/bin/mailinabox
|
chmod +x /usr/local/bin/mailinabox
|
||||||
|
@ -75,17 +75,17 @@ fi
|
||||||
# migration (schema) number for the files stored there, assume this is a fresh
|
# migration (schema) number for the files stored there, assume this is a fresh
|
||||||
# installation to that directory and write the file to contain the current
|
# installation to that directory and write the file to contain the current
|
||||||
# migration number for this version of Mail-in-a-Box.
|
# migration number for this version of Mail-in-a-Box.
|
||||||
if ! id -u "$STORAGE_USER" >/dev/null 2>&1; then
|
if ! id -u $STORAGE_USER >/dev/null 2>&1; then
|
||||||
useradd -m "$STORAGE_USER"
|
useradd -m $STORAGE_USER
|
||||||
fi
|
fi
|
||||||
if [ ! -d "$STORAGE_ROOT" ]; then
|
if [ ! -d $STORAGE_ROOT ]; then
|
||||||
mkdir -p "$STORAGE_ROOT"
|
mkdir -p $STORAGE_ROOT
|
||||||
fi
|
fi
|
||||||
f=$STORAGE_ROOT
|
f=$STORAGE_ROOT
|
||||||
while [[ $f != / ]]; do chmod a+rx "$f"; f=$(dirname "$f"); done;
|
while [[ $f != / ]]; do chmod a+rx "$f"; f=$(dirname "$f"); done;
|
||||||
if [ ! -f "$STORAGE_ROOT/mailinabox.version" ]; then
|
if [ ! -f $STORAGE_ROOT/mailinabox.version ]; then
|
||||||
setup/migrate.py --current > "$STORAGE_ROOT/mailinabox.version"
|
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
|
fi
|
||||||
|
|
||||||
# Save the global options in /etc/mailinabox.conf so that standalone
|
# Save the global options in /etc/mailinabox.conf so that standalone
|
||||||
|
@ -122,7 +122,7 @@ source setup/munin.sh
|
||||||
# Wait for the management daemon to start...
|
# Wait for the management daemon to start...
|
||||||
until nc -z -w 4 127.0.0.1 10222
|
until nc -z -w 4 127.0.0.1 10222
|
||||||
do
|
do
|
||||||
echo "Waiting for the Mail-in-a-Box management daemon to start..."
|
echo Waiting for the Mail-in-a-Box management daemon to start...
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -142,41 +142,41 @@ source setup/firstuser.sh
|
||||||
# We'd let certbot ask the user interactively, but when this script is
|
# We'd let certbot ask the user interactively, but when this script is
|
||||||
# run in the recommended curl-pipe-to-bash method there is no TTY and
|
# run in the recommended curl-pipe-to-bash method there is no TTY and
|
||||||
# certbot will fail if it tries to ask.
|
# certbot will fail if it tries to ask.
|
||||||
if [ ! -d "$STORAGE_ROOT/ssl/lets_encrypt/accounts/acme-v02.api.letsencrypt.org/" ]; then
|
if [ ! -d $STORAGE_ROOT/ssl/lets_encrypt/accounts/acme-v02.api.letsencrypt.org/ ]; then
|
||||||
echo
|
echo
|
||||||
echo "-----------------------------------------------"
|
echo "-----------------------------------------------"
|
||||||
echo "Mail-in-a-Box uses Let's Encrypt to provision free SSL/TLS certificates"
|
echo "Mail-in-a-Box uses Let's Encrypt to provision free SSL/TLS certificates"
|
||||||
echo "to enable HTTPS connections to your box. We're automatically"
|
echo "to enable HTTPS connections to your box. We're automatically"
|
||||||
echo "agreeing you to their subscriber agreement. See https://letsencrypt.org."
|
echo "agreeing you to their subscriber agreement. See https://letsencrypt.org."
|
||||||
echo
|
echo
|
||||||
certbot register --register-unsafely-without-email --agree-tos --config-dir "$STORAGE_ROOT/ssl/lets_encrypt"
|
certbot register --register-unsafely-without-email --agree-tos --config-dir $STORAGE_ROOT/ssl/lets_encrypt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Done.
|
# Done.
|
||||||
echo
|
echo
|
||||||
echo "-----------------------------------------------"
|
echo "-----------------------------------------------"
|
||||||
echo
|
echo
|
||||||
echo "Your Mail-in-a-Box is running."
|
echo Your Mail-in-a-Box is running.
|
||||||
echo
|
echo
|
||||||
echo "Please log in to the control panel for further instructions at:"
|
echo Please log in to the control panel for further instructions at:
|
||||||
echo
|
echo
|
||||||
if management/status_checks.py --check-primary-hostname; then
|
if management/status_checks.py --check-primary-hostname; then
|
||||||
# Show the nice URL if it appears to be resolving and has a valid certificate.
|
# Show the nice URL if it appears to be resolving and has a valid certificate.
|
||||||
echo "https://$PRIMARY_HOSTNAME/admin"
|
echo https://$PRIMARY_HOSTNAME/admin
|
||||||
echo
|
echo
|
||||||
echo "If you have a DNS problem put the box's IP address in the URL"
|
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:"
|
echo "(https://$PUBLIC_IP/admin) but then check the TLS fingerprint:"
|
||||||
openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256\
|
openssl x509 -in $STORAGE_ROOT/ssl/ssl_certificate.pem -noout -fingerprint -sha256\
|
||||||
| sed "s/SHA256 Fingerprint=//i"
|
| sed "s/SHA256 Fingerprint=//i"
|
||||||
else
|
else
|
||||||
echo "https://$PUBLIC_IP/admin"
|
echo https://$PUBLIC_IP/admin
|
||||||
echo
|
echo
|
||||||
echo "You will be alerted that the website has an invalid certificate. Check that"
|
echo You will be alerted that the website has an invalid certificate. Check that
|
||||||
echo "the certificate fingerprint matches:"
|
echo the certificate fingerprint matches:
|
||||||
echo
|
echo
|
||||||
openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256\
|
openssl x509 -in $STORAGE_ROOT/ssl/ssl_certificate.pem -noout -fingerprint -sha256\
|
||||||
| sed "s/SHA256 Fingerprint=//i"
|
| sed "s/SHA256 Fingerprint=//i"
|
||||||
echo
|
echo
|
||||||
echo "Then you can confirm the security exception and continue."
|
echo Then you can confirm the security exception and continue.
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/bin/bash
|
|
||||||
source /etc/mailinabox.conf
|
source /etc/mailinabox.conf
|
||||||
source setup/functions.sh # load our functions
|
source setup/functions.sh # load our functions
|
||||||
|
|
||||||
|
@ -12,8 +11,8 @@ source setup/functions.sh # load our functions
|
||||||
#
|
#
|
||||||
# First set the hostname in the configuration file, then activate the setting
|
# First set the hostname in the configuration file, then activate the setting
|
||||||
|
|
||||||
echo "$PRIMARY_HOSTNAME" > /etc/hostname
|
echo $PRIMARY_HOSTNAME > /etc/hostname
|
||||||
hostname "$PRIMARY_HOSTNAME"
|
hostname $PRIMARY_HOSTNAME
|
||||||
|
|
||||||
# ### Fix permissions
|
# ### Fix permissions
|
||||||
|
|
||||||
|
@ -54,14 +53,14 @@ if
|
||||||
[ -z "$SWAP_IN_FSTAB" ] &&
|
[ -z "$SWAP_IN_FSTAB" ] &&
|
||||||
[ ! -e /swapfile ] &&
|
[ ! -e /swapfile ] &&
|
||||||
[ -z "$ROOT_IS_BTRFS" ] &&
|
[ -z "$ROOT_IS_BTRFS" ] &&
|
||||||
[ "$TOTAL_PHYSICAL_MEM" -lt 1900000 ] &&
|
[ $TOTAL_PHYSICAL_MEM -lt 1900000 ] &&
|
||||||
[ "$AVAILABLE_DISK_SPACE" -gt 5242880 ]
|
[ $AVAILABLE_DISK_SPACE -gt 5242880 ]
|
||||||
then
|
then
|
||||||
echo "Adding a swap file to the system..."
|
echo "Adding a swap file to the system..."
|
||||||
|
|
||||||
# Allocate and activate the swap file. Allocate in 1KB chuncks
|
# Allocate and activate the swap file. Allocate in 1KB chuncks
|
||||||
# doing it in one go, could fail on low memory systems
|
# doing it in one go, could fail on low memory systems
|
||||||
dd if=/dev/zero of=/swapfile bs=1024 count=$((1024*1024)) status=none
|
dd if=/dev/zero of=/swapfile bs=1024 count=$[1024*1024] status=none
|
||||||
if [ -e /swapfile ]; then
|
if [ -e /swapfile ]; then
|
||||||
chmod 600 /swapfile
|
chmod 600 /swapfile
|
||||||
hide_output mkswap /swapfile
|
hide_output mkswap /swapfile
|
||||||
|
@ -111,7 +110,7 @@ hide_output add-apt-repository --y ppa:ondrej/php
|
||||||
# of things from Ubuntu, as well as the directory of packages provide by the
|
# of things from Ubuntu, as well as the directory of packages provide by the
|
||||||
# PPAs so we can install those packages later.
|
# PPAs so we can install those packages later.
|
||||||
|
|
||||||
echo "Updating system packages..."
|
echo Updating system packages...
|
||||||
hide_output apt-get update
|
hide_output apt-get update
|
||||||
apt_get_quiet upgrade
|
apt_get_quiet upgrade
|
||||||
|
|
||||||
|
@ -136,7 +135,7 @@ apt_get_quiet autoremove
|
||||||
# * bc: allows us to do math to compute sane defaults
|
# * bc: allows us to do math to compute sane defaults
|
||||||
# * openssh-client: provides ssh-keygen
|
# * openssh-client: provides ssh-keygen
|
||||||
|
|
||||||
echo "Installing system packages..."
|
echo Installing system packages...
|
||||||
apt_install python3 python3-dev python3-pip python3-setuptools \
|
apt_install python3 python3-dev python3-pip python3-setuptools \
|
||||||
netcat-openbsd wget curl git sudo coreutils bc file \
|
netcat-openbsd wget curl git sudo coreutils bc file \
|
||||||
pollinate openssh-client unzip \
|
pollinate openssh-client unzip \
|
||||||
|
@ -165,7 +164,7 @@ fi
|
||||||
# not likely the user will want to change this, so we only ask on first
|
# not likely the user will want to change this, so we only ask on first
|
||||||
# setup.
|
# setup.
|
||||||
if [ -z "${NONINTERACTIVE:-}" ]; then
|
if [ -z "${NONINTERACTIVE:-}" ]; then
|
||||||
if [ ! -f /etc/timezone ] || [ -n "${FIRST_TIME_SETUP:-}" ]; then
|
if [ ! -f /etc/timezone ] || [ ! -z ${FIRST_TIME_SETUP:-} ]; then
|
||||||
# If the file is missing or this is the user's first time running
|
# If the file is missing or this is the user's first time running
|
||||||
# Mail-in-a-Box setup, run the interactive timezone configuration
|
# Mail-in-a-Box setup, run the interactive timezone configuration
|
||||||
# tool.
|
# tool.
|
||||||
|
@ -227,7 +226,7 @@ fi
|
||||||
# hardware entropy to get going, by drawing from /dev/random. haveged makes this
|
# hardware entropy to get going, by drawing from /dev/random. haveged makes this
|
||||||
# less likely to stall for very long.
|
# less likely to stall for very long.
|
||||||
|
|
||||||
echo "Initializing system random number generator..."
|
echo Initializing system random number generator...
|
||||||
dd if=/dev/random of=/dev/urandom bs=1 count=32 2> /dev/null
|
dd if=/dev/random of=/dev/urandom bs=1 count=32 2> /dev/null
|
||||||
|
|
||||||
# This is supposedly sufficient. But because we're not sure if hardware entropy
|
# This is supposedly sufficient. But because we're not sure if hardware entropy
|
||||||
|
@ -271,11 +270,11 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then
|
||||||
# settings, find the port it is supposedly running on, and open that port #NODOC
|
# settings, find the port it is supposedly running on, and open that port #NODOC
|
||||||
# too. #NODOC
|
# too. #NODOC
|
||||||
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
|
SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC
|
||||||
if [ -n "$SSH_PORT" ]; then
|
if [ ! -z "$SSH_PORT" ]; then
|
||||||
if [ "$SSH_PORT" != "22" ]; then
|
if [ "$SSH_PORT" != "22" ]; then
|
||||||
|
|
||||||
echo "Opening alternate SSH port $SSH_PORT." #NODOC
|
echo Opening alternate SSH port $SSH_PORT. #NODOC
|
||||||
ufw_limit "$SSH_PORT" #NODOC
|
ufw_limit $SSH_PORT #NODOC
|
||||||
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
36
setup/web.sh
36
setup/web.sh
|
@ -8,7 +8,7 @@ source /etc/mailinabox.conf # load global vars
|
||||||
# Some Ubuntu images start off with Apache. Remove it since we
|
# Some Ubuntu images start off with Apache. Remove it since we
|
||||||
# will use nginx. Use autoremove to remove any Apache depenencies.
|
# will use nginx. Use autoremove to remove any Apache depenencies.
|
||||||
if [ -f /usr/sbin/apache2 ]; then
|
if [ -f /usr/sbin/apache2 ]; then
|
||||||
echo "Removing apache..."
|
echo Removing apache...
|
||||||
hide_output apt-get -y purge apache2 apache2-*
|
hide_output apt-get -y purge apache2 apache2-*
|
||||||
hide_output apt-get -y --purge autoremove
|
hide_output apt-get -y --purge autoremove
|
||||||
fi
|
fi
|
||||||
|
@ -19,7 +19,7 @@ fi
|
||||||
|
|
||||||
echo "Installing Nginx (web server)..."
|
echo "Installing Nginx (web server)..."
|
||||||
|
|
||||||
apt_install nginx php"${PHP_VER}"-cli php"${PHP_VER}"-fpm idn2
|
apt_install nginx php${PHP_VER}-cli php${PHP_VER}-fpm idn2
|
||||||
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
|
||||||
|
@ -46,15 +46,15 @@ tools/editconf.py /etc/nginx/nginx.conf -s \
|
||||||
ssl_protocols="TLSv1.2 TLSv1.3;"
|
ssl_protocols="TLSv1.2 TLSv1.3;"
|
||||||
|
|
||||||
# Tell PHP not to expose its version number in the X-Powered-By header.
|
# Tell PHP not to expose its version number in the X-Powered-By header.
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/php.ini -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/php.ini -c ';' \
|
||||||
expose_php=Off
|
expose_php=Off
|
||||||
|
|
||||||
# Set PHPs default charset to UTF-8, since we use it. See #367.
|
# Set PHPs default charset to UTF-8, since we use it. See #367.
|
||||||
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"
|
default_charset="UTF-8"
|
||||||
|
|
||||||
# Configure the path environment for php-fpm
|
# Configure the path environment for php-fpm
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
|
||||||
env[PATH]=/usr/local/bin:/usr/bin:/bin \
|
env[PATH]=/usr/local/bin:/usr/bin:/bin \
|
||||||
|
|
||||||
# Configure php-fpm based on the amount of memory the machine has
|
# Configure php-fpm based on the amount of memory the machine has
|
||||||
|
@ -62,32 +62,32 @@ tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
||||||
# Some synchronisation issues can occur when many people access the site at once.
|
# Some synchronisation issues can occur when many people access the site at once.
|
||||||
# The pm=ondemand setting is used for memory constrained machines < 2GB, this is copied over from PR: 1216
|
# The pm=ondemand setting is used for memory constrained machines < 2GB, this is copied over from PR: 1216
|
||||||
TOTAL_PHYSICAL_MEM=$(head -n 1 /proc/meminfo | awk '{print $2}' || /bin/true)
|
TOTAL_PHYSICAL_MEM=$(head -n 1 /proc/meminfo | awk '{print $2}' || /bin/true)
|
||||||
if [ "$TOTAL_PHYSICAL_MEM" -lt 1000000 ]
|
if [ $TOTAL_PHYSICAL_MEM -lt 1000000 ]
|
||||||
then
|
then
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
|
||||||
pm=ondemand \
|
pm=ondemand \
|
||||||
pm.max_children=8 \
|
pm.max_children=8 \
|
||||||
pm.start_servers=2 \
|
pm.start_servers=2 \
|
||||||
pm.min_spare_servers=1 \
|
pm.min_spare_servers=1 \
|
||||||
pm.max_spare_servers=3
|
pm.max_spare_servers=3
|
||||||
elif [ "$TOTAL_PHYSICAL_MEM" -lt 2000000 ]
|
elif [ $TOTAL_PHYSICAL_MEM -lt 2000000 ]
|
||||||
then
|
then
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
|
||||||
pm=ondemand \
|
pm=ondemand \
|
||||||
pm.max_children=16 \
|
pm.max_children=16 \
|
||||||
pm.start_servers=4 \
|
pm.start_servers=4 \
|
||||||
pm.min_spare_servers=1 \
|
pm.min_spare_servers=1 \
|
||||||
pm.max_spare_servers=6
|
pm.max_spare_servers=6
|
||||||
elif [ "$TOTAL_PHYSICAL_MEM" -lt 3000000 ]
|
elif [ $TOTAL_PHYSICAL_MEM -lt 3000000 ]
|
||||||
then
|
then
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
|
||||||
pm=dynamic \
|
pm=dynamic \
|
||||||
pm.max_children=60 \
|
pm.max_children=60 \
|
||||||
pm.start_servers=6 \
|
pm.start_servers=6 \
|
||||||
pm.min_spare_servers=3 \
|
pm.min_spare_servers=3 \
|
||||||
pm.max_spare_servers=9
|
pm.max_spare_servers=9
|
||||||
else
|
else
|
||||||
tools/editconf.py /etc/php/"$PHP_VER"/fpm/pool.d/www.conf -c ';' \
|
tools/editconf.py /etc/php/$PHP_VER/fpm/pool.d/www.conf -c ';' \
|
||||||
pm=dynamic \
|
pm=dynamic \
|
||||||
pm.max_children=120 \
|
pm.max_children=120 \
|
||||||
pm.start_servers=12 \
|
pm.start_servers=12 \
|
||||||
|
@ -138,16 +138,16 @@ cat conf/mta-sts.txt \
|
||||||
chmod a+r /var/lib/mailinabox/mta-sts.txt
|
chmod a+r /var/lib/mailinabox/mta-sts.txt
|
||||||
|
|
||||||
# make a default homepage
|
# make a default homepage
|
||||||
if [ -d "$STORAGE_ROOT/www/static" ]; then mv "$STORAGE_ROOT/www/static" "$STORAGE_ROOT/www/default"; fi # migration #NODOC
|
if [ -d $STORAGE_ROOT/www/static ]; then mv $STORAGE_ROOT/www/static $STORAGE_ROOT/www/default; fi # migration #NODOC
|
||||||
mkdir -p "$STORAGE_ROOT/www/default"
|
mkdir -p $STORAGE_ROOT/www/default
|
||||||
if [ ! -f "$STORAGE_ROOT/www/default/index.html" ]; then
|
if [ ! -f $STORAGE_ROOT/www/default/index.html ]; then
|
||||||
cp conf/www_default.html "$STORAGE_ROOT/www/default/index.html"
|
cp conf/www_default.html $STORAGE_ROOT/www/default/index.html
|
||||||
fi
|
fi
|
||||||
chown -R "$STORAGE_USER" "$STORAGE_ROOT/www"
|
chown -R $STORAGE_USER $STORAGE_ROOT/www
|
||||||
|
|
||||||
# Start services.
|
# Start services.
|
||||||
restart_service nginx
|
restart_service nginx
|
||||||
restart_service php"$PHP_VER"-fpm
|
restart_service php$PHP_VER-fpm
|
||||||
|
|
||||||
# Open ports.
|
# Open ports.
|
||||||
ufw_allow http
|
ufw_allow http
|
||||||
|
|
|
@ -22,8 +22,8 @@ source /etc/mailinabox.conf # load global vars
|
||||||
echo "Installing Roundcube (webmail)..."
|
echo "Installing Roundcube (webmail)..."
|
||||||
apt_install \
|
apt_install \
|
||||||
dbconfig-common \
|
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}-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 \
|
php${PHP_VER}-gd php${PHP_VER}-pspell php${PHP_VER}-mbstring libjs-jquery libjs-jquery-mousewheel libmagic1 \
|
||||||
sqlite3
|
sqlite3
|
||||||
|
|
||||||
# Install Roundcube from source if it is not already present or if it is out of date.
|
# Install Roundcube from source if it is not already present or if it is out of date.
|
||||||
|
@ -170,8 +170,8 @@ cat > ${RCM_PLUGIN_DIR}/carddav/config.inc.php <<EOF;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Create writable directories.
|
# Create writable directories.
|
||||||
mkdir -p /var/log/roundcubemail /var/tmp/roundcubemail "$STORAGE_ROOT/mail/roundcube"
|
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.
|
# Ensure the log file monitored by fail2ban exists, or else fail2ban can't start.
|
||||||
sudo -u www-data touch /var/log/roundcubemail/errors.log
|
sudo -u www-data touch /var/log/roundcubemail/errors.log
|
||||||
|
@ -194,10 +194,10 @@ usermod -a -G dovecot www-data
|
||||||
|
|
||||||
# set permissions so that PHP can use users.sqlite
|
# set permissions so that PHP can use users.sqlite
|
||||||
# could use dovecot instead of www-data, but not sure it matters
|
# 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"
|
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"
|
chmod 664 $STORAGE_ROOT/mail/users.sqlite
|
||||||
|
|
||||||
# Fix Carddav permissions:
|
# Fix Carddav permissions:
|
||||||
chown -f -R root:www-data ${RCM_PLUGIN_DIR}/carddav
|
chown -f -R root:www-data ${RCM_PLUGIN_DIR}/carddav
|
||||||
|
@ -205,9 +205,9 @@ chown -f -R root:www-data ${RCM_PLUGIN_DIR}/carddav
|
||||||
chmod -R 774 ${RCM_PLUGIN_DIR}/carddav
|
chmod -R 774 ${RCM_PLUGIN_DIR}/carddav
|
||||||
|
|
||||||
# Run Roundcube database migration script (database is created if it does not exist)
|
# 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
|
php$PHP_VER ${RCM_DIR}/bin/updatedb.sh --dir ${RCM_DIR}/SQL --package roundcube
|
||||||
chown www-data:www-data "$STORAGE_ROOT/mail/roundcube/roundcube.sqlite"
|
chown www-data:www-data $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
|
||||||
chmod 664 "$STORAGE_ROOT/mail/roundcube/roundcube.sqlite"
|
chmod 664 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite
|
||||||
|
|
||||||
# Patch the Roundcube code to eliminate an issue that causes postfix to reject our sqlite
|
# Patch the Roundcube code to eliminate an issue that causes postfix to reject our sqlite
|
||||||
# user database (see https://github.com/mail-in-a-box/mailinabox/issues/2185)
|
# user database (see https://github.com/mail-in-a-box/mailinabox/issues/2185)
|
||||||
|
@ -217,8 +217,8 @@ sed -i.miabold 's/^[^#]\+.\+PRAGMA journal_mode = WAL.\+$/#&/' \
|
||||||
# Because Roundcube wants to set the PRAGMA we just deleted from the source, we apply it here
|
# Because Roundcube wants to set the PRAGMA we just deleted from the source, we apply it here
|
||||||
# to the roundcube database (see https://github.com/roundcube/roundcubemail/issues/8035)
|
# to the roundcube database (see https://github.com/roundcube/roundcubemail/issues/8035)
|
||||||
# Database should exist, created by migration script
|
# Database should exist, created by migration script
|
||||||
hide_output sqlite3 "$STORAGE_ROOT/mail/roundcube/roundcube.sqlite" 'PRAGMA journal_mode=WAL;'
|
sqlite3 $STORAGE_ROOT/mail/roundcube/roundcube.sqlite 'PRAGMA journal_mode=WAL;' | 2>&1
|
||||||
|
|
||||||
# Enable PHP modules.
|
# Enable PHP modules.
|
||||||
phpenmod -v "$PHP_VER" imap
|
phpenmod -v $PHP_VER imap
|
||||||
restart_service php"$PHP_VER"-fpm
|
restart_service php$PHP_VER-fpm
|
||||||
|
|
|
@ -17,9 +17,9 @@ source /etc/mailinabox.conf # load global vars
|
||||||
|
|
||||||
echo "Installing Z-Push (Exchange/ActiveSync server)..."
|
echo "Installing Z-Push (Exchange/ActiveSync server)..."
|
||||||
apt_install \
|
apt_install \
|
||||||
php"${PHP_VER}"-soap php"${PHP_VER}"-imap libawl-php php"$PHP_VER"-xml
|
php${PHP_VER}-soap php${PHP_VER}-imap libawl-php php$PHP_VER-xml
|
||||||
|
|
||||||
phpenmod -v "$PHP_VER" imap
|
phpenmod -v $PHP_VER imap
|
||||||
|
|
||||||
# Copy Z-Push into place.
|
# Copy Z-Push into place.
|
||||||
VERSION=2.7.1
|
VERSION=2.7.1
|
||||||
|
@ -44,10 +44,10 @@ if [ $needs_update == 1 ]; then
|
||||||
# Create admin and top scripts with PHP_VER
|
# Create admin and top scripts with PHP_VER
|
||||||
rm -f /usr/sbin/z-push-{admin,top}
|
rm -f /usr/sbin/z-push-{admin,top}
|
||||||
echo '#!/bin/bash' > /usr/sbin/z-push-admin
|
echo '#!/bin/bash' > /usr/sbin/z-push-admin
|
||||||
echo php"$PHP_VER" /usr/local/lib/z-push/z-push-admin.php '"$@"' >> /usr/sbin/z-push-admin
|
echo php$PHP_VER /usr/local/lib/z-push/z-push-admin.php '"$@"' >> /usr/sbin/z-push-admin
|
||||||
chmod 755 /usr/sbin/z-push-admin
|
chmod 755 /usr/sbin/z-push-admin
|
||||||
echo '#!/bin/bash' > /usr/sbin/z-push-top
|
echo '#!/bin/bash' > /usr/sbin/z-push-top
|
||||||
echo php"$PHP_VER" /usr/local/lib/z-push/z-push-top.php '"$@"' >> /usr/sbin/z-push-top
|
echo php$PHP_VER /usr/local/lib/z-push/z-push-top.php '"$@"' >> /usr/sbin/z-push-top
|
||||||
chmod 755 /usr/sbin/z-push-top
|
chmod 755 /usr/sbin/z-push-top
|
||||||
|
|
||||||
echo $VERSION > /usr/local/lib/z-push/version
|
echo $VERSION > /usr/local/lib/z-push/version
|
||||||
|
@ -108,8 +108,8 @@ EOF
|
||||||
|
|
||||||
# Restart service.
|
# Restart service.
|
||||||
|
|
||||||
restart_service php"$PHP_VER"-fpm
|
restart_service php$PHP_VER-fpm
|
||||||
|
|
||||||
# Fix states after upgrade
|
# Fix states after upgrade
|
||||||
|
|
||||||
hide_output php"$PHP_VER" /usr/local/lib/z-push/z-push-admin.php -a fixstates
|
hide_output php$PHP_VER /usr/local/lib/z-push/z-push-admin.php -a fixstates
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#!/bin/bash
|
|
||||||
# Use this script to make an archive of the contents of all
|
# Use this script to make an archive of the contents of all
|
||||||
# of the configuration files we edit with editconf.py.
|
# of the configuration files we edit with editconf.py.
|
||||||
for fn in $(grep -hr editconf.py setup | sed "s/tools\/editconf.py //" | sed "s/ .*//" | sort | uniq); do
|
for fn in `grep -hr editconf.py setup | sed "s/tools\/editconf.py //" | sed "s/ .*//" | sort | uniq`; do
|
||||||
echo ======================================================================
|
echo ======================================================================
|
||||||
echo "$fn"
|
echo $fn
|
||||||
echo ======================================================================
|
echo ======================================================================
|
||||||
cat "$fn"
|
cat $fn
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,4 @@ POSTDATA=dummy
|
||||||
if [ "$1" == "--force" ]; then
|
if [ "$1" == "--force" ]; then
|
||||||
POSTDATA=force=1
|
POSTDATA=force=1
|
||||||
fi
|
fi
|
||||||
curl -s -d $POSTDATA --user "$(</var/lib/mailinabox/api.key):" http://127.0.0.1:10222/dns/update
|
curl -s -d $POSTDATA --user $(</var/lib/mailinabox/api.key): http://127.0.0.1:10222/dns/update
|
||||||
|
|
|
@ -30,7 +30,7 @@ import sys, re
|
||||||
|
|
||||||
# sanity check
|
# sanity check
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
print("usage: python3 editconf.py /etc/file.conf [-e] [-s] [-w] [-c <CHARACTER>] [-t] NAME=VAL [NAME=VAL ...]")
|
print("usage: python3 editconf.py /etc/file.conf [-s] [-w] [-c <CHARACTER>] [-t] NAME=VAL [NAME=VAL ...]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# parse command line arguments
|
# parse command line arguments
|
||||||
|
|
|
@ -14,13 +14,13 @@ if [ -z "$1" ]; then
|
||||||
echo
|
echo
|
||||||
echo "Available backups:"
|
echo "Available backups:"
|
||||||
echo
|
echo
|
||||||
find "$STORAGE_ROOT/owncloud-backup/"* -maxdepth 0 -type d
|
find $STORAGE_ROOT/owncloud-backup/* -maxdepth 0 -type d
|
||||||
echo
|
echo
|
||||||
echo "Supply the directory that was created during the last installation as the only commandline argument"
|
echo "Supply the directory that was created during the last installation as the only commandline argument"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "$1/config.php" ]; then
|
if [ ! -f $1/config.php ]; then
|
||||||
echo "This isn't a valid backup location"
|
echo "This isn't a valid backup location"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -36,14 +36,14 @@ cp -r "$1/owncloud-install" /usr/local/lib/owncloud
|
||||||
# restore access rights
|
# restore access rights
|
||||||
chmod 750 /usr/local/lib/owncloud/{apps,config}
|
chmod 750 /usr/local/lib/owncloud/{apps,config}
|
||||||
|
|
||||||
cp "$1/owncloud.db" "$STORAGE_ROOT/owncloud/"
|
cp "$1/owncloud.db" $STORAGE_ROOT/owncloud/
|
||||||
cp "$1/config.php" "$STORAGE_ROOT/owncloud/"
|
cp "$1/config.php" $STORAGE_ROOT/owncloud/
|
||||||
|
|
||||||
ln -sf "$STORAGE_ROOT/owncloud/config.php" /usr/local/lib/owncloud/config/config.php
|
ln -sf $STORAGE_ROOT/owncloud/config.php /usr/local/lib/owncloud/config/config.php
|
||||||
chown -f -R www-data:www-data "$STORAGE_ROOT/owncloud" /usr/local/lib/owncloud
|
chown -f -R www-data:www-data $STORAGE_ROOT/owncloud /usr/local/lib/owncloud
|
||||||
chown www-data:www-data "$STORAGE_ROOT/owncloud/config.php"
|
chown www-data:www-data $STORAGE_ROOT/owncloud/config.php
|
||||||
|
|
||||||
sudo -u www-data "php$PHP_VER" /usr/local/lib/owncloud/occ maintenance:mode --off
|
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ maintenance:mode --off
|
||||||
|
|
||||||
service php8.0-fpm start
|
service php8.0-fpm start
|
||||||
echo "Done"
|
echo "Done"
|
||||||
|
|
|
@ -11,13 +11,13 @@ source /etc/mailinabox.conf # load global vars
|
||||||
ADMIN=$(./mail.py user admins | head -n 1)
|
ADMIN=$(./mail.py user admins | head -n 1)
|
||||||
test -z "$1" || ADMIN=$1
|
test -z "$1" || ADMIN=$1
|
||||||
|
|
||||||
echo "I am going to unlock admin features for $ADMIN."
|
echo I am going to unlock admin features for $ADMIN.
|
||||||
echo "You can provide another user to unlock as the first argument of this script."
|
echo You can provide another user to unlock as the first argument of this script.
|
||||||
echo
|
echo
|
||||||
echo "WARNING: you could break mail-in-a-box when fiddling around with Nextcloud's admin interface"
|
echo WARNING: you could break mail-in-a-box when fiddling around with Nextcloud\'s admin interface
|
||||||
echo "If in doubt, press CTRL-C to cancel."
|
echo If in doubt, press CTRL-C to cancel.
|
||||||
echo
|
echo
|
||||||
echo "Press enter to continue."
|
echo Press enter to continue.
|
||||||
read
|
read
|
||||||
|
|
||||||
sudo -u www-data "php$PHP_VER" /usr/local/lib/owncloud/occ group:adduser admin "$ADMIN" && echo "Done."
|
sudo -u www-data php$PHP_VER /usr/local/lib/owncloud/occ group:adduser admin $ADMIN && echo Done.
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
curl -s -d POSTDATA --user "$(</var/lib/mailinabox/api.key):" http://127.0.0.1:10222/web/update
|
curl -s -d POSTDATA --user $(</var/lib/mailinabox/api.key): http://127.0.0.1:10222/web/update
|
||||||
|
|
Loading…
Reference in New Issue