mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			382 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env bash
 | 
						|
set -e
 | 
						|
 | 
						|
usage() {
 | 
						|
    cat <<EOF
 | 
						|
Usage:
 | 
						|
  install --hostname=zulip.example.com --email=zulip-admin@example.com [options...]
 | 
						|
  install --help
 | 
						|
 | 
						|
Other options:
 | 
						|
  --certbot
 | 
						|
  --self-signed-cert
 | 
						|
  --no-init-db
 | 
						|
  --cacert
 | 
						|
  --no-dist-upgrade
 | 
						|
 | 
						|
The --hostname and --email options are required,
 | 
						|
unless --no-init-db is set and --certbot is not.
 | 
						|
 | 
						|
EOF
 | 
						|
};
 | 
						|
 | 
						|
# 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,no-init-db,no-dist-upgrade,no-overwrite-settings,self-signed-cert,certbot,hostname:,email:,cacert: -n "$0" -- "$@")"
 | 
						|
eval "set -- $args"
 | 
						|
while true; do
 | 
						|
    case "$1" in
 | 
						|
        --help) usage; exit 0;;
 | 
						|
        --self-signed-cert) SELF_SIGNED_CERT=1; shift;;
 | 
						|
        --cacert) export CUSTOM_CA_CERTIFICATES="$2"; shift; shift;;
 | 
						|
        --certbot) USE_CERTBOT=1; shift;;
 | 
						|
        --hostname) EXTERNAL_HOST="$2"; shift; shift;;
 | 
						|
        --email) ZULIP_ADMINISTRATOR="$2"; shift; shift;;
 | 
						|
        --no-overwrite-settings) NO_OVERWRITE_SETTINGS=1; shift;;
 | 
						|
        --no-init-db) NO_INIT_DB=1; shift;;
 | 
						|
        --no-dist-upgrade) NO_DIST_UPGRADE=1; shift;;
 | 
						|
        --) shift; break;;
 | 
						|
    esac
 | 
						|
done
 | 
						|
 | 
						|
if [ "$#" -gt 0 ]; then
 | 
						|
    usage >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
## Options from environment variables.
 | 
						|
#
 | 
						|
# Specify options for apt.
 | 
						|
read -r -a APT_OPTIONS <<< "${APT_OPTIONS:-}"
 | 
						|
# Install additional packages using apt.
 | 
						|
read -r -a 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}"
 | 
						|
 | 
						|
if [ -n "$SELF_SIGNED_CERT" ] && [ -n "$USE_CERTBOT" ]; then
 | 
						|
    set +x
 | 
						|
    echo "error: --self-signed-cert and --certbot are incompatible" >&2
 | 
						|
    echo >&2
 | 
						|
    usage >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
if [ -z "$EXTERNAL_HOST" ] || [ -z "$ZULIP_ADMINISTRATOR" ]; then
 | 
						|
    if [ -n "$USE_CERTBOT" ] || [ -z "$NO_INIT_DB" ]; then
 | 
						|
        usage >&2
 | 
						|
        exit 1
 | 
						|
    fi
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$EXTERNAL_HOST" = zulip.example.com ] ||
 | 
						|
   [ "$ZULIP_ADMINISTRATOR" = zulip-admin@example.com ]; then
 | 
						|
    # These example values are specifically checked for and would fail
 | 
						|
    # later; see check_config in zerver/lib/management.py.
 | 
						|
    echo 'error: The example hostname and email must be replaced with real values.' >&2
 | 
						|
    echo >&2
 | 
						|
    usage >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
# Do set -x after option parsing is complete
 | 
						|
set -x
 | 
						|
 | 
						|
ZULIP_PATH="$(readlink -f "$(dirname "$0")"/../..)"
 | 
						|
 | 
						|
# Force a known locale.  Some packages on PyPI fail to install in some locales.
 | 
						|
localedef -i en_US -f UTF-8 en_US.UTF-8
 | 
						|
export LC_ALL="en_US.UTF-8"
 | 
						|
export LANG="en_US.UTF-8"
 | 
						|
export LANGUAGE="en_US.UTF-8"
 | 
						|
 | 
						|
# Check for a supported OS release.
 | 
						|
apt-get install -y lsb-release
 | 
						|
