2016-10-24 16:18:02 +02:00
#!/bin/bash
2016-10-25 12:00:54 -07:00
set -eu -o pipefail
2016-10-24 16:18:02 +02:00
2016-11-01 15:13:20 +01:00
if [ [ ${ EUID } -ne 0 ] ] ; then
echo "This script should be run as root." > /dev/stderr
2017-01-23 12:57:29 -08:00
exit 1
fi
if [ [ $( lsb_release -rs) != "16.04" ] ] ; then
echo "Cloudron requires Ubuntu 16.04" > /dev/stderr
2016-11-01 15:13:20 +01:00
exit 1
fi
2016-10-24 14:52:30 -07:00
# change this to a hash when we make a upgrade release
2016-10-25 14:01:35 +02:00
readonly LOG_FILE = "/var/log/cloudron-setup.log"
2017-02-15 14:19:25 -08:00
readonly DATA_FILE = "/root/cloudron-install-data.json"
2017-03-22 14:21:40 +01:00
readonly MINIMUM_DISK_SIZE_GB = "18" # this is the size of "/" and required to fit in docker images 18 is a safe bet for different reporting on 20GB min
2017-03-13 13:05:59 -07:00
readonly MINIMUM_MEMORY = "974" # this is mostly reported for 1GB main memory (DO 992, EC2 990, Linode 989, Serverdiscounter.com 974)
2017-01-02 18:02:40 +01:00
2017-02-16 17:32:44 -08:00
readonly curl = "curl --fail --connect-timeout 20 --retry 10 --retry-delay 2 --max-time 2400"
2017-01-02 18:02:40 +01:00
# copied from cloudron-resize-fs.sh
2017-07-24 18:14:51 -07:00
readonly rootfs_type = $( LC_ALL = C df --output= fstype / | tail -n1)
2017-03-13 10:32:27 -07:00
readonly physical_memory = $( LC_ALL = C free -m | awk '/Mem:/ { print $2 }' )
2017-03-27 13:51:34 +02:00
readonly disk_size_bytes = $( LC_ALL = C df --output= size / | tail -n1)
2017-03-22 14:21:40 +01:00
readonly disk_size_gb = $(( ${ disk_size_bytes } / 1024 / 1024 ))
2017-01-02 18:02:40 +01:00
# verify the system has minimum requirements met
2017-07-24 18:14:51 -07:00
if [ [ " ${ rootfs_type } " != "ext4" ] ] ; then
echo "Error: Cloudron requires '/' to be ext4" # see #364
exit 1
fi
2017-01-02 18:02:40 +01:00
if [ [ " ${ physical_memory } " -lt " ${ MINIMUM_MEMORY } " ] ] ; then
2017-01-03 14:27:01 -08:00
echo "Error: Cloudron requires atleast 1GB physical memory"
2017-01-02 18:02:40 +01:00
exit 1
fi
if [ [ " ${ disk_size_gb } " -lt " ${ MINIMUM_DISK_SIZE_GB } " ] ] ; then
2017-03-27 13:51:34 +02:00
echo " Error: Cloudron requires atleast 20GB disk space (Disk space on / is ${ disk_size_gb } GB) "
2017-01-02 18:02:40 +01:00
exit 1
fi
2016-10-24 14:52:30 -07:00
2016-12-26 11:37:50 -08:00
initBaseImage = "true"
# provisioning data
2016-10-24 16:18:02 +02:00
domain = ""
2017-10-25 20:35:24 -07:00
adminLocation = "my"
2017-07-16 21:58:33 -07:00
zoneName = ""
2016-10-26 10:53:25 -07:00
provider = ""
2016-11-13 11:20:50 +01:00
encryptionKey = ""
2016-10-24 14:52:30 -07:00
restoreUrl = ""
2016-12-15 07:35:54 -08:00
dnsProvider = "manual"
2016-12-05 17:01:23 +01:00
tlsProvider = "le-prod"
2017-04-13 15:20:33 -07:00
requestedVersion = ""
2017-01-11 12:35:31 -08:00
apiServerOrigin = "https://api.cloudron.io"
2017-06-08 10:30:23 -07:00
webServerOrigin = "https://cloudron.io"
2016-12-26 11:37:50 -08:00
dataJson = ""
2017-02-07 12:42:32 +01:00
prerelease = "false"
2017-02-01 14:06:18 -08:00
sourceTarballUrl = ""
2017-02-07 12:42:32 +01:00
rebootServer = "true"
2017-04-06 16:26:22 -07:00
baseDataDir = ""
2016-10-24 16:18:02 +02:00
2017-04-14 15:04:20 +02:00
# TODO this is still there for the restore case, see other occasions below
versionsUrl = "https://s3.amazonaws.com/prod-cloudron-releases/versions.json"
2017-10-25 20:35:24 -07:00
args = $( getopt -o "" -l "domain:,help,skip-baseimage-init,data:,data-dir:,provider:,encryption-key:,restore-url:,tls-provider:,version:,dns-provider:,env:,admin-location:,prerelease,skip-reboot,source-url:" -n " $0 " -- " $@ " )
2016-10-24 16:18:02 +02:00
eval set -- " ${ args } "
while true; do
case " $1 " in
--domain) domain = " $2 " ; shift 2; ;
2017-10-25 20:35:24 -07:00
--admin-location) adminLocation = " $2 " ; shift 2; ;
2017-10-20 22:13:54 +02:00
--help) echo "See https://cloudron.io/documentation/installation/ on how to install Cloudron" ; exit 0; ;
2016-10-24 16:18:02 +02:00
--provider) provider = " $2 " ; shift 2; ;
2016-11-13 11:20:50 +01:00
--encryption-key) encryptionKey = " $2 " ; shift 2; ;
2016-10-24 14:52:30 -07:00
--restore-url) restoreUrl = " $2 " ; shift 2; ;
2016-10-24 17:30:47 +02:00
--tls-provider) tlsProvider = " $2 " ; shift 2; ;
2016-12-15 07:35:54 -08:00
--dns-provider) dnsProvider = " $2 " ; shift 2; ;
2016-12-30 13:12:22 -08:00
--version) requestedVersion = " $2 " ; shift 2; ;
2017-01-10 20:19:39 -08:00
--env)
if [ [ " $2 " = = "dev" ] ] ; then
2017-04-14 15:04:20 +02:00
versionsUrl = "https://s3.amazonaws.com/dev-cloudron-releases/versions.json"
2017-01-11 12:35:31 -08:00
apiServerOrigin = "https://api.dev.cloudron.io"
2017-06-08 10:30:23 -07:00
webServerOrigin = "https://dev.cloudron.io"
2017-01-12 18:05:42 -08:00
tlsProvider = "le-staging"
2017-01-10 20:19:39 -08:00
prerelease = "true"
elif [ [ " $2 " = = "staging" ] ] ; then
2017-04-14 15:04:20 +02:00
versionsUrl = "https://s3.amazonaws.com/staging-cloudron-releases/versions.json"
2017-01-11 12:35:31 -08:00
apiServerOrigin = "https://api.staging.cloudron.io"
2017-06-08 10:30:23 -07:00
webServerOrigin = "https://staging.cloudron.io"
2017-01-12 18:05:42 -08:00
tlsProvider = "le-staging"
2017-01-10 20:19:39 -08:00
prerelease = "true"
fi
shift 2; ;
2016-12-26 10:00:00 -08:00
--skip-baseimage-init) initBaseImage = "false" ; shift; ;
2017-02-07 12:42:32 +01:00
--skip-reboot) rebootServer = "false" ; shift; ;
2016-12-26 11:37:50 -08:00
--data) dataJson = " $2 " ; shift 2; ;
2017-01-10 20:19:39 -08:00
--prerelease) prerelease = "true" ; shift; ;
2017-02-01 14:06:18 -08:00
--source-url) sourceTarballUrl = " $2 " ; version = "0.0.1+custom" ; shift 2; ;
2017-04-06 16:26:22 -07:00
--data-dir) baseDataDir = $( realpath " $2 " ) ; shift 2; ;
2016-10-24 16:18:02 +02:00
--) break; ;
*) echo " Unknown option $1 " ; exit 1; ;
esac
done
2016-12-27 13:36:02 -08:00
# validate arguments in the absence of data
if [ [ -z " ${ dataJson } " ] ] ; then
if [ [ -z " ${ provider } " ] ] ; then
2017-10-19 07:28:07 -07:00
echo "--provider is required (azure, cloudscale.ch, digitalocean, ec2, exoscale, lightsail, linode, ovh, rosehosting, scaleway, vultr or generic)"
2016-12-27 13:36:02 -08:00
exit 1
elif [ [ \
2017-03-14 09:32:51 +01:00
" ${ provider } " != "ami" && \
2017-02-15 20:10:28 -08:00
" ${ provider } " != "azure" && \
2017-10-19 07:28:07 -07:00
" ${ provider } " != "cloudscale.ch" && \
2017-02-15 15:49:00 -08:00
" ${ provider } " != "digitalocean" && \
2016-12-27 13:36:02 -08:00
" ${ provider } " != "ec2" && \
2017-09-21 17:47:02 -07:00
" ${ provider } " != "exoscale" && \
2017-06-12 14:05:03 -07:00
" ${ provider } " != "gce" && \
2017-02-15 15:49:00 -08:00
" ${ provider } " != "lightsail" && \
" ${ provider } " != "linode" && \
" ${ provider } " != "ovh" && \
2017-02-18 12:01:49 +01:00
" ${ provider } " != "rosehosting" && \
2017-02-15 15:49:00 -08:00
" ${ provider } " != "scaleway" && \
" ${ provider } " != "vultr" && \
" ${ provider } " != "generic" \
2016-12-27 13:36:02 -08:00
] ] ; then
2017-10-19 07:28:07 -07:00
echo "--provider must be one of: azure, cloudscale.ch, digitalocean, ec2, exoscale, gce, lightsail, linode, ovh, rosehosting, scaleway, vultr or generic"
2016-12-27 13:36:02 -08:00
exit 1
fi
2016-10-26 10:53:25 -07:00
2017-01-12 10:31:54 -08:00
if [ [ " ${ tlsProvider } " != "fallback" && " ${ tlsProvider } " != "le-prod" && " ${ tlsProvider } " != "le-staging" ] ] ; then
echo "--tls-provider must be one of: le-prod, le-staging, fallback"
exit 1
fi
2016-12-27 13:36:02 -08:00
if [ [ -z " ${ dnsProvider } " ] ] ; then
echo "--dns-provider is required (noop, manual)"
exit 1
elif [ [ " ${ dnsProvider } " != "noop" && " ${ dnsProvider } " != "manual" ] ] ; then
echo "--dns-provider must be one of : manual, noop"
exit 1
fi
2017-04-07 11:37:30 -07:00
if [ [ -n " ${ baseDataDir } " && ! -d " ${ baseDataDir } " ] ] ; then
echo " ${ baseDataDir } does not exist "
exit 1
fi
2016-12-15 07:35:54 -08:00
fi
2016-10-25 15:28:26 +02:00
echo ""
2016-10-25 14:07:28 +02:00
echo "##############################################"
2017-04-13 15:20:33 -07:00
echo " Cloudron Setup ( ${ requestedVersion :- latest } ) "
2016-10-25 14:07:28 +02:00
echo "##############################################"
echo ""
echo " Follow setup logs in a second terminal with:"
echo " $ tail -f ${ LOG_FILE } "
echo ""
2016-12-22 13:28:04 -08:00
echo " Join us at https://chat.cloudron.io for any questions."
echo ""
2016-10-25 14:07:28 +02:00
2017-01-05 14:03:30 -08:00
if [ [ " ${ initBaseImage } " = = "true" ] ] ; then
2017-02-12 20:48:36 +01:00
echo "=> Updating apt and installing script dependencies"
2017-01-05 14:03:30 -08:00
if ! apt-get update & >> " ${ LOG_FILE } " ; then
echo "Could not update package repositories"
exit 1
fi
2017-01-05 14:03:54 -08:00
if ! apt-get install curl python3 ubuntu-standard -y & >> " ${ LOG_FILE } " ; then
2017-01-05 14:03:30 -08:00
echo "Could not install setup dependencies (curl)"
exit 1
fi
fi
2016-10-25 13:05:24 -07:00
echo "=> Checking version"
2017-02-01 14:06:18 -08:00
if [ [ " ${ sourceTarballUrl } " = = "" ] ] ; then
2017-04-13 15:20:33 -07:00
if ! releaseJson = $( $curl -s " ${ apiServerOrigin } /api/v1/releases?prerelease= ${ prerelease } &boxVersion= ${ requestedVersion } " ) ; then
echo "Failed to get release information"
exit 1
fi
if [ [ " $requestedVersion " = = "" ] ] ; then
version = $( echo " ${ releaseJson } " | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["version"])' )
2017-02-01 14:06:18 -08:00
else
version = " ${ requestedVersion } "
fi
2017-04-13 15:20:33 -07:00
if ! sourceTarballUrl = $( echo " ${ releaseJson } " | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["info"]["sourceTarballUrl"])' ) ; then
echo " No source code for version ' ${ requestedVersion :- latest } ' "
2017-02-01 14:06:18 -08:00
exit 1
fi
2016-10-25 13:05:24 -07:00
fi
2016-12-30 13:12:22 -08:00
# Build data
2017-04-14 15:04:20 +02:00
# TODO versionsUrl is still there for the cloudron restore case
2016-12-30 13:12:22 -08:00
if [ [ -z " ${ dataJson } " ] ] ; then
if [ [ -z " ${ restoreUrl } " ] ] ; then
data = $( cat <<EOF
{
2017-04-14 15:04:20 +02:00
"boxVersionsUrl": "${versionsUrl}",
2016-12-30 13:12:22 -08:00
"fqdn": "${domain}",
2017-10-25 20:35:24 -07:00
"adminLocation": "${adminLocation}",
2017-07-16 21:58:33 -07:00
"zoneName": "${zoneName}",
2016-12-30 13:12:22 -08:00
"provider": "${provider}",
2017-01-11 12:35:31 -08:00
"apiServerOrigin": "${apiServerOrigin}",
2017-06-08 10:30:23 -07:00
"webServerOrigin": "${webServerOrigin}",
2016-12-30 13:12:22 -08:00
"tlsConfig": {
"provider": "${tlsProvider}"
},
"dnsConfig": {
"provider": "${dnsProvider}"
},
"backupConfig" : {
"provider": "filesystem",
"backupFolder": "/var/backups",
2017-04-22 20:27:52 -07:00
"key": "${encryptionKey}",
2017-09-21 09:49:10 -07:00
"format": "tgz",
2017-04-22 20:27:52 -07:00
"retentionSecs": 172800
2016-12-30 13:12:22 -08:00
},
"version": "${version}"
}
EOF
)
else
data = $( cat <<EOF
{
2017-04-14 15:04:20 +02:00
"boxVersionsUrl": "${versionsUrl}",
2016-12-30 13:12:22 -08:00
"fqdn": "${domain}",
2017-10-25 20:35:24 -07:00
"adminLocation": "${adminLocation}",
2017-07-16 21:58:33 -07:00
"zoneName": "${zoneName}",
2016-12-30 13:12:22 -08:00
"provider": "${provider}",
2017-01-11 12:35:31 -08:00
"apiServerOrigin": "${apiServerOrigin}",
2017-06-08 10:30:23 -07:00
"webServerOrigin": "${webServerOrigin}",
2016-12-30 13:12:22 -08:00
"restore": {
"url": "${restoreUrl}",
"key": "${encryptionKey}"
},
"version": "${version}"
}
EOF
)
fi
else
data = " ${ dataJson } "
fi
2017-01-03 14:48:37 -08:00
echo " => Downloading version ${ version } ... "
2016-12-23 18:28:18 -08:00
box_src_tmp_dir = $( mktemp -dt box-src-XXXXXX)
2017-02-16 17:32:44 -08:00
if ! $curl -sL " ${ sourceTarballUrl } " | tar -zxf - -C " ${ box_src_tmp_dir } " ; then
2016-12-23 18:28:18 -08:00
echo " Could not download source tarball. See ${ LOG_FILE } for details "
exit 1
fi
2017-01-03 14:48:37 -08:00
if [ [ " ${ initBaseImage } " = = "true" ] ] ; then
2017-01-19 09:58:31 -08:00
echo -n "=> Installing base dependencies and downloading docker images (this takes some time) ..."
2017-01-09 09:22:22 -08:00
if ! /bin/bash " ${ box_src_tmp_dir } /baseimage/initializeBaseUbuntuImage.sh " " ${ provider } " "../src" & >> " ${ LOG_FILE } " ; then
2017-01-03 14:48:37 -08:00
echo " Init script failed. See ${ LOG_FILE } for details "
exit 1
fi
2017-01-19 09:58:31 -08:00
echo ""
2017-01-03 14:48:37 -08:00
fi
echo " => Installing version ${ version } (this takes some time) ... "
2017-02-15 14:19:25 -08:00
echo " ${ data } " > " ${ DATA_FILE } "
2017-04-14 17:24:28 +02:00
# poor mans semver
2017-05-08 12:04:00 -07:00
if [ [ ${ version } = = "0.10" * ] ] ; then
if ! /bin/bash " ${ box_src_tmp_dir } /scripts/installer.sh " --data-file " ${ DATA_FILE } " & >> " ${ LOG_FILE } " ; then
2017-04-14 17:24:28 +02:00
echo " Failed to install cloudron. See ${ LOG_FILE } for details "
exit 1
fi
else
2017-05-08 12:04:00 -07:00
if ! /bin/bash " ${ box_src_tmp_dir } /scripts/installer.sh " --data-file " ${ DATA_FILE } " --data-dir " ${ baseDataDir } " & >> " ${ LOG_FILE } " ; then
2017-04-14 17:24:28 +02:00
echo " Failed to install cloudron. See ${ LOG_FILE } for details "
exit 1
fi
2016-10-25 12:47:51 -07:00
fi
2017-02-15 14:19:25 -08:00
rm " ${ DATA_FILE } "
2016-10-25 11:27:58 +02:00
2016-12-30 11:35:03 +01:00
echo -n "=> Waiting for cloudron to be ready (this takes some time) ..."
2016-10-24 14:52:30 -07:00
while true; do
echo -n "."
2017-02-16 17:32:44 -08:00
if status = $( $curl -q -f "http://localhost:3000/api/v1/cloudron/status" 2>/dev/null) ; then
2017-01-09 12:57:34 -08:00
[ [ -z " $domain " ] ] && break # with no domain, we are up and running
[ [ " $status " = = *"\"tls\": true" * ] ] && break # with a domain, wait for the cert
2016-10-24 14:52:30 -07:00
fi
sleep 10
done
2017-01-05 20:18:57 -08:00
if [ [ -n " ${ domain } " ] ] ; then
2017-02-14 14:30:54 -08:00
echo -e " \n\nVisit https://my. ${ domain } to finish setup once the server has rebooted.\n "
2017-01-05 20:18:57 -08:00
else
2017-02-14 14:30:54 -08:00
echo -e "\n\nVisit https://<IP> to finish setup once the server has rebooted.\n"
2017-01-05 20:18:57 -08:00
fi
2017-02-07 12:42:32 +01:00
if [ [ " ${ rebootServer } " = = "true" ] ] ; then
echo -e "\n\nRebooting this server now to let bootloader changes take effect.\n"
2017-06-21 17:20:02 -07:00
systemctl stop mysql # sometimes mysql ends up having corrupt privilege tables
2017-02-07 12:42:32 +01:00
systemctl reboot
fi