Files
zulip/scripts/lib/install
Greg Price cef8549ec6 install: Add --snakeoil-cert option.
This provides a major simplification for non-production installs,
including our own testing (it's already in both the test-install
harness script and the "production" test suite) as well as potential
admins evaluating Zulip.

Ultimately this should probably be the default behavior, with perhaps
something shown to admins on the web as a reminder and link to help on
installing a better certificate.  For now, pending working through
that, just get the behavior in and leave it opt-in.
2018-01-22 18:55:46 -08:00

286 lines
9.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
usage() {
cat <<EOF
Usage:
install [--hostname=zulip.example.com] [--email=admin@example.com] [options...]
install --help
Other options:
--certbot
--snakeoil-cert
If --certbot is used, --hostname and --email are required.
EOF
exit 0
};
# Shell option parsing. Over time, we'll want to move some of the
# environment variables below into this self-documenting system.
args="$(getopt -o '' --long help,snakeoil-cert,certbot,hostname:,email: -n "$0" -- "$@")"
eval "set -- $args"
while true; do
case "$1" in
--help)
show_help=1
shift
;;
--snakeoil-cert)
SNAKEOIL_CERT=1
shift
;;
--certbot)
USE_CERTBOT=1
shift
;;
--hostname)
EXTERNAL_HOST="$2"
shift
shift
;;
--email)
ZULIP_ADMINISTRATOR="$2"
shift
shift
;;
--)
break
;;
esac
done
if [ -n "$show_help" ]; then
usage
fi
if [ -n "$USE_CERTBOT" ] \
&& { [ -z "$EXTERNAL_HOST" ] || [ -z "$ZULIP_ADMINISTRATOR" ]; }; then
usage
fi
# Do set -x after option parsing is complete
set -x
# Force a known locale. Some packages on PyPI fail to install in some locales.
export LC_ALL="en_US.UTF-8"
# Specify options for apt.
APT_OPTIONS="${APT_OPTIONS:-}"
# Install additional packages using apt.
ADDITIONAL_PACKAGES=${ADDITIONAL_PACKAGES:-}
# Deployment type is almost always voyager.
DEPLOYMENT_TYPE="${DEPLOYMENT_TYPE:-voyager}"
# Comma-separated list of puppet manifests to install. default is
# zulip::voyager for an all-in-one system or zulip::dockervoyager for
# Docker. Use e.g. zulip::app_frontend for a Zulip frontend server.
PUPPET_CLASSES="${PUPPET_CLASSES:-zulip::voyager}"
VIRTUALENV_NEEDED="${VIRTUALENV_NEEDED:-yes}"
# Check for at least ~1.9GB of RAM before starting installation;
# otherwise users will find out about insufficient RAM via weird
# errors like a segfault running `pip install`.
mem_kb=$(cat /proc/meminfo | head -n1 | awk '{print $2}')
if [ "$mem_kb" -lt 1900000 ]; then
echo "Insufficient RAM. Zulip requires at least 2GB of RAM."
exit 1
fi
if ! [ -e /usr/bin/realpath ]; then
# realpath is in coreutils on Xenial, but not in Trusty
apt-get install -y realpath
fi
ZULIP_PATH="$(realpath $(dirname $0)/../..)"
# setup-apt-repo does an `apt-get update`
"$ZULIP_PATH"/scripts/lib/setup-apt-repo
# Handle issues around upstart on Ubuntu Xenial
"$ZULIP_PATH"/scripts/lib/check-upstart
# Check early for missing SSL certificates
if [ "$PUPPET_CLASSES" = "zulip::voyager" ] && [ -z "$USE_CERTBOT""$SNAKEOIL_CERT" ] && { ! [ -e "/etc/ssl/private/zulip.key" ] || ! [ -e "/etc/ssl/certs/zulip.combined-chain.crt" ]; }; then
set +x
echo
echo "Could not find SSL certificates!"
for f in "/etc/ssl/private/zulip.key" "/etc/ssl/certs/zulip.combined-chain.crt"; do
[ -e "$f" ] || echo " - $f is missing!"
done
echo "See https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html for help."
echo "For non-production testing, try the --snakeoil-cert option to use"
echo "your system's self-signed certificate."
echo
echo "Once fixed, just rerun scripts/setup/install; it'll pick up from here!"
echo
exit 1
fi
apt-get -y dist-upgrade $APT_OPTIONS
apt-get install -y \
puppet git curl \
python python3 python-six python3-six crudini \
$ADDITIONAL_PACKAGES
if [ -n "$USE_CERTBOT" ]; then
"$ZULIP_PATH"/scripts/setup/setup-certbot \
--no-zulip-conf --method=standalone \
--hostname "$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR"
fi
# Create and activate a virtualenv
if [ "$VIRTUALENV_NEEDED" = "yes" ]; then
"$ZULIP_PATH"/scripts/lib/create-production-venv "$ZULIP_PATH"
fi
"$ZULIP_PATH"/scripts/lib/install-node
# puppet apply
mkdir -p /etc/zulip
(
echo -e "[machine]\npuppet_classes = $PUPPET_CLASSES\ndeploy_type = $DEPLOYMENT_TYPE";
# Note: there are four dpkg-query outputs to consider:
#
# root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null
# root@host# apt install rabbitmq-server
# root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null
# install ok installed
# root@host# apt remove rabbitmq-server
# root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null
# deinstall ok config-files
# root@host# apt purge rabbitmq-server
# root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null
# unknown ok not-installed
#
# (There are more possibilities in the case of dpkg errors.) Here
# we are checking for either empty or not-installed.
if [ -n "$TRAVIS" ] || ! dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null | grep -vq ' not-installed$'; then
echo -e "\n[rabbitmq]\nnodename = zulip@localhost"
fi
if [ -n "$USE_CERTBOT" ]; then
echo -e "\n[certbot]\nauto_renew = yes"
fi
) > /etc/zulip/zulip.conf
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f
# Detect which features were selected for the below
set +e
[ -e "/etc/init.d/camo" ]; has_camo=$?
[ -e "/etc/init.d/nginx" ]; has_nginx=$?
[ -e "/etc/supervisor/conf.d/zulip.conf" ]; has_appserver=$?
[ -e "/etc/cron.d/rabbitmq-numconsumers" ]; has_rabbit=$?
[ -e "/etc/init.d/postgresql" ]; has_postgres=$?
set -e
# Docker service setup is done in the docker config, not here
if [ "$DEPLOYMENT_TYPE" = "dockervoyager" ]; then
has_camo=1
has_nginx=1
has_appserver=1
has_rabbit=1
has_postgres=1
fi
# These server restarting bits should be moveable into puppet-land, ideally
apt-get -y upgrade
if [ "$has_nginx" = 0 ]; then
if [ -n "$SNAKEOIL_CERT" ] && ! [ -e "/etc/ssl/private/zulip.key" ]; then
apt-get install -y openssl ssl-cert
ln -nsf /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/certs/zulip.combined-chain.crt
ln -nsf /etc/ssl/private/ssl-cert-snakeoil.key /etc/ssl/private/zulip.key
fi
# Check nginx was configured properly now that we've installed it.
# Most common failure mode is certs not having been installed.
nginx -t || (
set +x
echo
echo "Verifying the Zulip nginx configuration failed!"
echo
echo "This is almost always a problem with your SSL certificates."
echo "See https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html for help"
echo
echo "Once fixed, just rerun scripts/setup/install; it'll pick up from here!"
echo
exit 1
)
service nginx restart
fi
if [ "$has_appserver" = 0 ]; then
"$ZULIP_PATH"/scripts/setup/generate_secrets.py --production
cp -a "$ZULIP_PATH"/zproject/prod_settings_template.py /etc/zulip/settings.py
if [ -n "$EXTERNAL_HOST" ]; then
sed -i "s/^EXTERNAL_HOST =.*/EXTERNAL_HOST = '$EXTERNAL_HOST'/" /etc/zulip/settings.py
fi
if [ -n "ZULIP_ADMINISTRATOR" ]; then
sed -i "s/^ZULIP_ADMINISTRATOR =.*/ZULIP_ADMINISTRATOR = '$ZULIP_ADMINISTRATOR'/" /etc/zulip/settings.py
fi
ln -nsf /etc/zulip/settings.py "$ZULIP_PATH"/zproject/prod_settings.py
fi
# Restart camo since generate_secrets.py likely replaced its secret key
if [ "$has_camo" = 0 ] && [ -z "$TRAVIS" ]; then
# We don't run this in Travis CI due to a weird hang bug
service camo restart
fi
if [ "$has_rabbit" = 0 ]; then
if ! rabbitmqctl status >/dev/null; then
set +x
echo; echo "RabbitMQ seems to not have started properly after the installation process."
echo "Often, this can be caused by misconfigured /etc/hosts in virtualized environments"
echo "See https://github.com/zulip/zulip/issues/53#issuecomment-143805121"
echo "for more information"
echo
set -x
exit 1
fi
"$ZULIP_PATH"/scripts/setup/configure-rabbitmq
fi
if [ "$has_postgres" = 0 ]; then
"$ZULIP_PATH"/scripts/setup/postgres-init-db
fi
if [ "$has_appserver" = 0 ]; then
deploy_path=$("$ZULIP_PATH"/scripts/lib/zulip_tools.py make_deploy_path)
mv "$ZULIP_PATH" "$deploy_path"
ln -nsf /home/zulip/deployments/next "$ZULIP_PATH"
ln -nsf "$deploy_path" /home/zulip/deployments/next
ln -nsf "$deploy_path" /home/zulip/deployments/current
ln -nsf /etc/zulip/settings.py "$deploy_path"/zproject/prod_settings.py
mkdir -p "$deploy_path"/prod-static/serve
cp -rT "$deploy_path"/prod-static/serve /home/zulip/prod-static
chown -R zulip:zulip /home/zulip /var/log/zulip /etc/zulip/settings.py
if ! [ -e "/home/zulip/prod-static/generated" ]; then
# If we're installing from a git checkout, we need to run
# `tools/update-prod-static` in order to build the static
# assets.
su zulip -c "/home/zulip/deployments/current/tools/update-prod-static --authors-not-required"
fi
fi
if [ -e "/var/run/supervisor.sock" ]; then
# If supervisor isn't running, no need to chown its socket
chown zulip:zulip /var/run/supervisor.sock
fi
set +x
cat <<EOF
Installation complete!
Now edit /etc/zulip/settings.py and fill in the mandatory values.
Once you've done that, please run:
su zulip -c /home/zulip/deployments/current/scripts/setup/initialize-database
To configure the initial database.
EOF