os_info="$(lsb_release --short --id --release --codename)"
 | 
						|
{ read -r os_id; read -r os_release; read -r os_codename; } <<< "$os_info"
 | 
						|
 | 
						|
case "$os_codename" in
 | 
						|
    xenial|stretch|bionic) ;;
 | 
						|
    *)
 | 
						|
        set +x
 | 
						|
        cat <<EOF
 | 
						|
 | 
						|
Unsupported OS release: $os_codename
 | 
						|
 | 
						|
Zulip in production is supported only on:
 | 
						|
 - Debian 9 "stretch"
 | 
						|
 - Ubuntu 16.04 LTS "xenial"
 | 
						|
 - Ubuntu 18.04 LTS "bionic"
 | 
						|
 | 
						|
For more information, see:
 | 
						|
  https://zulip.readthedocs.io/en/latest/production/requirements.html
 | 
						|
EOF
 | 
						|
        exit 1
 | 
						|
esac
 | 
						|
 | 
						|
if [ "$os_id" = Ubuntu ] && ! apt-cache policy |
 | 
						|
           grep -q "^     release v=$os_release,o=Ubuntu,a=$os_codename,n=$os_codename,l=Ubuntu,c=universe"; then
 | 
						|
    set +x
 | 
						|
    cat <<'EOF'
 | 
						|
 | 
						|
You must enable the Ubuntu Universe repository before installing
 | 
						|
Zulip.  You can do this with:
 | 
						|
 | 
						|
    sudo add-apt-repository universe
 | 
						|
    sudo apt update
 | 
						|
 | 
						|
For more information, see:
 | 
						|
  https://zulip.readthedocs.io/en/latest/production/requirements.html
 | 
						|
EOF
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
# 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=$(head -n1 /proc/meminfo | awk '{print $2}')
 | 
						|
if [ "$mem_kb" -lt 1900000 ]; then
 | 
						|
    set +x
 | 
						|
    echo -e '\033[0;31m' >&2
 | 
						|
    echo "Insufficient RAM.  Zulip requires at least 2GB of RAM." >&2
 | 
						|
    echo >&2
 | 
						|
    echo -e '\033[0m' >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
# 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""$SELF_SIGNED_CERT" ] && { ! [ -e "/etc/ssl/private/zulip.key" ] || ! [ -e "/etc/ssl/certs/zulip.combined-chain.crt" ]; }; then
 | 
						|
    set +x
 | 
						|
    cat <<EOF
 | 
						|
 | 
						|
No SSL certificate found.  One or both required files is missing:
 | 
						|
    /etc/ssl/private/zulip.key
 | 
						|
    /etc/ssl/certs/zulip.combined-chain.crt
 | 
						|
 | 
						|
Suggested solutions:
 | 
						|
 * For most sites, the --certbot option is recommended.
 | 
						|
 * If you have your own key and cert, see docs linked below
 | 
						|
   for how to install them.
 | 
						|
 * For non-production testing, try the --self-signed-cert option.
 | 
						|
 | 
						|
For help and more details, see our SSL documentation:
 | 
						|
  https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html
 | 
						|
 | 
						|
Once fixed, just rerun scripts/setup/install; it'll pick up from here!
 | 
						|
 | 
						|
EOF
 | 
						|
   exit 1
 | 
						|
fi
 | 
						|
 | 
						|
# don't run dist-upgrade in one click apps to make the
 | 
						|
# installation process more seamless.
 | 
						|
if [ -z "$NO_DIST_UPGRADE" ]; then
 | 
						|
    apt-get -y dist-upgrade "${APT_OPTIONS[@]}"
 | 
						|
fi
 | 
						|
 | 
						|
if ! apt-get install -y \
 | 
						|
    puppet git curl wget jq \
 | 
						|
    python python3 python-six python3-six crudini \
 | 
						|
    "${ADDITIONAL_PACKAGES[@]}"; then
 | 
						|
    set +x
 | 
						|
    echo -e '\033[0;31m' >&2
 | 
						|
    echo "Installing packages failed; is network working and (on Ubuntu) the universe repository enabled?" >&2
 | 
						|
    echo >&2
 | 
						|
    echo -e '\033[0m' >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
 | 
						|
if [ -n "$USE_CERTBOT" ]; then
 | 
						|
    "$ZULIP_PATH"/scripts/setup/setup-certbot \
 | 
						|
        --no-zulip-conf --method=standalone \
 | 
						|
        "$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR"
 | 
						|
