Files
cloudron-box/setup/start.sh
T

262 lines
10 KiB
Bash
Raw Normal View History

#!/bin/bash
set -eu -o pipefail
2016-12-29 14:21:08 -08:00
echo "==> Cloudron Start"
readonly USER="yellowtent"
2017-01-24 10:09:05 -08:00
readonly HOME_DIR="/home/${USER}"
readonly BOX_SRC_DIR="${HOME_DIR}/box"
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
readonly CONFIG_DIR="${HOME_DIR}/configs"
readonly curl="curl --fail --connect-timeout 20 --retry 10 --retry-delay 2 --max-time 2400"
2016-12-29 14:21:08 -08:00
readonly script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${script_dir}/argparser.sh" "$@" # this injects the arg_* variables used below
2018-01-31 11:56:51 +01:00
echo "==> Configuring host"
2016-12-29 12:01:59 -08:00
sed -e 's/^#NTP=/NTP=0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org 2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org/' -i /etc/systemd/timesyncd.conf
timedatectl set-ntp 1
timedatectl set-timezone UTC
2018-01-30 21:10:04 -08:00
hostnamectl set-hostname "${arg_admin_fqdn}"
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
2017-06-30 16:50:31 -05:00
# preserve the existing storage driver (user might be using overlay2)
storage_driver=$(docker info | grep "Storage Driver" | sed 's/.*: //')
2017-08-10 12:27:21 -07:00
[[ -n "${storage_driver}" ]] || storage_driver="overlay2" # if the above command fails
2017-06-30 16:50:31 -05:00
2017-01-10 18:30:09 -08:00
temp_file=$(mktemp)
2017-01-30 12:25:58 -08:00
# create systemd drop-in. some apps do not work with aufs
2017-06-30 16:50:31 -05:00
echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=${storage_driver}" > "${temp_file}"
2017-01-30 12:25:58 -08:00
2016-12-29 12:01:59 -08:00
systemctl enable docker
2017-01-30 12:25:58 -08:00
# restart docker if options changed
2017-01-31 00:00:16 -08:00
if [[ ! -f /etc/systemd/system/docker.service.d/cloudron.conf ]] || ! diff -q /etc/systemd/system/docker.service.d/cloudron.conf "${temp_file}" >/dev/null; then
mkdir -p /etc/systemd/system/docker.service.d
2017-01-30 12:25:58 -08:00
mv "${temp_file}" /etc/systemd/system/docker.service.d/cloudron.conf
2017-01-11 15:40:13 -08:00
systemctl daemon-reload
2017-01-10 18:30:09 -08:00
systemctl restart docker
fi
2017-01-12 17:42:53 -08:00
docker network create --subnet=172.18.0.0/16 cloudron || true
2016-12-29 12:01:59 -08:00
# caas has ssh on port 202 and we disable password login
if [[ "${arg_provider}" == "caas" ]]; then
# https://stackoverflow.com/questions/4348166/using-with-sed on why ? must be escaped
sed -e 's/^#\?PermitRootLogin .*/PermitRootLogin without-password/g' \
-e 's/^#\?PermitEmptyPasswords .*/PermitEmptyPasswords no/g' \
-e 's/^#\?PasswordAuthentication .*/PasswordAuthentication no/g' \
-e 's/^#\?Port .*/Port 202/g' \
-i /etc/ssh/sshd_config
# required so we can connect to this machine since port 22 is blocked by iptables by now
systemctl reload sshd
fi
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
mkdir -p "${PLATFORM_DATA_DIR}/graphite"
mkdir -p "${PLATFORM_DATA_DIR}/mysql"
mkdir -p "${PLATFORM_DATA_DIR}/postgresql"
mkdir -p "${PLATFORM_DATA_DIR}/mongodb"
mkdir -p "${PLATFORM_DATA_DIR}/addons/mail"
mkdir -p "${PLATFORM_DATA_DIR}/collectd/collectd.conf.d"
mkdir -p "${PLATFORM_DATA_DIR}/logrotate.d"
mkdir -p "${PLATFORM_DATA_DIR}/acme"
2017-09-26 16:31:08 -07:00
mkdir -p "${PLATFORM_DATA_DIR}/backup"
2018-06-15 09:17:10 -07:00
mkdir -p "${PLATFORM_DATA_DIR}/logs/backup"
2018-08-01 15:38:40 -07:00
mkdir -p "${PLATFORM_DATA_DIR}/update"
2017-01-24 10:09:05 -08:00
mkdir -p "${BOX_DATA_DIR}/appicons"
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"
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
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
echo "==> Creating config directory"
mkdir -p "${CONFIG_DIR}"
2016-12-29 12:01:59 -08:00
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
2017-09-18 11:28:35 -07:00
# If IP6 is not enabled, dns queries seem to fail on some hosts
2017-09-19 10:28:57 -07:00
echo -e "server:\n\tinterface: 0.0.0.0\n\tdo-ip6: yes\n\taccess-control: 127.0.0.1 allow\n\taccess-control: 172.18.0.1/16 allow\n\tcache-max-negative-ttl: 30\n\tcache-max-ttl: 300\n\t#logfile: /var/log/unbound.log\n\t#verbosity: 10" > /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/
systemctl daemon-reload
2017-01-23 10:14:18 +01:00
systemctl enable unbound
2018-06-06 11:37:00 +02:00
systemctl enable cloudron-syslog
2016-12-29 12:01:59 -08:00
systemctl enable cloudron.target
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
2017-01-23 10:14:18 +01:00
# ensure unbound runs
2017-01-12 17:42:53 -08:00
systemctl restart unbound
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"
rm -rf /etc/collectd
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"
2016-12-29 14:21:08 -08:00
systemctl restart collectd
2016-12-29 12:01:59 -08: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
2018-06-06 17:36:48 +02:00
cp "${script_dir}/start/app-logrotate" "${PLATFORM_DATA_DIR}/logrotate.d/app-logrotate"
2018-06-06 18:39:52 +02:00
chown root:root "${PLATFORM_DATA_DIR}/logrotate.d/app-logrotate"
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
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
systemctl daemon-reload
fi
# remove this migration after 1.10
2018-02-01 21:51:30 -08:00
[[ -f /etc/nginx/cert/host.cert ]] && cp /etc/nginx/cert/host.cert "/etc/nginx/cert/${arg_admin_domain}.host.cert"
2018-02-01 22:24:17 -08:00
[[ -f /etc/nginx/cert/host.key ]] && cp /etc/nginx/cert/host.key "/etc/nginx/cert/${arg_admin_domain}.host.key"
2017-01-25 12:04:02 -08:00
systemctl start nginx
2016-12-29 12:01:59 -08:00
# bookkeep the version as part of data
2017-04-13 11:34:55 -07:00
echo "{ \"version\": \"${arg_version}\", \"apiServerOrigin\": \"${arg_api_server_origin}\" }" > "${BOX_DATA_DIR}/version"
# 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
readonly mysql_root_password="password"
mysqladmin -u root -ppassword password password # reset default root password
mysql -u root -p${mysql_root_password} -e 'CREATE DATABASE IF NOT EXISTS box'
2018-01-31 11:56:51 +01:00
echo "==> Migrating data"
sudo -u "${USER}" -H bash <<EOF
set -eu
cd "${BOX_SRC_DIR}"
2017-08-31 10:55:08 -07:00
BOX_ENV=cloudron DATABASE_URL=mysql://root:${mysql_root_password}@127.0.0.1/box "${BOX_SRC_DIR}/node_modules/.bin/db-migrate" up
EOF
2016-12-29 14:35:48 -08:00
echo "==> Creating cloudron.conf"
cat > "${CONFIG_DIR}/cloudron.conf" <<CONF_END
{
"version": "${arg_version}",
"apiServerOrigin": "${arg_api_server_origin}",
"webServerOrigin": "${arg_web_server_origin}",
2018-01-28 14:19:28 -08:00
"adminDomain": "${arg_admin_domain}",
"adminFqdn": "${arg_admin_fqdn}",
2017-10-25 20:35:24 -07:00
"adminLocation": "${arg_admin_location}",
2015-12-29 12:25:22 +01:00
"provider": "${arg_provider}",
2018-08-22 21:26:05 +02:00
"isDemo": ${arg_is_demo},
"edition": "${arg_edition}"
}
CONF_END
2018-03-15 14:01:20 -07:00
echo "==> Creating config.json for dashboard"
cat > "${BOX_SRC_DIR}/dashboard/dist/config.json" <<CONF_END
{
"webServerOrigin": "${arg_web_server_origin}"
}
CONF_END
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
2016-12-29 14:35:48 -08:00
echo "==> Changing ownership"
chown "${USER}:${USER}" -R "${CONFIG_DIR}"
2018-08-01 15:38:40 -07: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"
chown "${USER}:${USER}" "${PLATFORM_DATA_DIR}/INFRA_VERSION" 2>/dev/null || true
chown "${USER}:${USER}" "${PLATFORM_DATA_DIR}"
2016-12-29 14:35:48 -08:00
# logrotate files have to be owned by root, this is here to fixup existing installations where we were resetting the owner to yellowtent
chown root:root -R "${PLATFORM_DATA_DIR}/logrotate.d"
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"
2015-09-07 11:18:44 -07:00
systemctl start cloudron.target
2015-09-07 11:18:44 -07:00
sleep 2 # give systemd sometime to start the processes
2018-01-31 11:56:51 +01:00
echo "==> Almost done"