rpcbind is required for NFSv2 and v3 . It seems this gets installed by nfs-common. It was never used by us since the firewall blocks port 111 anyways. NFSv3 needs 2049 for NFS, 111 for portmap, 635 for mountd, 4045 for NLM, 4046 for NSM, 4049 for rquota ... NFSv4 works better because there's just a single target port, plus the "heartbeat" of lease renewal would keep the TCP/IP session alive. https://serverfault.com/questions/949127/nfs-client-firewall-settings-and-rpcbind https://docs.redhat.com/en/documentation/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/s2-nfs-methodology-portmap.html#s2-nfs-methodology-portmap https://community.netapp.com/t5/Tech-ONTAP-Blogs/NFSv3-and-NFSv4-What-s-the-difference/ba-p/441316
261 lines
11 KiB
Bash
Executable File
261 lines
11 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)
|
|
|
|
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}"
|
|
mkdir -p "${APPS_DATA_DIR}"
|
|
mkdir -p "${MAIL_DATA_DIR}"
|
|
|
|
# keep these in sync with paths.js
|
|
log "Ensuring directories"
|
|
|
|
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}/redis"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/tls"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/addons/mail/banner" \
|
|
"${PLATFORM_DATA_DIR}/addons/mail/dkim"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/collectd"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/logrotate.d"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/acme"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/backup"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/logs/backup" \
|
|
"${PLATFORM_DATA_DIR}/logs/updater" \
|
|
"${PLATFORM_DATA_DIR}/logs/tasks" \
|
|
"${PLATFORM_DATA_DIR}/logs/collectd"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/update"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/sftp/ssh" # sftp keys
|
|
mkdir -p "${PLATFORM_DATA_DIR}/firewall"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/sshfs"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/cifs"
|
|
mkdir -p "${PLATFORM_DATA_DIR}/oidc"
|
|
|
|
# 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.conf" /etc/unbound/unbound.conf.d/cloudron-network.conf
|
|
rm -f /etc/unbound/unbound.conf.d/remote-control.conf # on ubuntu 24
|
|
# update the root anchor after a out-of-disk-space situation (see #269)
|
|
# it returns 1 even on fail, it's not clear - https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound-anchor.html#exit-code
|
|
unbound-anchor -v -a /var/lib/unbound/root.key || log "unbound-anchor failed, but it probably worked"
|
|
|
|
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
|
|
|
|
log "Configuring collectd"
|
|
rm -rf /etc/collectd /var/log/collectd.log "${PLATFORM_DATA_DIR}/collectd/collectd.conf.d"
|
|
ln -sfF "${PLATFORM_DATA_DIR}/collectd" /etc/collectd
|
|
cp "${script_dir}/start/collectd/collectd.conf" "${PLATFORM_DATA_DIR}/collectd/collectd.conf"
|
|
systemctl restart collectd
|
|
|
|
log "Configuring sysctl"
|
|
# If privacy extensions are not disabled on server, this breaks IPv6 detection
|
|
# https://bugs.launchpad.net/ubuntu/+source/procps/+bug/1068756
|
|
if [[ ! -f /etc/sysctl.d/99-cloudimg-ipv6.conf ]]; then
|
|
echo "==> Disable temporary address (IPv6)"
|
|
echo -e "# See https://bugs.launchpad.net/ubuntu/+source/procps/+bug/1068756\nnet.ipv6.conf.all.use_tempaddr = 0\nnet.ipv6.conf.default.use_tempaddr = 0\n\n" > /etc/sysctl.d/99-cloudimg-ipv6.conf
|
|
sysctl -p
|
|
fi
|
|
|
|
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
|
|
|
|
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" "${PLATFORM_DATA_DIR}/collectd" "${PLATFORM_DATA_DIR}/addons" "${PLATFORM_DATA_DIR}/acme" "${PLATFORM_DATA_DIR}/backup" "${PLATFORM_DATA_DIR}/logs" "${PLATFORM_DATA_DIR}/update" "${PLATFORM_DATA_DIR}/sftp" "${PLATFORM_DATA_DIR}/firewall" "${PLATFORM_DATA_DIR}/sshfs" "${PLATFORM_DATA_DIR}/cifs" "${PLATFORM_DATA_DIR}/tls" "${PLATFORM_DATA_DIR}/oidc"
|
|
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"
|