mirror of
https://github.com/zulip/zulip.git
synced 2026-06-18 21:01:52 +08:00
Rather than require a configuration option, detect the `tsearch_data`
error, in conjunction with a remote PostgreSQL host, and warn and
continue. It is pretty much impossible to arrive at that combination
and then _not_ want to try again with the flag, so we should handle
that degradation gracefully, instead of requiring an explicit
install and configuration flag.
(cherry picked from commit 1f3aed14a5)
762 lines
26 KiB
Bash
Executable File
762 lines
26 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -e
|
||
|
||
usage() {
|
||
# A subset of this documentation also appears in docs/production/install.md
|
||
cat <<'EOF'
|
||
Usage:
|
||
install --hostname=zulip.example.com --email=zulip-admin@example.com [options...]
|
||
install --help
|
||
|
||
Options:
|
||
--hostname=zulip.example.com
|
||
The user-accessible domain name for this Zulip server, i.e.,
|
||
what users will type in their web browser. Required, unless
|
||
--no-init-db or --puppet-classes is set, and --certbot is not.
|
||
|
||
--email=zulip-admin@example.com
|
||
The email address of the person or team who should get support
|
||
and error emails from this Zulip server. Required, unless
|
||
--no-init-db or --puppet-classes is set and --certbot is not.
|
||
|
||
--certbot
|
||
Obtains a free SSL certificate for the server using Certbot,
|
||
https://certbot.eff.org/ Recommended. Conflicts with --self-signed-cert.
|
||
--self-signed-cert
|
||
Generate a self-signed SSL certificate for the server. This isn’t suitable for
|
||
production use, but may be convenient for testing. Conflicts with --certbot.
|
||
|
||
--postgresql-database-name=zulip
|
||
Sets the PostgreSQL database name.
|
||
--postgresql-database-user=zulip
|
||
Sets the PostgreSQL database user.
|
||
--postgresql-version=17
|
||
Sets the version of PostgreSQL that will be installed.
|
||
|
||
--no-init-db
|
||
Does not do any database initialization; use when you already have a Zulip
|
||
database.
|
||
--puppet-classes
|
||
Comma-separated list of Puppet classes to install; defaults to
|
||
'zulip:::profile::standalone'. Implies --no-init-db.
|
||
|
||
--no-overwrite-settings
|
||
Preserve existing `/etc/zulip` configuration files.
|
||
--no-dist-upgrade
|
||
Skip the initial `apt-get dist-upgrade`.
|
||
|
||
--push-notifications
|
||
With this option, the Zulip installer registers your server for the Mobile
|
||
Push Notification Service, and sets up the initial default configuration.
|
||
You will be immediately prompted to agree to the Terms of Service, and your
|
||
server will be registered at the end of the installation process.
|
||
--no-push-notifications
|
||
Disable push notifications registration (the default if neither
|
||
flag is provided).
|
||
|
||
--no-submit-usage-statistics
|
||
If you enable push notifications, by default your server
|
||
will submit basic metadata (required for billing and for
|
||
determining free plan eligibility), as well as aggregate usage
|
||
statistics. You can disable submitting usage statistics by passing
|
||
this flag.
|
||
If push notifications are not enabled, data won't be submitted, so
|
||
this flag is redundant.
|
||
|
||
--agree-to-terms-of-service
|
||
If you enable push notifications, you can pass this flag to indicate
|
||
that you have read and agree to the Zulip Terms of Service:
|
||
<https://zulip.com/policies/terms>.
|
||
This skips the Terms of Service prompt, allowing for running the installer
|
||
with --push-notifications in scripts without requiring user input.
|
||
|
||
|
||
EOF
|
||
}
|
||
|
||
system_requirements_failure() {
|
||
set +x
|
||
echo >&2
|
||
cat >&2
|
||
cat <<EOF >&2
|
||
|
||
For more information, see:
|
||
https://zulip.readthedocs.io/en/latest/production/requirements.html
|
||
EOF
|
||
exit 1
|
||
}
|
||
|
||
# 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,hostname:,email:,certbot,self-signed-cert,cacert:,postgresql-database-name:,postgresql-database-user:,postgresql-version:,no-init-db,puppet-classes:,no-overwrite-settings,no-dist-upgrade,push-notifications,no-push-notifications,no-submit-usage-statistics,agree-to-terms-of-service -n "$0" -- "$@")"
|
||
|
||
eval "set -- $args"
|
||
while true; do
|
||
case "$1" in
|
||
--help)
|
||
usage
|
||
exit 0
|
||
;;
|
||
|
||
--hostname)
|
||
EXTERNAL_HOST="$2"
|
||
shift
|
||
shift
|
||
;;
|
||
--email)
|
||
ZULIP_ADMINISTRATOR="$2"
|
||
shift
|
||
shift
|
||
;;
|
||
|
||
--certbot)
|
||
USE_CERTBOT=1
|
||
shift
|
||
;;
|
||
--self-signed-cert)
|
||
SELF_SIGNED_CERT=1
|
||
shift
|
||
;;
|
||
--postgresql-database-name)
|
||
POSTGRESQL_DATABASE_NAME="$2"
|
||
shift
|
||
shift
|
||
;;
|
||
--postgresql-database-user)
|
||
POSTGRESQL_DATABASE_USER="$2"
|
||
shift
|
||
shift
|
||
;;
|
||
--postgresql-version)
|
||
POSTGRESQL_VERSION="$2"
|
||
shift
|
||
shift
|
||
;;
|
||
--no-init-db)
|
||
NO_INIT_DB=1
|
||
shift
|
||
;;
|
||
--puppet-classes)
|
||
PUPPET_CLASSES="$2"
|
||
NO_INIT_DB=1
|
||
shift
|
||
shift
|
||
;;
|
||
|
||
--no-overwrite-settings)
|
||
NO_OVERWRITE_SETTINGS=1
|
||
shift
|
||
;;
|
||
--no-dist-upgrade)
|
||
NO_DIST_UPGRADE=1
|
||
shift
|
||
;;
|
||
--push-notifications)
|
||
if [ -n "$NO_PUSH_NOTIFICATIONS" ]; then
|
||
echo "error: --push-notifications and --no-push-notifications are incompatible." >&2
|
||
exit 1
|
||
fi
|
||
PUSH_NOTIFICATIONS=1
|
||
shift
|
||
;;
|
||
--no-push-notifications)
|
||
if [ -n "$PUSH_NOTIFICATIONS" ]; then
|
||
echo "error: --push-notifications and --no-push-notifications are incompatible." >&2
|
||
exit 1
|
||
fi
|
||
NO_PUSH_NOTIFICATIONS=1
|
||
shift
|
||
;;
|
||
--no-submit-usage-statistics)
|
||
NO_SUBMIT_USAGE_STATISTICS=1
|
||
shift
|
||
;;
|
||
--agree-to-terms-of-service)
|
||
AGREE_TO_TERMS_OF_SERVICE_FLAG=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.
|
||
read -r -a ADDITIONAL_PACKAGES <<<"${ADDITIONAL_PACKAGES:-}"
|
||
# Comma-separated list of Puppet manifests to install. The default is
|
||
# zulip::profile::standalone for an all-in-one system or
|
||
# zulip::profile::docker for Docker. Use
|
||
# e.g. zulip::profile::app_frontend for a Zulip frontend server.
|
||
PUPPET_CLASSES="${PUPPET_CLASSES:-zulip::profile::standalone}"
|
||
POSTGRESQL_VERSION="${POSTGRESQL_VERSION:-17}"
|
||
|
||
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 zerver/checks.py
|
||
echo 'error: The example hostname and email must be replaced with real values.' >&2
|
||
echo >&2
|
||
usage >&2
|
||
exit 1
|
||
fi
|
||
|
||
case "$POSTGRESQL_VERSION" in
|
||
[0-9] | [0-9].* | 1[0-3] | 1[0-3].*)
|
||
echo "error: PostgreSQL 14 or newer is required." >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
if [ -z "$PUSH_NOTIFICATIONS" ] && [ -z "$NO_PUSH_NOTIFICATIONS" ]; then
|
||
# Unless specified, we default to --no-push-notifications
|
||
NO_PUSH_NOTIFICATIONS=1
|
||
fi
|
||
|
||
# We set these to Python-style True/False string values, for easy
|
||
# insertion into the settings.py file.
|
||
if [ -n "$PUSH_NOTIFICATIONS" ]; then
|
||
SERVICE_MOBILE_PUSH="True"
|
||
|
||
# --push-notifications also enables SUBMIT_USAGE_STATISTICS, unless the user
|
||
# explicitly opted out by passing --no-submit-usage-statistics.
|
||
if [ -n "$NO_SUBMIT_USAGE_STATISTICS" ]; then
|
||
SERVICE_SUBMIT_USAGE_STATISTICS="False"
|
||
else
|
||
SERVICE_SUBMIT_USAGE_STATISTICS="True"
|
||
fi
|
||
else
|
||
SERVICE_MOBILE_PUSH="False"
|
||
# SUBMIT_USAGE_STATISTICS without PUSH_NOTIFICATIONS is an unusual
|
||
# configuration that we don't need to offer in the installer.
|
||
SERVICE_SUBMIT_USAGE_STATISTICS="False"
|
||
fi
|
||
|
||
# ToS acceptance needs to be ensured if --push-notifications is passed.
|
||
if [ -n "$PUSH_NOTIFICATIONS" ]; then
|
||
# If the user provided the --agree-to-terms-of-service flag, we can just proceed.
|
||
if [ -n "$AGREE_TO_TERMS_OF_SERVICE_FLAG" ]; then
|
||
PUSH_NOTIFICATIONS_SERVICE_TOS_AGREED=1
|
||
echo "Push notifications will be enabled, as you agreed to the Zulip Terms of Service"
|
||
echo "by passing the --agree-to-terms-of-service flag."
|
||
sleep 2
|
||
else
|
||
# If user asked for push notifications, prompt for ToS acceptance.
|
||
echo
|
||
echo "You chose to register your server for the Mobile Push Notifications Service."
|
||
echo "Doing so will share basic metadata with the service's maintainers, including:"
|
||
echo
|
||
echo "* The server's configured hostname: $EXTERNAL_HOST"
|
||
echo "* The server's configured contact email address: $ZULIP_ADMINISTRATOR"
|
||
echo "* Basic metadata about each organization hosted by the server; see:"
|
||
echo " <https://zulip.com/doc-permalinks/basic-metadata>"
|
||
if [ -z "$NO_SUBMIT_USAGE_STATISTICS" ]; then
|
||
echo "* The server's usage statistics; see:"
|
||
echo " <https://zulip.com/doc-permalinks/usage-statistics>"
|
||
fi
|
||
echo
|
||
echo "For details on why a centralized push notification service is necessary, see:"
|
||
echo " <https://zulip.com/doc-permalinks/why-service>"
|
||
echo
|
||
echo "Use of this service is governed by the Zulip Terms of Service:"
|
||
echo " <https://zulip.com/policies/terms>"
|
||
echo
|
||
read -r -p "Do you want to agree to the Zulip Terms of Service and proceed? [Y/n] " tos_prompt
|
||
echo
|
||
|
||
# Normalize the user’s response to lowercase.
|
||
case "${tos_prompt,,}" in
|
||
"" | y | yes)
|
||
echo "Great! Push notifications will be enabled; continuing with installation..."
|
||
PUSH_NOTIFICATIONS_SERVICE_TOS_AGREED=1
|
||
sleep 2
|
||
;;
|
||
*)
|
||
echo "In order to enable push notifications, you must agree to the Terms of Service."
|
||
echo "If you do not want to enable push notifications, run the command without the --push-notifications flag."
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
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.
|
||
export LC_ALL="C.UTF-8"
|
||
export LANG="C.UTF-8"
|
||
export LANGUAGE="C.UTF-8"
|
||
|
||
# Force a known path; this fixes problems on Debian where `su` from
|
||
# non-root may not adjust `$PATH` to root's.
|
||
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||
|
||
# Check for a supported OS release.
|
||
if [ -f /etc/os-release ]; then
|
||
os_info="$(
|
||
. /etc/os-release
|
||
printf '%s\n' "$ID" "$ID_LIKE" "$VERSION_ID" "$VERSION_CODENAME"
|
||
)"
|
||
{
|
||
read -r os_id
|
||
read -r os_id_like
|
||
read -r os_version_id
|
||
read -r os_version_codename || true
|
||
} <<<"$os_info"
|
||
case " $os_id $os_id_like " in
|
||
*' debian '*)
|
||
package_system="apt"
|
||
;;
|
||
*' rhel '*)
|
||
package_system="yum"
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
if ! "$ZULIP_PATH/scripts/lib/supported-os"; then
|
||
system_requirements_failure <<EOF
|
||
Unsupported OS release: $os_id $os_version_id
|
||
|
||
Zulip in production is supported only on:
|
||
- Debian 12
|
||
- Debian 13
|
||
- Ubuntu 22.04 LTS
|
||
- Ubuntu 24.04 LTS
|
||
EOF
|
||
fi
|
||
|
||
machine="$(uname -m)"
|
||
if [ "$machine" != x86_64 ] && [ "$machine" != aarch64 ]; then
|
||
system_requirements_failure <<EOF
|
||
Unsupported CPU architecture: $machine (expected x86_64 or aarch64).
|
||
EOF
|
||
fi
|
||
|
||
dpkg_architecture="$(dpkg --print-architecture)"
|
||
if [ "$dpkg_architecture" != amd64 ] && [ "$dpkg_architecture" != arm64 ]; then
|
||
system_requirements_failure <<EOF
|
||
Unsupported OS architecture: $dpkg_architecture (expected amd64 or arm64).
|
||
EOF
|
||
fi
|
||
|
||
has_universe() {
|
||
apt-cache policy \
|
||
| grep -q "^ release v=$os_version_id,o=Ubuntu,a=$os_version_codename,n=$os_version_codename,l=Ubuntu,c=universe"
|
||
}
|
||
|
||
if [ "$os_id" = ubuntu ] && ! has_universe && ! { apt-get update && has_universe; }; then
|
||
system_requirements_failure <<EOF
|
||
You must enable the Ubuntu Universe repository before installing
|
||
Zulip. You can do this with:
|
||
|
||
sudo add-apt-repository universe
|
||
sudo apt update
|
||
EOF
|
||
fi
|
||
|
||
case ",$PUPPET_CLASSES," in
|
||
*,zulip::profile::standalone,* | *,zulip::profile::postgresql,*)
|
||
if [ "$package_system" = apt ]; then
|
||
# We're going to install PostgreSQL from the PostgreSQL apt
|
||
# repository; this may conflict with the existing PostgreSQL.
|
||
OTHER_PG="$(dpkg --get-selections \
|
||
| grep -E '^postgresql-[0-9]+\s+install$' \
|
||
| grep -v "^postgresql-$POSTGRESQL_VERSION\b" \
|
||
| cut -f 1)" || true
|
||
if [ -n "$OTHER_PG" ]; then
|
||
INDENTED="${OTHER_PG//$'\n'/$'\n' }"
|
||
SPACED="${OTHER_PG//$'\n'/ }"
|
||
cat <<EOF
|
||
|
||
The following PostgreSQL servers were found to already be installed:
|
||
|
||
$INDENTED
|
||
|
||
Zulip needs to install PostgreSQL $POSTGRESQL_VERSION, but does not wish
|
||
to uninstall existing databases in order to do so. Remove all other
|
||
PostgreSQL servers manually before running the installer:
|
||
|
||
sudo apt-get remove $SPACED
|
||
|
||
EOF
|
||
exit 1
|
||
fi
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
# Check for at least ~1.86GB of RAM before starting installation;
|
||
# otherwise users will find out about insufficient RAM via weird
|
||
# errors like a segfault running `pip install`.
|
||
# Additionally, some AWS images that are advertised to be 2 GB
|
||
# are actually 1880000B in size.
|
||
mem_kb=$(head -n1 /proc/meminfo | awk '{print $2}')
|
||
if [ "$mem_kb" -lt 1860000 ]; 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
|
||
|
||
# Anything under 5GB, we recommended allocating 2GB of swap. Error
|
||
# out if there's no swap.
|
||
swap_kb=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
|
||
if [ "$mem_kb" -lt 5000000 ] && [ "$swap_kb" -eq 0 ]; then
|
||
set +x
|
||
echo -e '\033[0;31m' >&2
|
||
echo "No swap allocated; when running with < 5GB of RAM, we recommend at least 2GB of swap." >&2
|
||
echo "https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-22-04" >&2
|
||
echo >&2
|
||
echo -e '\033[0m' >&2
|
||
exit 1
|
||
fi
|
||
|
||
# Do package update, e.g. do `apt-get update` on Debian
|
||
if [ "$package_system" = apt ]; then
|
||
# setup-apt-repo does an `apt-get update`
|
||
"$ZULIP_PATH"/scripts/lib/setup-apt-repo
|
||
elif [ "$package_system" = yum ]; then
|
||
"$ZULIP_PATH"/scripts/lib/setup-yum-repo
|
||
fi
|
||
|
||
# Check early for missing SSL certificates
|
||
if [ "$PUPPET_CLASSES" = "zulip::profile::standalone" ] && [ -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
|
||
if [ "$package_system" = apt ]; then
|
||
apt-get -y dist-upgrade "${APT_OPTIONS[@]}"
|
||
elif [ "$package_system" = yum ]; then
|
||
# On CentOS, there is no need to do `yum -y upgrade` because `yum -y
|
||
# update` already does the same thing.
|
||
:
|
||
fi
|
||
fi
|
||
|
||
if [ "$package_system" = apt ]; then
|
||
# Note that any additions to these lists must also be added to
|
||
# `zulip::profile::base` such that the new dependency is seen by
|
||
# upgrades, as well as new installs.
|
||
if ! apt-get install -y --no-install-recommends \
|
||
python3 python3-yaml puppet git curl jq 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
|
||
elif [ "$package_system" = yum ]; then
|
||
if ! yum install -y \
|
||
python3 python3-pyyaml puppet git curl jq crudini \
|
||
"${ADDITIONAL_PACKAGES[@]}"; then
|
||
set +x
|
||
echo -e '\033[0;31m' >&2
|
||
echo "Installing packages failed; is network working?" >&2
|
||
echo >&2
|
||
echo -e '\033[0m' >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# We generate a self-signed cert even with certbot, so we can use the
|
||
# webroot authenticator, which requires nginx be set up with a
|
||
# certificate.
|
||
if [ -n "$SELF_SIGNED_CERT" ] || [ -n "$USE_CERTBOT" ]; then
|
||
"$ZULIP_PATH"/scripts/setup/generate-self-signed-cert \
|
||
--exists-ok "${EXTERNAL_HOST:-$(hostname)}"
|
||
fi
|
||
|
||
# Generate /etc/zulip/zulip.conf .
|
||
mkdir -p /etc/zulip
|
||
has_class() {
|
||
grep -qx "$1" /var/lib/puppet/classes.txt
|
||
}
|
||
|
||
# puppet apply --noop fails unless the user that it _would_ chown
|
||
# files to exists; https://tickets.puppetlabs.com/browse/PUP-3907
|
||
#
|
||
# The home directory here should match what's declared in base.pp.
|
||
id -u zulip &>/dev/null || useradd -m zulip --home-dir /home/zulip
|
||
if [ -n "$NO_OVERWRITE_SETTINGS" ] && [ -e "/etc/zulip/zulip.conf" ]; then
|
||
"$ZULIP_PATH"/scripts/zulip-puppet-apply --noop \
|
||
--write-catalog-summary \
|
||
--classfile=/var/lib/puppet/classes.txt
|
||
else
|
||
# Write out more than we need, and remove sections that are not
|
||
# applicable to the classes that are actually necessary.
|
||
cat <<EOF >/etc/zulip/zulip.conf
|
||
[machine]
|
||
puppet_classes = $PUPPET_CLASSES
|
||
deploy_type = production
|
||
|
||
[postgresql]
|
||
version = $POSTGRESQL_VERSION
|
||
EOF
|
||
|
||
"$ZULIP_PATH"/scripts/zulip-puppet-apply --noop \
|
||
--write-catalog-summary \
|
||
--classfile=/var/lib/puppet/classes.txt
|
||
|
||
# We only need the PostgreSQL version setting on database hosts,
|
||
# or hosts which talk directly to the database (e.g. application
|
||
# hosts); but we don't know if this is a database host until we
|
||
# have the catalog summary.
|
||
if (! has_class "zulip::postgresql_common" && ! has_class "zulip::postgresql_client") || [ "$package_system" != apt ]; then
|
||
crudini --del /etc/zulip/zulip.conf postgresql
|
||
fi
|
||
|
||
if [ -n "$POSTGRESQL_DATABASE_NAME" ]; then
|
||
crudini --set /etc/zulip/zulip.conf postgresql database_name "$POSTGRESQL_DATABASE_NAME"
|
||
fi
|
||
|
||
if [ -n "$POSTGRESQL_DATABASE_USER" ]; then
|
||
crudini --set /etc/zulip/zulip.conf postgresql database_user "$POSTGRESQL_DATABASE_USER"
|
||
fi
|
||
fi
|
||
|
||
if has_class "zulip::app_frontend_base"; then
|
||
# Frontend deploys use /home/zulip/deployments; without this, the
|
||
# install directory is also only readable by root.
|
||
mkdir -p /home/zulip/deployments
|
||
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
|
||
|
||
# Create and activate a virtualenv
|
||
"$deploy_path"/scripts/lib/create-production-venv "$deploy_path"
|
||
|
||
"$deploy_path"/scripts/lib/install-node
|
||
|
||
if [ -z "$NO_OVERWRITE_SETTINGS" ] || ! [ -e "/etc/zulip/settings.py" ]; then
|
||
cp -a "$deploy_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
|
||
|
||
# Set SERVICE settings based on what the user provided.
|
||
if grep -q -E "^#?\s*ZULIP_SERVICE_PUSH_NOTIFICATIONS = " /etc/zulip/settings.py; then
|
||
sed -i -E "s/^#?\s*ZULIP_SERVICE_PUSH_NOTIFICATIONS = .*/ZULIP_SERVICE_PUSH_NOTIFICATIONS = $SERVICE_MOBILE_PUSH/" /etc/zulip/settings.py
|
||
else
|
||
echo "ZULIP_SERVICE_PUSH_NOTIFICATIONS = $SERVICE_MOBILE_PUSH" >>/etc/zulip/settings.py
|
||
fi
|
||
|
||
if grep -q -E "^#?\s*ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS = " /etc/zulip/settings.py; then
|
||
sed -i -E "s/^#?\s*ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS = .*/ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS = $SERVICE_SUBMIT_USAGE_STATISTICS/" /etc/zulip/settings.py
|
||
else
|
||
echo "ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS = $SERVICE_SUBMIT_USAGE_STATISTICS" >>/etc/zulip/settings.py
|
||
fi
|
||
fi
|
||
ln -nsf /etc/zulip/settings.py "$deploy_path"/zproject/prod_settings.py
|
||
"$deploy_path"/scripts/setup/generate_secrets.py --production
|
||
else
|
||
deploy_path="$ZULIP_PATH"
|
||
fi
|
||
|
||
"$deploy_path"/scripts/zulip-puppet-apply -f
|
||
|
||
if [ "$package_system" = apt ]; then
|
||
apt-get -y --with-new-pkgs upgrade
|
||
elif [ "$package_system" = yum ]; then
|
||
# No action is required because `yum update` already does upgrade.
|
||
:
|
||
fi
|
||
|
||
if [ -n "$USE_CERTBOT" ]; then
|
||
"$deploy_path"/scripts/setup/setup-certbot \
|
||
"$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR"
|
||
fi
|
||
|
||
if has_class "zulip::nginx" && ! has_class "zulip::profile::docker"; then
|
||
# Check nginx was configured properly now that we've installed it.
|
||
# Most common failure mode is certs not having been installed.
|
||
if ! nginx -t; then
|
||
(
|
||
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
|
||
)
|
||
fi
|
||
fi
|
||
|
||
if has_class "zulip::profile::rabbitmq"; 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
|
||
fi
|
||
|
||
# Set up a basic .gitconfig for the 'zulip' user
|
||
if [ -n "$ZULIP_ADMINISTRATOR" ]; then
|
||
(
|
||
cd / # Make sure the current working directory is readable by zulip
|
||
su zulip -c "git config --global user.email $ZULIP_ADMINISTRATOR"
|
||
su zulip -c "git config --global user.name 'Zulip Server ($EXTERNAL_HOST)'"
|
||
)
|
||
fi
|
||
|
||
if ! has_class "zulip::app_frontend_base"; then
|
||
set +x
|
||
cat <<EOF
|
||
|
||
Success!
|
||
|
||
Not configuring PostgreSQL, or /home/zulip/deployments, because this
|
||
is not a front-end install.
|
||
|
||
EOF
|
||
exit 0
|
||
fi
|
||
|
||
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/deployments/current/zulip-git-version ]; then
|
||
mkdir /srv/zulip.git
|
||
chown zulip:zulip /srv/zulip.git
|
||
su zulip -c 'git clone --bare --mirror /home/zulip/deployments/current /srv/zulip.git'
|
||
su zulip -c 'cd /home/zulip/deployments/current && ./scripts/lib/update-git-upstream && ./tools/cache-zulip-git-version'
|
||
fi
|
||
|
||
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'
|
||
fi
|
||
|
||
if [ -n "$NO_INIT_DB" ]; then
|
||
set +x
|
||
cat <<EOF
|
||
|
||
Success!
|
||
|
||
Stopping because --no-init-db was passed. To complete the
|
||
installation, configure PostgreSQL by creating the database and
|
||
database user, and then run:
|
||
|
||
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database'
|
||
su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'
|
||
EOF
|
||
|
||
if [ -n "$PUSH_NOTIFICATIONS" ]; then
|
||
echo
|
||
echo "Since you specified you want to enable the push notification service, you'll also need to "
|
||
echo "manually register your server by running:"
|
||
echo
|
||
echo " su zulip -c '/home/zulip/deployments/current/manage.py register_server'"
|
||
echo
|
||
fi
|
||
exit 0
|
||
else
|
||
/home/zulip/deployments/current/scripts/setup/create-database
|
||
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database --quiet'
|
||
|
||
if [ -n "$PUSH_NOTIFICATIONS" ]; then
|
||
if [ -z "$PUSH_NOTIFICATIONS_SERVICE_TOS_AGREED" ]; then
|
||
# This should be impossible as the installation should have aborted early if the user
|
||
# passed --push-notifications without accepting the ToS. But we include this as a precaution
|
||
# to not allow future bugs to cause ToS acceptance to be skipped.
|
||
SKIP_TOS_AGREEMENT_OPTION=""
|
||
else
|
||
SKIP_TOS_AGREEMENT_OPTION="--agree-to-terms-of-service"
|
||
fi
|
||
set +x
|
||
echo "Services enabled, attempting to register server..."
|
||
set -x
|
||
|
||
# Without PYTHONUNBUFFERED=1, stdout/stderr might end up displayed not in chronological order, resulting
|
||
# in confusing output to the user.
|
||
su zulip -c "PYTHONUNBUFFERED=1 /home/zulip/deployments/current/manage.py register_server ${SKIP_TOS_AGREEMENT_OPTION}" \
|
||
|| {
|
||
set +x
|
||
echo
|
||
echo "WARNING: Server registration for push notifications failed."
|
||
echo "This does not affect the rest of your Zulip installation."
|
||
echo
|
||
echo "To enable push notifications after resolving the issue, run:"
|
||
echo " su zulip -c '/home/zulip/deployments/current/manage.py register_server'"
|
||
echo
|
||
set -x
|
||
}
|
||
fi
|
||
|
||
su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'
|
||
fi
|