#!/bin/bash set -eu -o pipefail # scripts requires root if [[ ${EUID} -ne 0 ]]; then echo "This script should be run as root. Run with sudo" exit 1 fi readonly RED='\033[31m' readonly GREEN='\033[32m' readonly YELLOW='\033[33m' readonly DONE='\033[m' readonly PASTEBIN="https://paste.cloudron.io" readonly LINE="\n========================================================\n" readonly HELP_MESSAGE=" Cloudron Support and Diagnostics Tool Options: --disable-dnssec Disable DNSSEC --enable-remote-access Enable SSH Remote Access for the Cloudron support team --send-diagnostics Collects server diagnostics and uploads it to ${PASTEBIN} --troubleshoot Dashboard down? Run tests to identify the potential problem --owner-login Login as owner --use-external-dns Forwards all DNS requests to Google (8.8.8.8) and Cloudflare (1.1.1.1) DNS servers --help Show this message " function success() { echo -e "[${GREEN}OK${DONE}]\t${1}" } function info() { echo -e "\t${1}" } function warn() { echo -e "[${YELLOW}WARN${DONE}]\t${1}" } function fail() { echo -e "[${RED}FAIL${DONE}]\t${1}" } function enable_remote_access() { local -r cloudron_support_public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWS+930b8QdzbchGljt3KSljH9wRhYvht8srrtQHdzg support@cloudron.io" local -r ssh_user="cloudron-support" local -r keys_file="/home/cloudron-support/.ssh/authorized_keys" echo -n "Enabling Remote Access for the Cloudron support team..." mkdir -p $(dirname "${keys_file}") # .ssh does not exist sometimes touch "${keys_file}" # required for concat to work if ! grep -q "${cloudron_support_public_key}" "${keys_file}"; then echo -e "\n${cloudron_support_public_key}" >> "${keys_file}" chmod 600 "${keys_file}" chown "${ssh_user}" "${keys_file}" fi echo "Done" } function check_host_mysql() { if ! systemctl is-active -q mysql; then info "MySQL is down. Trying to restart MySQL ..." systemctl restart mysql if ! systemctl is-active -q mysql; then fail "MySQL is still down, please investigate the error by inspecting /var/log/mysql/error.log" exit 1 fi fi success "MySQL is running" } function check_box() { if ! systemctl is-active -q box; then info "box is down. re-running migration script and restarting it ..." /home/yellowtent/box/setup/start.sh systemctl stop box # a restart sometimes doesn't restart, no idea systemctl start box if ! systemctl is-active -q box; then fail "box is still down, please investigate the error by inspecting /home/yellowtent/platformdata/logs/box.log" exit 1 fi fi success "box is running" } function owner_login() { check_host_mysql local -r owner_username=$(mysql -NB -uroot -ppassword -e "SELECT username FROM box.users WHERE role='owner' AND username IS NOT NULL AND active=1 ORDER BY creationTime LIMIT 1" 2>/dev/null) local -r owner_password=$(pwgen -1s 12) local -r dashboard_domain=$(mysql -NB -uroot -ppassword -e "SELECT value FROM box.settings WHERE name='dashboard_domain'" 2>/dev/null) mysql -NB -uroot -ppassword -e "INSERT INTO box.settings (name, value) VALUES ('ghosts_config', '{\"${owner_username}\":\"${owner_password}\"}') ON DUPLICATE KEY UPDATE name='ghosts_config', value='{\"${owner_username}\":\"${owner_password}\"}'" 2>/dev/null echo "Login at https://my.${dashboard_domain} as ${owner_username} / ${owner_password} . This password may only be used once." } function send_diagnostics() { local -r log="/tmp/cloudron-support.log" echo -n "Generating Cloudron Support stats..." rm -rf $log echo -e $LINE"Linux"$LINE >> $log uname -nar &>> $log echo -e $LINE"Ubuntu"$LINE >> $log lsb_release -a &>> $log echo -e $LINE"Dashboard Domain"$LINE >> $log mysql -NB -uroot -ppassword -e "SELECT value FROM box.settings WHERE name='dashboard_domain'" &>> $log 2>/dev/null || true echo -e $LINE"Docker containers"$LINE >> $log if ! timeout --kill-after 10s 15s docker ps -a &>> $log 2>&1; then echo -e "Docker is not responding" >> $log fi echo -e $LINE"Filesystem stats"$LINE >> $log df -h &>> $log echo -e $LINE"Appsdata stats"$LINE >> $log du -hcsL /home/yellowtent/appsdata/* &>> $log || true echo -e $LINE"Boxdata stats"$LINE >> $log du -hcsL /home/yellowtent/boxdata/* &>> $log echo -e $LINE"Backup stats (possibly misleading)"$LINE >> $log du -hcsL /var/backups/* &>> $log || true echo -e $LINE"System daemon status"$LINE >> $log systemctl status --lines=100 box mysql unbound cloudron-syslog nginx collectd docker &>> $log echo -e $LINE"Box logs"$LINE >> $log tail -n 100 /home/yellowtent/platformdata/logs/box.log &>> $log echo -e $LINE"Interface Info"$LINE >> $log ip addr &>> $log echo -e $LINE"Firewall chains"$LINE >> $log iptables -L &>> $log has_ipv6=$(cat /proc/net/if_inet6 >/dev/null 2>&1 && echo "yes" || echo "no") echo -e "IPv6: ${has_ipv6}" >> $log [[ "${has_ipv6}" == "yes" ]] && ip6tables -L &>> $log echo "Done" echo -n "Uploading information..." paste_key=$(curl -X POST ${PASTEBIN}/documents --silent --data-binary "@$log" | python3 -c "import sys, json; print(json.load(sys.stdin)['key'])") echo "Done" echo -e "\nPlease email the following link to support@cloudron.io : ${PASTEBIN}/${paste_key}" } function check_unbound() { if ! systemctl is-active -q unbound; then info "unbound is down. updating root anchor to see if it fixes it" unbound-anchor -a /var/lib/unbound/root.key systemctl restart unbound if ! systemctl is-active -q unbound; then fail "unbound is still down, please investigate the error using 'journalctl -u unbound'" exit 1 fi fi test_resolve=$(dig cloudron.io @127.0.0.1 +short) if [[ -z "test_resolve" ]]; then fail "DNS is not resolving, maybe try forwarding all DNS requests using the --use-external-dns option" exit 1 fi success "unbound is running" } function check_nginx() { local -r dashboard_domain=$(mysql -NB -uroot -ppassword -e "SELECT value FROM box.settings WHERE name='dashboard_domain'" 2>/dev/null) if ! systemctl is-active -q nginx; then fail "nginx is down. Removing extraneous dashboard domain configs ..." cd /home/yellowtent/platformdata/nginx/applications/dashboard/ && find . ! -name "my.${dashboard_domain}.conf" -type f -exec rm -f {} + systemctl restart nginx if ! systemctl is-active -q nginx; then fail "nginx is still down, please investigate the error by inspecting /var/log/nginx/error.log" exit 1 fi fi success "nginx is running" } function check_docker() { if ! systemctl is-active -q docker; then info "Docker is down. Trying to restart docker ..." systemctl restart docker if ! systemctl is-active -q docker; then fail "Docker is still down, please investigate the error using 'journalctl -u docker'" exit 1 fi fi success "docker is running" } function check_hairpin_nat() { local -r dashboard_domain=$(mysql -NB -uroot -ppassword -e "SELECT value FROM box.settings WHERE name='dashboard_domain'" 2>/dev/null) if ! curl --fail -s https://my.${dashboard_domain} >/dev/null; then fail "Could not reach dashboard domain. Is Hairpin NAT functional?" exit 1 fi success "Hairpin NAT is good" } function check_expired_domain() { local -r dashboard_domain=$(mysql -NB -uroot -ppassword -e "SELECT value FROM box.settings WHERE name='dashboard_domain'" 2>/dev/null) if ! command -v whois &> /dev/null; then info "Domain ${dashboard_domain} expiry check skipped because whois is not installed. Run 'apt install whois' to check" exit 0 fi local -r expdate=$(whois ${dashboard_domain} | egrep -i 'Expiration Date:|Expires on|Expiry Date:' | head -1 | awk '{print $NF}') if [[ -z "${expdate}" ]]; then warn "Domain ${dashboard_domain} expiry check skipped because whois does not have this information" exit 0 fi local -r expdate_secs=$(date -d"$expdate" +%s) local -r curdate_secs="$(date +%s)" if (( curdate_secs > expdate_secs )); then fail "Domain ${dashboard_domain} appears to be expired" exit 1 fi success "Domain ${dashboard_domain} is valid and has not expired" } function use_external_dns() { local -r conf_file="/etc/unbound/unbound.conf.d/forward-everything.conf" info "To remove the forwarding, please delete $conf_file and 'systemctl restart unbound'" cat > $conf_file < $conf_file <