mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
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.
286 lines
9.2 KiB
Bash
Executable File
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
|