2015-07-20 00:09:47 -07:00
#!/bin/bash
set -eu -o pipefail
2018-10-26 10:13:27 -07:00
# This script is run after the box code is switched. This means that this script
# should pretty much always succeed. No network logic/download code here.
2016-12-29 14:21:08 -08:00
echo "==> Cloudron Start"
2015-07-20 00:09:47 -07:00
readonly USER = "yellowtent"
2017-01-24 10:09:05 -08:00
readonly HOME_DIR = " /home/ ${ USER } "
readonly BOX_SRC_DIR = " ${ HOME_DIR } /box "
2017-03-29 15:51:53 +02:00
readonly PLATFORM_DATA_DIR = " ${ HOME_DIR } /platformdata " # platform data
readonly APPS_DATA_DIR = " ${ HOME_DIR } /appsdata " # app data
2017-01-24 10:09:05 -08:00
readonly BOX_DATA_DIR = " ${ HOME_DIR } /boxdata " # box data
2015-07-20 00:09:47 -07:00
2016-12-29 14:21:08 -08:00
readonly script_dir = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " && pwd ) "
2018-12-10 15:36:00 -08:00
readonly json = " $( realpath ${ script_dir } /../node_modules/.bin/json) "
2019-01-17 09:20:31 -08:00
readonly ubuntu_version = $( lsb_release -rs)
2015-07-20 00:09:47 -07:00
2018-12-26 19:42:45 -08:00
cp -f " ${ script_dir } /../scripts/cloudron-support " /usr/bin/cloudron-support
2020-11-18 22:03:57 +01:00
cp -f " ${ script_dir } /../scripts/cloudron-translation-update " /usr/bin/cloudron-translation-update
2018-12-26 19:42:45 -08:00
2020-04-29 21:55:21 -07:00
# this needs to match the cloudron/base:2.0.0 gid
if ! getent group media; then
addgroup --gid 500 --system media
fi
2016-12-29 12:01:59 -08:00
echo "==> Configuring docker"
cp " ${ script_dir } /start/docker-cloudron-app.apparmor " /etc/apparmor.d/docker-cloudron-app
2017-01-10 18:15:10 -08:00
systemctl enable apparmor
2016-12-29 12:01:59 -08:00
systemctl restart apparmor
2017-01-24 10:32:32 -08:00
usermod ${ USER } -a -G docker
2020-11-20 17:22:54 -08:00
# unbound (which starts after box code) relies on this interface to exist. dockerproxy also relies on this.
docker network create --subnet= 172.18.0.0/16 --ip-range= 172.18.0.0/20 cloudron || true
2016-12-29 12:01:59 -08:00
2017-03-30 13:45:57 +02:00
mkdir -p " ${ BOX_DATA_DIR } "
2017-03-29 16:09:49 +02:00
mkdir -p " ${ APPS_DATA_DIR } "
2016-12-29 14:35:48 -08:00
# keep these in sync with paths.js
echo "==> Ensuring directories"
2017-03-30 13:45:57 +02:00
2017-03-29 15:51:53 +02:00
mkdir -p " ${ PLATFORM_DATA_DIR } /graphite "
mkdir -p " ${ PLATFORM_DATA_DIR } /mysql "
mkdir -p " ${ PLATFORM_DATA_DIR } /postgresql "
mkdir -p " ${ PLATFORM_DATA_DIR } /mongodb "
2018-09-18 12:28:03 -07:00
mkdir -p " ${ PLATFORM_DATA_DIR } /redis "
2020-08-23 14:33:58 -07:00
mkdir -p " ${ PLATFORM_DATA_DIR } /addons/mail/banner "
2017-03-29 15:51:53 +02:00
mkdir -p " ${ PLATFORM_DATA_DIR } /collectd/collectd.conf.d "
2017-08-11 22:05:31 +02:00
mkdir -p " ${ PLATFORM_DATA_DIR } /logrotate.d "
2017-03-29 15:51:53 +02:00
mkdir -p " ${ PLATFORM_DATA_DIR } /acme "
2017-09-26 16:31:08 -07:00
mkdir -p " ${ PLATFORM_DATA_DIR } /backup "
2019-03-01 14:40:28 -08:00
mkdir -p " ${ PLATFORM_DATA_DIR } /logs/backup " \
" ${ PLATFORM_DATA_DIR } /logs/updater " \
" ${ PLATFORM_DATA_DIR } /logs/tasks " \
2020-02-18 20:34:13 -08:00
" ${ PLATFORM_DATA_DIR } /logs/crash " \
" ${ PLATFORM_DATA_DIR } /logs/collectd "
2018-08-01 15:38:40 -07:00
mkdir -p " ${ PLATFORM_DATA_DIR } /update "
2017-03-29 15:51:53 +02:00
2017-01-24 10:09:05 -08:00
mkdir -p " ${ BOX_DATA_DIR } /appicons "
2020-09-14 10:29:48 -07:00
mkdir -p " ${ BOX_DATA_DIR } /firewall "
2019-11-25 16:12:22 +01:00
mkdir -p " ${ BOX_DATA_DIR } /profileicons "
2017-01-24 10:09:05 -08:00
mkdir -p " ${ BOX_DATA_DIR } /certs "
mkdir -p " ${ BOX_DATA_DIR } /acme " # acme keys
2017-09-09 22:37:39 -07:00
mkdir -p " ${ BOX_DATA_DIR } /mail/dkim "
2020-04-08 23:11:37 -07:00
mkdir -p " ${ BOX_DATA_DIR } /well-known " # .well-known documents
2017-01-24 10:09:05 -08:00
2017-04-20 15:41:25 +02:00
# ensure backups folder exists and is writeable
mkdir -p /var/backups
chmod 777 /var/backups
2016-12-29 12:01:59 -08:00
echo "==> Configuring journald"
sed -e " s/^#SystemMaxUse=.* $/SystemMaxUse=100M/ " \
-e " s/^#ForwardToSyslog=.* $/ForwardToSyslog=no/ " \
-i /etc/systemd/journald.conf
# When rotating logs, systemd kills journald too soon sometimes
# See https://github.com/systemd/systemd/issues/1353 (this is upstream default)
sed -e " s/^WatchdogSec=.* $/WatchdogSec=3min/ " \
-i /lib/systemd/system/systemd-journald.service
# Give user access to system logs
2017-01-24 10:32:32 -08:00
usermod -a -G systemd-journal ${ USER }
2016-12-29 12:01:59 -08:00
mkdir -p /var/log/journal # in some images, this directory is not created making system log to /run/systemd instead
chown root:systemd-journal /var/log/journal
2017-01-23 11:01:02 +01:00
systemctl daemon-reload
2016-12-29 12:01:59 -08:00
systemctl restart systemd-journald
2017-01-24 10:32:32 -08:00
setfacl -n -m u:${ USER } :r /var/log/journal/*/system.journal
2016-12-29 12:01:59 -08:00
2020-06-15 17:12:37 +02:00
# Give user access to nginx logs (uses adm group)
usermod -a -G adm ${ USER }
2017-01-23 10:14:18 +01:00
echo "==> Setting up unbound"
# DO uses Google nameservers by default. This causes RBL queries to fail (host 2.0.0.127.zen.spamhaus.org)
# We do not use dnsmasq because it is not a recursive resolver and defaults to the value in the interfaces file (which is Google DNS!)
# We listen on 0.0.0.0 because there is no way control ordering of docker (which creates the 172.18.0.0/16) and unbound
2018-12-21 11:40:45 -08:00
# If IP6 is not enabled, dns queries seem to fail on some hosts. -s returns false if file missing or 0 size
2018-12-22 19:48:14 -08:00
ip6 = $( [ [ -s /proc/net/if_inet6 ] ] && echo "yes" || echo "no" )
2019-11-13 14:48:56 -08:00
cp -f " ${ script_dir } /start/unbound.conf " /etc/unbound/unbound.conf.d/cloudron-network.conf
2017-09-03 17:48:25 -07:00
# update the root anchor after a out-of-disk-space situation (see #269)
unbound-anchor -a /var/lib/unbound/root.key
2017-01-23 10:14:18 +01:00
2016-12-29 12:01:59 -08:00
echo "==> Adding systemd services"
cp -r " ${ script_dir } /start/systemd/. " /etc/systemd/system/
2020-08-01 20:00:20 -07:00
systemctl disable cloudron.target || true
rm -f /etc/systemd/system/cloudron.target
2019-01-17 09:20:31 -08:00
[ [ " ${ ubuntu_version } " = = "16.04" ] ] && sed -e 's/MemoryMax/MemoryLimit/g' -i /etc/systemd/system/box.service
2016-12-29 12:01:59 -08:00
systemctl daemon-reload
2020-11-18 11:43:28 -08:00
systemctl enable --now cloudron-syslog
2020-08-01 20:00:20 -07:00
systemctl enable box
2017-03-29 02:18:38 -07:00
systemctl enable cloudron-firewall
# update firewall rules
systemctl restart cloudron-firewall
2016-12-29 12:01:59 -08:00
# For logrotate
2016-12-29 14:21:08 -08:00
systemctl enable --now cron
2016-12-29 12:01:59 -08:00
2020-11-22 23:51:21 -08:00
# DNS. resolvconf package will magically update resolv.conf depending on which DNS server gets activated. We have to trick resolvconf
# into putting the systemd-resolved file and then disable it. Ideally, we want to even uninstall the package but currently that will
# display a blocking message - "The removal of the resolvconf package may have resulted in some information about name servers becoming unavailable."
if [ [ " ${ ubuntu_version } " = = "16.04" ] ] ; then
systemctl restart unbound # systemd-resolved was only enabled in 16.10 and resolvconf is the default
else
systemctl stop unbound # this removes unbound's 127.0.0.1 resolv.conf entry. for update case, this also frees up loopback port 53
systemctl enable --now systemd-resolved # resolved can now use loopback 53. resolv.conf is now updated by resolvconf
systemctl disable --now resolvconf || true # don't let resolvconf update resolv.conf again. on ubuntu 20, there is no resolvconf
systemctl restart unbound # start it back with latest configuration on port 533
rm -f /etc/resolv.conf && ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf # this still points to resolvconf's resolv.conf and is required for reboots
fi
2016-12-29 14:21:08 -08:00
2018-06-06 11:37:00 +02:00
# ensure cloudron-syslog runs
systemctl restart cloudron-syslog
2016-12-29 14:21:08 -08:00
echo "==> Configuring sudoers"
2017-01-24 10:32:32 -08:00
rm -f /etc/sudoers.d/${ USER }
cp " ${ script_dir } /start/sudoers " /etc/sudoers.d/${ USER }
2016-12-29 14:21:08 -08:00
echo "==> Configuring collectd"
2020-02-18 20:34:13 -08:00
rm -rf /etc/collectd /var/log/collectd.log
2017-03-29 15:51:53 +02:00
ln -sfF " ${ PLATFORM_DATA_DIR } /collectd " /etc/collectd
2017-08-10 19:41:55 -07:00
cp " ${ script_dir } /start/collectd/collectd.conf " " ${ PLATFORM_DATA_DIR } /collectd/collectd.conf "
2020-09-15 23:19:04 -07:00
if [ [ " ${ ubuntu_version } " = = "20.04" ] ] ; then
# https://bugs.launchpad.net/ubuntu/+source/collectd/+bug/1872281
if ! grep -q LD_PRELOAD /etc/default/collectd; then
echo -e "\nLD_PRELOAD=/usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.so" >> /etc/default/collectd
fi
fi
2016-12-29 14:21:08 -08:00
systemctl restart collectd
2016-12-29 12:01:59 -08:00
2017-08-11 22:05:31 +02:00
echo "==> Configuring logrotate"
if ! grep -q " ^include ${ PLATFORM_DATA_DIR } /logrotate.d " /etc/logrotate.conf; then
echo -e " \ninclude ${ PLATFORM_DATA_DIR } /logrotate.d\n " >> /etc/logrotate.conf
fi
2019-07-30 14:47:33 -07:00
rm -f " ${ PLATFORM_DATA_DIR } /logrotate.d/ " *
2019-03-01 14:40:28 -08:00
cp " ${ script_dir } /start/logrotate/ " * " ${ PLATFORM_DATA_DIR } /logrotate.d/ "
2019-03-18 22:05:35 -07:00
# logrotate files have to be owned by root, this is here to fixup existing installations where we were resetting the owner to yellowtent
2019-03-01 14:40:28 -08:00
chown root:root " ${ PLATFORM_DATA_DIR } /logrotate.d/ "
2017-08-11 22:05:31 +02:00
2017-08-10 12:10:37 -07:00
echo "==> Adding motd message for admins"
cp " ${ script_dir } /start/cloudron-motd " /etc/update-motd.d/92-cloudron
2016-12-29 14:21:08 -08:00
echo "==> Configuring nginx"
2016-12-29 12:01:59 -08:00
# link nginx config to system config
unlink /etc/nginx 2>/dev/null || rm -rf /etc/nginx
2017-03-29 15:51:53 +02:00
ln -s " ${ PLATFORM_DATA_DIR } /nginx " /etc/nginx
mkdir -p " ${ PLATFORM_DATA_DIR } /nginx/applications "
mkdir -p " ${ PLATFORM_DATA_DIR } /nginx/cert "
cp " ${ script_dir } /start/nginx/nginx.conf " " ${ PLATFORM_DATA_DIR } /nginx/nginx.conf "
cp " ${ script_dir } /start/nginx/mime.types " " ${ PLATFORM_DATA_DIR } /nginx/mime.types "
2017-03-13 13:52:16 -07:00
if ! grep -q "^Restart=" /etc/systemd/system/multi-user.target.wants/nginx.service; then
2017-01-25 12:04:02 -08:00
# default nginx service file does not restart on crash
echo -e "\n[Service]\nRestart=always\n" >> /etc/systemd/system/multi-user.target.wants/nginx.service
fi
2020-05-25 15:22:01 -07:00
# worker_rlimit_nofile in nginx config can be max this number
mkdir -p /etc/systemd/system/nginx.service.d
if ! grep -q "^LimitNOFILE=" /etc/systemd/system/nginx.service.d/cloudron.conf; then
echo -e "[Service]\nLimitNOFILE=16384\n" > /etc/systemd/system/nginx.service.d/cloudron.conf
fi
systemctl daemon-reload
2017-01-25 12:04:02 -08:00
systemctl start nginx
2016-12-29 12:01:59 -08:00
2015-08-13 15:16:01 -07:00
# restart mysql to make sure it has latest config
2017-02-07 22:45:54 -08:00
if [ [ ! -f /etc/mysql/mysql.cnf ] ] || ! diff -q " ${ script_dir } /start/mysql.cnf " /etc/mysql/mysql.cnf >/dev/null; then
# wait for all running mysql jobs
cp " ${ script_dir } /start/mysql.cnf " /etc/mysql/mysql.cnf
while true; do
if ! systemctl list-jobs | grep mysql; then break; fi
echo "Waiting for mysql jobs..."
sleep 1
done
2017-10-30 16:14:20 -07:00
while true; do
if systemctl restart mysql; then break; fi
echo "Restarting MySql again after sometime since this fails randomly"
sleep 1
done
2017-02-07 22:45:54 -08:00
else
systemctl start mysql
fi
2015-08-13 15:16:01 -07:00
2015-07-20 00:09:47 -07:00
readonly mysql_root_password = "password"
mysqladmin -u root -ppassword password password # reset default root password
2020-09-15 23:25:40 -07:00
if [ [ " ${ ubuntu_version } " = = "20.04" ] ] ; then
# mysql 8 added a new caching_sha2_password scheme which mysqljs does not support
mysql -u root -p${ mysql_root_password } -e " ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY ' ${ mysql_root_password } '; "
fi
2015-07-20 00:09:47 -07:00
mysql -u root -p${ mysql_root_password } -e 'CREATE DATABASE IF NOT EXISTS box'
2020-05-17 21:50:50 -07:00
# set HOME explicity, because it's not set when the installer calls it. this is done because
# paths.js uses this env var and some of the migrate code requires box code
2018-01-31 11:56:51 +01:00
echo "==> Migrating data"
2019-09-25 10:17:02 -07:00
cd " ${ BOX_SRC_DIR } "
2020-05-17 21:50:50 -07:00
if ! HOME = ${ HOME_DIR } BOX_ENV = cloudron DATABASE_URL = mysql://root:${ mysql_root_password } @127.0.0.1/box " ${ BOX_SRC_DIR } /node_modules/.bin/db-migrate " up; then
2019-09-25 10:17:02 -07:00
echo "DB migration failed"
exit 1
fi
2015-07-20 00:09:47 -07:00
2019-07-26 14:55:36 -07:00
rm -f /etc/cloudron/cloudron.conf
2017-10-02 00:35:24 -07:00
if [ [ ! -f " ${ BOX_DATA_DIR } /dhparams.pem " ] ] ; then
echo "==> Generating dhparams (takes forever)"
openssl dhparam -out " ${ BOX_DATA_DIR } /dhparams.pem " 2048
cp " ${ BOX_DATA_DIR } /dhparams.pem " " ${ PLATFORM_DATA_DIR } /addons/mail/dhparams.pem "
else
cp " ${ BOX_DATA_DIR } /dhparams.pem " " ${ PLATFORM_DATA_DIR } /addons/mail/dhparams.pem "
fi
2019-03-27 13:50:56 -07:00
# old installations used to create appdata/<app>/redis which is now part of old backups and prevents restore
echo "==> Cleaning up stale redis directories"
find " ${ APPS_DATA_DIR } " -maxdepth 2 -type d -name redis -exec rm -rf { } +
2020-05-13 19:23:04 -07:00
echo "==> Cleaning up old logs"
rm -f /home/yellowtent/platformdata/logs/*/*.log.* || true
2016-12-29 14:35:48 -08:00
echo "==> Changing ownership"
2018-11-07 15:21:12 -08:00
# be careful of what is chown'ed here. subdirs like mysql,redis etc are owned by the containers and will stop working if perms change
2018-12-14 15:40:25 -08:00
chown -R " ${ USER } " /etc/cloudron
2018-11-07 15:21:12 -08:00
chown " ${ USER } : ${ USER } " -R " ${ PLATFORM_DATA_DIR } /nginx " " ${ PLATFORM_DATA_DIR } /collectd " " ${ PLATFORM_DATA_DIR } /addons " " ${ PLATFORM_DATA_DIR } /acme " " ${ PLATFORM_DATA_DIR } /backup " " ${ PLATFORM_DATA_DIR } /logs " " ${ PLATFORM_DATA_DIR } /update "
2017-03-29 15:51:53 +02:00
chown " ${ USER } : ${ USER } " " ${ PLATFORM_DATA_DIR } /INFRA_VERSION " 2>/dev/null || true
chown " ${ USER } : ${ USER } " " ${ PLATFORM_DATA_DIR } "
2018-09-13 13:55:49 -07:00
chown " ${ USER } : ${ USER } " " ${ APPS_DATA_DIR } "
2016-12-29 14:35:48 -08:00
2017-10-16 21:41:48 -07:00
# do not chown the boxdata/mail directory; dovecot gets upset
chown " ${ USER } : ${ USER } " " ${ BOX_DATA_DIR } "
find " ${ BOX_DATA_DIR } " -mindepth 1 -maxdepth 1 -not -path " ${ BOX_DATA_DIR } /mail " -exec chown -R " ${ USER } : ${ USER } " { } \;
2017-11-22 21:53:31 -08:00
chown " ${ USER } : ${ USER } " " ${ BOX_DATA_DIR } /mail "
2017-10-16 21:41:48 -07:00
chown " ${ USER } : ${ USER } " -R " ${ BOX_DATA_DIR } /mail/dkim " # this is owned by box currently since it generates the keys
2018-01-31 11:56:51 +01:00
echo "==> Starting Cloudron"
2020-08-01 20:00:20 -07:00
systemctl start box
2015-07-20 00:09:47 -07:00
2015-09-07 11:18:44 -07:00
sleep 2 # give systemd sometime to start the processes
2015-07-20 00:09:47 -07:00
2018-01-31 11:56:51 +01:00
echo "==> Almost done"