#!/bin/bash set -euv -o pipefail readonly USER=yellowtent readonly USER_HOME="/home/${USER}" readonly INSTALLER_SOURCE_DIR="${USER_HOME}/installer" readonly INSTALLER_REVISION="$1" readonly SELFHOSTED=$(( $# > 1 ? 1 : 0 )) readonly USER_DATA_FILE="/root/user_data.img" readonly USER_DATA_DIR="/home/yellowtent/data" readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "${SOURCE_DIR}/INFRA_VERSION" ]; then source "${SOURCE_DIR}/INFRA_VERSION" else echo "No INFRA_VERSION found, skip pulling docker images" fi if [ ${SELFHOSTED} == 0 ]; then echo "!! Initializing Ubuntu image for CaaS" else echo "!! Initializing Ubuntu image for Selfhosting" fi echo "==== Create User ${USER} ====" if ! id "${USER}"; then useradd "${USER}" -m fi echo "=== Yellowtent base image preparation (installer revision - ${INSTALLER_REVISION}) ===" export DEBIAN_FRONTEND=noninteractive echo "=== Upgrade ===" apt-get update apt-get upgrade -y apt-get install -y curl # Setup firewall before everything. docker creates it's own chain and the -X below will remove it # Do NOT use iptables-persistent because it's startup ordering conflicts with docker echo "=== Setting up firewall ===" # clear tables and set default policy iptables -F # flush all chains iptables -X # delete all chains # default policy for filter table iptables -P INPUT DROP iptables -P FORWARD ACCEPT # TODO: disable icc and make this as reject iptables -P OUTPUT ACCEPT # NOTE: keep these in sync with src/apps.js validatePortBindings # allow ssh, http, https, ping, dns iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT if [ ${SELFHOSTED} == 0 ]; then iptables -A INPUT -p tcp -m tcp -m multiport --dports 80,202,443,886 -j ACCEPT else iptables -A INPUT -p tcp -m tcp -m multiport --dports 80,22,443,886 -j ACCEPT fi iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT iptables -A INPUT -p udp --sport 53 -j ACCEPT iptables -A INPUT -s 172.17.0.0/16 -j ACCEPT # required to accept any connections from apps to our IP: # loopback iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # disable metadata access to non-root # modprobe ipt_owner iptables -A OUTPUT -m owner ! --uid-owner root -d 169.254.169.254 -j DROP # prevent DoS # iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT # log dropped incoming. keep this at the end of all the rules iptables -N LOGGING # new chain iptables -A INPUT -j LOGGING # last rule in INPUT chain iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7 iptables -A LOGGING -j DROP echo "==== Install btrfs tools ===" apt-get -y install btrfs-tools echo "==== Install docker ====" # install docker from binary to pin it to a specific version. the current debian repo does not allow pinning curl https://get.docker.com/builds/Linux/x86_64/docker-1.9.1 > /usr/bin/docker chmod +x /usr/bin/docker groupadd docker cat > /etc/systemd/system/docker.socket < /etc/systemd/system/docker.service <> /etc/fstab mkdir -p "${USER_DATA_DIR}" && mount "${USER_DATA_FILE}" mkdir -p "${USER_DATA_DIR}/docker" # give docker sometime to start up and create iptables rules systemctl enable docker systemctl start docker sleep 10 # Disable forwarding to metadata route from containers iptables -I FORWARD -d 169.254.169.254 -j DROP # ubuntu will restore iptables from this file automatically. this is here so that docker's chain is saved to this file mkdir /etc/iptables && iptables-save > /etc/iptables/rules.v4 echo "=== Enable memory accounting ==" sed -e 's/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1 panic_on_oops=1 panic=5"/' -i /etc/default/grub update-grub # now add the user to the docker group usermod "${USER}" -a -G docker if [ -z $(echo "${INFRA_VERSION}") ]; then echo "Skip pulling base docker images" else echo "=== Pulling base docker images ===" docker pull "${BASE_IMAGE}" echo "=== Pulling mysql addon image ===" docker pull "${MYSQL_IMAGE}" echo "=== Pulling postgresql addon image ===" docker pull "${POSTGRESQL_IMAGE}" echo "=== Pulling redis addon image ===" docker pull "${REDIS_IMAGE}" echo "=== Pulling mongodb addon image ===" docker pull "${MONGODB_IMAGE}" echo "=== Pulling graphite docker images ===" docker pull "${GRAPHITE_IMAGE}" echo "=== Pulling mail relay ===" docker pull "${MAIL_IMAGE}" fi echo "==== Install nginx ====" apt-get -y install nginx-full echo "==== Install build-essential ====" apt-get -y install build-essential rcconf echo "==== Install mysql ====" debconf-set-selections <<< 'mysql-server mysql-server/root_password password password' debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password password' apt-get -y install mysql-server echo "==== Install pwgen ====" apt-get -y install pwgen echo "==== Install collectd ===" apt-get install -y collectd collectd-utils update-rc.d -f collectd remove # this simply makes it explicit that we run logrotate via cron. it's already part of base ubuntu echo "==== Install logrotate ===" apt-get install -y cron logrotate systemctl enable cron echo "==== Extracting installer source ====" rm -rf "${INSTALLER_SOURCE_DIR}" && mkdir -p "${INSTALLER_SOURCE_DIR}" tar xvf /root/installer.tar -C "${INSTALLER_SOURCE_DIR}" && rm /root/installer.tar echo "${INSTALLER_REVISION}" > "${INSTALLER_SOURCE_DIR}/REVISION" echo "==== Install nodejs ====" # Cannot use anything above 4.1.1 - https://github.com/nodejs/node/issues/3803 mkdir -p /usr/local/node-4.1.1 curl -sL https://nodejs.org/dist/v4.1.1/node-v4.1.1-linux-x64.tar.gz | tar zxvf - --strip-components=1 -C /usr/local/node-4.1.1 ln -s /usr/local/node-4.1.1/bin/node /usr/bin/node ln -s /usr/local/node-4.1.1/bin/npm /usr/bin/npm apt-get install -y python # Install python which is required for npm rebuild echo "=== Rebuilding npm packages ===" cd "${INSTALLER_SOURCE_DIR}" && npm install --production chown "${USER}:${USER}" -R "${INSTALLER_SOURCE_DIR}" echo "==== Install installer systemd script ====" selfhostEnv="" if [ ${SELFHOSTED} == 1 ]; then selfhostEnv="SELFHOSTED=true" fi cat > /etc/systemd/system/cloudron-installer.service < /etc/systemd/system/iptables-restore.service < /etc/systemd/system/box-setup.service <