collectd (with the python plugin) seems semi-abandoned. replace with our own. we have more control over how to collect things instead of relying on random plugins.
241 lines
9.8 KiB
Bash
Executable File
241 lines
9.8 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -eu -o pipefail
|
|
|
|
# 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.
|
|
|
|
function log() {
|
|
echo -e "$(date +'%Y-%m-%dT%H:%M:%S')" "==> start: $1"
|
|
}
|
|
|
|
log "Cloudron Start"
|
|
|
|
readonly USER="yellowtent"
|
|
readonly HOME_DIR="/home/${USER}"
|
|
readonly BOX_SRC_DIR="${HOME_DIR}/box"
|
|
readonly PLATFORM_DATA_DIR="${HOME_DIR}/platformdata"
|
|
readonly APPS_DATA_DIR="${HOME_DIR}/appsdata"
|
|
readonly BOX_DATA_DIR="${HOME_DIR}/boxdata/box"
|
|
readonly MAIL_DATA_DIR="${HOME_DIR}/boxdata/mail"
|
|
|
|
readonly script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly ubuntu_version=$(lsb_release -rs)
|
|
|
|
vergte() {
|
|
greater_version=$(echo -e "$1\n$2" | sort -rV | head -n1)
|
|
[[ "$1" == "${greater_version}" ]] && return 0 || return 1
|
|
}
|
|
|
|
cp -f "${script_dir}/../scripts/cloudron-support" /usr/bin/cloudron-support
|
|
cp -f "${script_dir}/../scripts/cloudron-translation-update" /usr/bin/cloudron-translation-update
|
|
rm -f /usr/bin/cloudron-logs # legacy script
|
|
|
|
# this needs to match the cloudron/base:4.2.0 gid
|
|
if ! getent group media; then
|
|
addgroup --gid 500 --system media
|
|
fi
|
|
|
|
log "Configuring docker"
|
|
cp "${script_dir}/start/docker-cloudron-app.apparmor" /etc/apparmor.d/docker-cloudron-app
|
|
systemctl enable apparmor
|
|
systemctl restart apparmor
|
|
|
|
usermod ${USER} -a -G docker
|
|
|
|
if ! grep -q ip6tables /etc/systemd/system/docker.service.d/cloudron.conf; then
|
|
log "Adding ip6tables flag to docker" # https://github.com/moby/moby/pull/41622
|
|
echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2 --experimental --ip6tables --userland-proxy=false" > /etc/systemd/system/docker.service.d/cloudron.conf
|
|
systemctl daemon-reload
|
|
systemctl restart docker
|
|
fi
|
|
|
|
if ! grep -q userland-proxy /etc/systemd/system/docker.service.d/cloudron.conf; then
|
|
log "Adding userland-proxy=false to docker" # https://github.com/moby/moby/pull/41622
|
|
echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H fd:// --log-driver=journald --exec-opt native.cgroupdriver=cgroupfs --storage-driver=overlay2 --experimental --ip6tables --userland-proxy=false" > /etc/systemd/system/docker.service.d/cloudron.conf
|
|
systemctl daemon-reload
|
|
systemctl restart docker
|
|
fi
|
|
|
|
mkdir -p "${BOX_DATA_DIR}" "${APPS_DATA_DIR}" "${MAIL_DATA_DIR}"
|
|
|
|
# keep these in sync with paths.js
|
|
log "Ensuring directories"
|
|
|
|
mkdir -p "${PLATFORM_DATA_DIR}/"{graphite,mysql,postgresql,mongodb,redis,tls,logrotate.d,acme,backup,update,firewall,sshfs,cifs,oidc,diskusage}
|
|
mkdir -p "${PLATFORM_DATA_DIR}/addons/mail/"{banner,dkim}
|
|
mkdir -p "${PLATFORM_DATA_DIR}/logs/"{backup,updater,tasks}
|
|
mkdir -p "${PLATFORM_DATA_DIR}/sftp/ssh" # sftp keys
|
|
|
|
# ensure backups folder exists and is writeable
|
|
mkdir -p /var/backups
|
|
chmod 777 /var/backups
|
|
|
|
log "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
|
|
|
|
usermod -a -G systemd-journal ${USER} # Give user access to system logs
|
|
if [[ ! -d /var/log/journal ]]; then # in some images, this directory is not created making system log to /run/systemd instead
|
|
mkdir -p /var/log/journal
|
|
chown root:systemd-journal /var/log/journal
|
|
chmod g+s /var/log/journal # sticky bit for group propagation
|
|
fi
|
|
systemctl daemon-reload
|
|
systemctl restart systemd-journald
|
|
|
|
# Give user access to nginx logs (uses adm group)
|
|
usermod -a -G adm ${USER}
|
|
|
|
log "Setting up unbound"
|
|
cp -f "${script_dir}/start/unbound/unbound.conf" /etc/unbound/unbound.conf.d/cloudron-network.conf
|
|
unbound_version=$(unbound -V | sed -n 's/^Version \([0-9.]*\)/\1/p')
|
|
if vergte "${unbound_version}" "1.19.2"; then
|
|
cp "${script_dir}/start/unbound/prefer-ip4.conf" /etc/unbound/unbound.conf.d/cloudron-prefer-ip4.conf
|
|
fi
|
|
rm -f /etc/unbound/unbound.conf.d/remote-control.conf # on ubuntu 24
|
|
|
|
log "Adding systemd services"
|
|
cp -r "${script_dir}/start/systemd/." /etc/systemd/system/
|
|
systemctl daemon-reload
|
|
systemctl enable unbound
|
|
systemctl enable box
|
|
systemctl enable cloudron-firewall
|
|
systemctl enable --now cloudron-disable-thp
|
|
|
|
# update firewall rules. this must be done after docker created it's rules
|
|
systemctl restart cloudron-firewall
|
|
|
|
# For logrotate
|
|
systemctl enable --now cron
|
|
|
|
# ensure unbound runs
|
|
systemctl restart unbound
|
|
|
|
# nfs-common depends on rpcbind which is only needed for NFS v2/v3 . can be removed after 8.0.1 . systemctl list-sockets | grep 111
|
|
systemctl disable rpcbind.socket rpcbind.service || true
|
|
systemctl stop rpcbind.socket rpcbind.service || true
|
|
|
|
log "Configuring sudoers"
|
|
rm -f /etc/sudoers.d/${USER} /etc/sudoers.d/cloudron
|
|
cp "${script_dir}/start/sudoers" /etc/sudoers.d/cloudron
|
|
|
|
# can be removed after 9.0
|
|
log "Unconfiguring collectd"
|
|
rm -rf "${PLATFORM_DATA_DIR}/collectd"
|
|
systemctl disable collectd || true
|
|
systemctl stop collectd || true
|
|
|
|
log "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
|
|
cp "${script_dir}/start/logrotate/"* "${PLATFORM_DATA_DIR}/logrotate.d/"
|
|
|
|
# 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 "${PLATFORM_DATA_DIR}/logrotate.d/"
|
|
|
|
log "Adding motd message for admins"
|
|
cp "${script_dir}/start/cloudron-motd" /etc/update-motd.d/92-cloudron
|
|
|
|
log "Configuring nginx"
|
|
# 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/dashboard"
|
|
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"
|
|
touch "${PLATFORM_DATA_DIR}/nginx/trusted.ips"
|
|
if ! grep -q "^Restart=" /etc/systemd/system/multi-user.target.wants/nginx.service; then
|
|
# 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
|
|
|
|
# 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 2>/dev/null; then
|
|
echo -e "[Service]\nLimitNOFILE=16384\n" > /etc/systemd/system/nginx.service.d/cloudron.conf
|
|
fi
|
|
|
|
systemctl daemon-reload
|
|
systemctl start nginx
|
|
|
|
# restart mysql to make sure it has latest config
|
|
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
|
|
log "Waiting for mysql jobs..."
|
|
sleep 1
|
|
done
|
|
log "Stopping mysql"
|
|
systemctl stop mysql
|
|
while mysqladmin ping 2>/dev/null; do
|
|
log "Waiting for mysql to stop..."
|
|
sleep 1
|
|
done
|
|
fi
|
|
|
|
# the start/stop of mysql is separate to make sure it got reloaded with latest config and it's up and running before we start the new box code
|
|
# when using 'system restart mysql', it seems to restart much later and the box code loses connection during platform startup (dangerous!)
|
|
log "Starting mysql"
|
|
systemctl start mysql
|
|
while ! mysqladmin ping 2>/dev/null; do
|
|
log "Waiting for mysql to start..."
|
|
sleep 1
|
|
done
|
|
|
|
readonly mysql_root_password="password"
|
|
mysqladmin -u root -ppassword password password # reset default root password
|
|
readonly mysqlVersion=$(mysql -NB -u root -p${mysql_root_password} -e 'SELECT VERSION()' 2>/dev/null)
|
|
if [[ "${mysqlVersion}" == "8.0."* ]]; 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
|
|
mysql -u root -p${mysql_root_password} -e 'CREATE DATABASE IF NOT EXISTS box'
|
|
|
|
# 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
|
|
log "Migrating data"
|
|
cd "${BOX_SRC_DIR}"
|
|
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
|
|
log "DB migration failed"
|
|
exit 1
|
|
fi
|
|
|
|
# migrate disk usage cache file
|
|
[[ -f "${PLATFORM_DATA_DIR}/diskusage.json" ]] && mv "${PLATFORM_DATA_DIR}/diskusage.json" "${PLATFORM_DATA_DIR}/diskusage/cache.json"
|
|
|
|
log "Changing ownership"
|
|
# note, change ownership after db migrate. this allow db migrate to move files around as root and then we can fix it up here
|
|
# 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
|
|
chown -R "${USER}" /etc/cloudron
|
|
chown "${USER}:${USER}" -R "${PLATFORM_DATA_DIR}/"{nginx,addons,acme,backup,logs,update,sftp,firewall,sshfs,cifs,tls,oidc,diskusage}
|
|
chown "${USER}:${USER}" "${PLATFORM_DATA_DIR}/INFRA_VERSION" 2>/dev/null || true
|
|
chown "${USER}:${USER}" "${PLATFORM_DATA_DIR}"
|
|
chown "${USER}:${USER}" "${APPS_DATA_DIR}"
|
|
|
|
chown "${USER}:${USER}" -R "${BOX_DATA_DIR}"
|
|
# do not chown the boxdata/mail directory entirely; dovecot gets upset
|
|
chown "${USER}:${USER}" "${MAIL_DATA_DIR}"
|
|
|
|
# this require logs dir to have correct permissions
|
|
log "Starting cloudron-syslog"
|
|
systemctl enable cloudron-syslog
|
|
systemctl start cloudron-syslog
|
|
|
|
log "Starting Cloudron"
|
|
systemctl start box
|
|
|
|
sleep 2 # give systemd sometime to start the processes
|
|
|
|
log "Almost done"
|