elif [ -n "$SELF_SIGNED_CERT" ]; then
 | 
						|
    "$ZULIP_PATH"/scripts/setup/generate-self-signed-cert \
 | 
						|
        --exists-ok "${EXTERNAL_HOST:-$(hostname)}"
 | 
						|
fi
 | 
						|
 | 
						|
# Create and activate a virtualenv
 | 
						|
if [ "$VIRTUALENV_NEEDED" = "yes" ]; then
 | 
						|
    "$ZULIP_PATH"/scripts/lib/create-production-venv "$ZULIP_PATH"
 | 
						|
    "$ZULIP_PATH"/scripts/lib/create-thumbor-venv "$ZULIP_PATH"
 | 
						|
fi
 | 
						|
 | 
						|
"$ZULIP_PATH"/scripts/lib/install-node
 | 
						|
 | 
						|
# Generate /etc/zulip/zulip.conf .
 | 
						|
mkdir -p /etc/zulip
 | 
						|
(
 | 
						|
    cat <<EOF
 | 
						|
[machine]
 | 
						|
puppet_classes = $PUPPET_CLASSES
 | 
						|
deploy_type = $DEPLOYMENT_TYPE
 | 
						|
EOF
 | 
						|
 | 
						|
    # 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
 | 
						|
        cat <<EOF
 | 
						|
 | 
						|
[rabbitmq]
 | 
						|
nodename = zulip@localhost
 | 
						|
EOF
 | 
						|
    fi
 | 
						|
 | 
						|
    if [ -n "$USE_CERTBOT" ]; then
 | 
						|
        cat <<EOF
 | 
						|
 | 
						|
[certbot]
 | 
						|
auto_renew = yes
 | 
						|
EOF
 | 
						|
    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=0
 | 
						|
    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
 | 
						|
    # 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
 | 
						|
        cat <<EOF
 | 
						|
 | 
						|
Verifying the Zulip nginx configuration failed!
 | 
						|
 | 
						|
This is almost always a problem with your SSL certificates.  See:
 | 
						|
  https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html
 | 
						|
 | 
						|
Once fixed, just rerun scripts/setup/install; it'll pick up from here!
 | 
						|
 | 
						|
EOF
 | 
						|
        exit 1
 | 
						|
    )
 | 
						|
    service nginx restart
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$has_appserver" = 0 ]; then
 | 
						|
    "$ZULIP_PATH"/scripts/setup/generate_secrets.py --production
 | 
						|
    if [ -z "$NO_OVERWRITE_SETTINGS" ] || ! [ -e "/etc/zulip/settings.py" ]; then
 | 
						|
        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
 | 
						|
    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 ]; then
 | 
						|
    # Cut off stdin because a bug in the Debian packaging for camo
 | 
						|
    # causes our stdin to leak to the daemon, which can cause tools
 | 
						|
    # invoking the installer to hang.
 | 
						|
    # TODO: fix in Debian too.
 | 
						|
    service camo restart </dev/null
 | 
						|
fi
 | 
						|
 | 
						|
if [ "$has_rabbit" = 0 ]; then
 | 
						|
    if ! rabbitmqctl status >/dev/null; then
 | 
						|
        set +x
 | 
						|
        cat <<EOF
 | 
						|
 | 
						|
RabbitMQ seems to not have started properly after the installation process.
 | 
						|
Often this is caused by misconfigured /etc/hosts in virtualized environments.
 | 
						|
For more information, see:
 | 
						|
  https://github.com/zulip/zulip/issues/53#issuecomment-143805121
 | 
						|
 | 
						|
EOF
 | 
						|
        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
 | 
						|
    chown zulip:zulip /var/run/supervisor.sock
 | 
						|
fi
 | 
						|
 | 
						|
if [ -n "$NO_INIT_DB" ]; then
 | 
						|
    set +x
 | 
						|
    cat <<EOF
 | 
						|
 | 
						|
 Success!
 | 
						|
 | 
						|
 Stopping because --no-init-db was passed.  To complete the installation, run:
 | 
						|
 | 
						|
   su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database'
 | 
						|
EOF
 | 
						|
    exit 0
 | 
						|
fi
 | 
						|
 | 
						|
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database --quiet'
 | 
						|
 | 
						|
su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'
 |