mirror of https://github.com/zulip/zulip.git
417 lines
16 KiB
Markdown
417 lines
16 KiB
Markdown
# Deployment options
|
|
|
|
The default Zulip installation instructions will install a complete
|
|
Zulip server, with all of the services it needs, on a single machine.
|
|
|
|
For production deployment, however, it's common to want to do
|
|
something more complicated. This page documents the options for doing so.
|
|
|
|
## Installing Zulip from Git
|
|
|
|
To install a development version of Zulip from Git, just clone the Git
|
|
repository from GitHub:
|
|
|
|
```bash
|
|
# First, install Git if you don't have it installed already
|
|
sudo apt install git
|
|
git clone https://github.com/zulip/zulip.git zulip-server-git
|
|
```
|
|
|
|
and then
|
|
[continue the normal installation instructions](install.md#step-2-install-zulip).
|
|
You can also [upgrade Zulip from Git](upgrade.md#upgrading-from-a-git-repository).
|
|
|
|
The most common use case for this is upgrading to `main` to get a
|
|
feature that hasn't made it into an official release yet (often
|
|
support for a new base OS release). See [upgrading to
|
|
main][upgrade-to-main] for notes on how `main` works and the
|
|
support story for it, and [upgrading to future
|
|
releases][upgrade-to-future-release] for notes on upgrading Zulip
|
|
afterwards.
|
|
|
|
In particular, we are always very glad to investigate problems with
|
|
installing Zulip from `main`; they are rare and help us ensure that
|
|
our next major release has a reliable install experience.
|
|
|
|
[upgrade-to-main]: modify.md#upgrading-to-main
|
|
[upgrade-to-future-release]: modify.md#upgrading-to-future-releases
|
|
|
|
## Zulip in Docker
|
|
|
|
Zulip has an officially supported, experimental
|
|
[docker image](https://github.com/zulip/docker-zulip). Please note
|
|
that Zulip's [normal installer](install.md) has been
|
|
extremely reliable for years, whereas the Docker image is new and has
|
|
rough edges, so we recommend the normal installer unless you have a
|
|
specific reason to prefer Docker.
|
|
|
|
## Zulip installer details
|
|
|
|
The [Zulip installer](install.md) does the following:
|
|
|
|
- Creates the `zulip` user, which the various Zulip servers will run as.
|
|
- Creates `/home/zulip/deployments/`, which the Zulip code for this
|
|
deployment (and future deployments when you upgrade) goes into. At the
|
|
very end of the install process, the script moves the Zulip code tree
|
|
it's running from (which you unpacked from a tarball above) to a
|
|
directory there, and makes `/home/zulip/deployments/current` as a
|
|
symbolic link to it.
|
|
- Installs Zulip's various dependencies.
|
|
- Configures the various third-party services Zulip uses, including
|
|
PostgreSQL, RabbitMQ, Memcached and Redis.
|
|
- Initializes Zulip's database.
|
|
|
|
### Advanced installer options
|
|
|
|
The Zulip installer supports the following advanced installer options
|
|
as well as those mentioned in the
|
|
[install](install.md#installer-options) documentation:
|
|
|
|
- `--postgresql-version`: Sets the version of PostgreSQL that will be
|
|
installed. We currently support PostgreSQL 12, 13, 14, 15, and 16, with 16
|
|
being the default.
|
|
|
|
- `--postgresql-database-name=exampledbname`: With this option, you
|
|
can customize the default database name. If you do not set this. The
|
|
default database name will be `zulip`. This setting can only be set
|
|
on the first install.
|
|
|
|
- `--postgresql-database-user=exampledbuser`: With this option, you
|
|
can customize the default database user. If you do not set this. The
|
|
default database user will be `zulip`. This setting can only be set
|
|
on the first install.
|
|
|
|
- `--postgresql-missing-dictionaries`: Set
|
|
`postgresql.missing_dictionaries` ([docs][missing-dicts]) in the
|
|
Zulip settings, which omits some configuration needed for full-text
|
|
indexing. This should be used with [cloud managed databases like
|
|
RDS](#using-zulip-with-amazon-rds-as-the-database). This option
|
|
conflicts with `--no-overwrite-settings`.
|
|
|
|
- `--no-init-db`: This option instructs the installer to not do any
|
|
database initialization. This should be used when you already have a
|
|
Zulip database.
|
|
|
|
- `--no-overwrite-settings`: This option preserves existing
|
|
`/etc/zulip` configuration files.
|
|
|
|
[missing-dicts]: system-configuration.md#missing_dictionaries
|
|
|
|
## Installing on an existing server
|
|
|
|
Zulip's installation process assumes it is the only application
|
|
running on the server; though installing alongside other applications
|
|
is not recommended, we do have [some notes on the
|
|
process](install-existing-server.md).
|
|
|
|
## Deployment hooks
|
|
|
|
Zulip's upgrades have a hook system which allows for arbitrary
|
|
user-configured actions to run before and after an upgrade; see the
|
|
[upgrading documentation](upgrade.md#deployment-hooks) for details on
|
|
how to write your own.
|
|
|
|
### Zulip message deploy hook
|
|
|
|
Zulip can use its deploy hooks to send a message immediately before and after
|
|
conducting an upgrade. To configure this:
|
|
|
|
1. Add `, zulip::hooks::zulip_notify` to the `puppet_classes` line in
|
|
`/etc/zulip/zulip.conf`
|
|
1. Add a `[zulip_notify]` section to `/etc/zulip/zulip.conf`:
|
|
```ini
|
|
[zulip_notify]
|
|
bot_email = your-bot@zulip.example.com
|
|
server = zulip.example.com
|
|
stream = deployments
|
|
```
|
|
1. Add the [api key](https://zulip.com/api/api-keys#get-a-bots-api-key) for the
|
|
bot user in `/etc/zulip/zulip-secrets.conf` as `zulip_release_api_key`:
|
|
```ini
|
|
# Replace with your own bot's token, found in the Zulip UI
|
|
zulip_release_api_key = abcd1234E6DK0F7pNSqaMSuzd8C5i7Eu
|
|
```
|
|
1. As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`.
|
|
|
|
### Sentry deploy hook
|
|
|
|
Zulip can use its deploy hooks to create [Sentry
|
|
releases][sentry-release], which can help associate Sentry [error
|
|
logging][sentry-error] with specific releases. If you are deploying
|
|
Zulip from Git, it can be aware of which Zulip commits are associated
|
|
with the release, and help identify which commits might be relevant to
|
|
an error.
|
|
|
|
To do so:
|
|
|
|
1. Enable [Sentry error logging][sentry-error].
|
|
2. Add a new [internal Sentry integration][sentry-internal] named
|
|
"Release annotator".
|
|
3. Grant the internal integration the [permissions][sentry-perms] of
|
|
"Admin" on "Release".
|
|
4. Add `, zulip::hooks::sentry` to the `puppet_classes` line in `/etc/zulip/zulip.conf`
|
|
5. Add a `[sentry]` section to `/etc/zulip/zulip.conf`:
|
|
```ini
|
|
[sentry]
|
|
organization = your-organization-name
|
|
project = your-project-name
|
|
```
|
|
6. Add the [authentication token][sentry-tokens] for your internal Sentry integration
|
|
to your `/etc/zulip/zulip-secrets.conf`:
|
|
```ini
|
|
# Replace with your own token, found in Sentry
|
|
sentry_release_auth_token = 6c12f890c1c864666e64ee9c959c4552b3de473a076815e7669f53793fa16afc
|
|
```
|
|
7. As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`.
|
|
|
|
If you are deploying Zulip from Git, you will also need to:
|
|
|
|
1. In your Zulip project, add the [GitHub integration][sentry-github].
|
|
2. Configure the `zulip/zulip` GitHub project for your Sentry project.
|
|
You should do this even if you are deploying a private fork of
|
|
Zulip.
|
|
3. Additionally grant the internal integration "Read & Write" on
|
|
"Organization"; this is necessary to associate the commits with the
|
|
release.
|
|
|
|
[sentry-release]: https://docs.sentry.io/product/releases/
|
|
[sentry-error]: ../subsystems/logging.md#sentry-error-logging
|
|
[sentry-github]: https://docs.sentry.io/product/integrations/source-code-mgmt/github/
|
|
[sentry-internal]: https://docs.sentry.io/product/integrations/integration-platform/internal-integration/
|
|
[sentry-perms]: https://docs.sentry.io/product/integrations/integration-platform/#permissions
|
|
[sentry-tokens]: https://docs.sentry.io/product/integrations/integration-platform/internal-integration#auth-tokens
|
|
|
|
## Running Zulip's service dependencies on different machines
|
|
|
|
Zulip has full support for each top-level service living on its own
|
|
machine.
|
|
|
|
You can configure remote servers for PostgreSQL, RabbitMQ, Redis,
|
|
in `/etc/zulip/settings.py`; just search for the service name in that
|
|
file and you'll find inline documentation in comments for how to
|
|
configure it.
|
|
|
|
Since some of these services require some configuration on the node
|
|
itself (e.g. installing our PostgreSQL extensions), we have designed
|
|
the Puppet configuration that Zulip uses for installing and upgrading
|
|
configuration to be completely modular.
|
|
|
|
For example, to install a Zulip Redis server on a machine, you can run
|
|
the following after unpacking a Zulip production release tarball:
|
|
|
|
```bash
|
|
env PUPPET_CLASSES=zulip::profile::redis ./scripts/setup/install
|
|
```
|
|
|
|
All puppet modules under `zulip::profile` are allowed to be configured
|
|
stand-alone on a host. You can see most likely manifests you might
|
|
want to choose in the list of includes in [the main manifest for the
|
|
default all-in-one Zulip server][standalone.pp], though it's also
|
|
possible to subclass some of the lower-level manifests defined in that
|
|
directory if you want to customize. A good example of doing this is
|
|
in the [zulip_ops Puppet configuration][zulipchat-puppet] that we use
|
|
as part of managing chat.zulip.org and zulip.com.
|
|
|
|
[standalone.pp]: https://github.com/zulip/zulip/blob/main/puppet/zulip/manifests/profile/standalone.pp
|
|
[zulipchat-puppet]: https://github.com/zulip/zulip/tree/main/puppet/zulip_ops/manifests
|
|
|
|
### Using Zulip with Amazon RDS as the database
|
|
|
|
You can use DBaaS services like Amazon RDS for the Zulip database.
|
|
The experience is slightly degraded, in that most DBaaS provides don't
|
|
include useful dictionary files in their installations and don't
|
|
provide a way to provide them yourself, resulting in a degraded
|
|
[full-text search](../subsystems/full-text-search.md) experience
|
|
around issues dictionary files are relevant (e.g. stemming).
|
|
|
|
You also need to pass some extra options to the Zulip installer in
|
|
order to avoid it throwing an error when Zulip attempts to configure
|
|
the database's dictionary files for full-text search; the details are
|
|
below.
|
|
|
|
#### Step 1: Set up Zulip
|
|
|
|
Follow the [standard instructions](install.md), with one
|
|
change. When running the installer, pass the `--no-init-db`
|
|
flag, e.g.:
|
|
|
|
```bash
|
|
sudo -s # If not already root
|
|
./zulip-server-*/scripts/setup/install --certbot \
|
|
--email=YOUR_EMAIL --hostname=YOUR_HOSTNAME \
|
|
--no-init-db --postgresql-missing-dictionaries
|
|
```
|
|
|
|
The script also installs and starts PostgreSQL on the server by
|
|
default. We don't need it, so run the following command to
|
|
stop and disable the local PostgreSQL server.
|
|
|
|
```bash
|
|
sudo service postgresql stop
|
|
sudo update-rc.d postgresql disable
|
|
```
|
|
|
|
This complication will be removed in a future version.
|
|
|
|
#### Step 2: Create the PostgreSQL database
|
|
|
|
Access an administrative `psql` shell on your PostgreSQL database, and
|
|
run the commands in `scripts/setup/create-db.sql` to:
|
|
|
|
- Create a database called `zulip`.
|
|
- Create a user called `zulip`.
|
|
- Now log in with the `zulip` user to create a schema called
|
|
`zulip` in the `zulip` database. You might have to grant `create`
|
|
privileges first for the `zulip` user to do this.
|
|
|
|
Depending on how authentication works for your PostgreSQL installation,
|
|
you may also need to set a password for the Zulip user, generate a
|
|
client certificate, or similar; consult the documentation for your
|
|
database provider for the available options.
|
|
|
|
#### Step 3: Configure Zulip to use the PostgreSQL database
|
|
|
|
In `/etc/zulip/settings.py` on your Zulip server, configure the
|
|
following settings with details for how to connect to your PostgreSQL
|
|
server. Your database provider should provide these details.
|
|
|
|
- `REMOTE_POSTGRES_HOST`: Name or IP address of the PostgreSQL server.
|
|
- `REMOTE_POSTGRES_PORT`: Port on the PostgreSQL server.
|
|
- `REMOTE_POSTGRES_SSLMODE`: SSL Mode used to connect to the server.
|
|
|
|
If you're using password authentication, you should specify the
|
|
password of the `zulip` user in /etc/zulip/zulip-secrets.conf as
|
|
follows:
|
|
|
|
```ini
|
|
postgres_password = abcd1234
|
|
```
|
|
|
|
Now complete the installation by running the following commands.
|
|
|
|
```bash
|
|
# Ask Zulip installer to initialize the PostgreSQL database.
|
|
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database'
|
|
|
|
# And then generate a realm creation link:
|
|
su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'
|
|
```
|
|
|
|
## Using an alternate port
|
|
|
|
If you'd like your Zulip server to use an HTTPS port other than 443, you can
|
|
configure that as follows:
|
|
|
|
1. Edit `EXTERNAL_HOST` in `/etc/zulip/settings.py`, which controls how
|
|
the Zulip server reports its own URL, and restart the Zulip server
|
|
with `/home/zulip/deployments/current/scripts/restart-server`.
|
|
1. Add the following block to `/etc/zulip/zulip.conf`:
|
|
|
|
```ini
|
|
[application_server]
|
|
nginx_listen_port = 12345
|
|
```
|
|
|
|
1. As root, run
|
|
`/home/zulip/deployments/current/scripts/zulip-puppet-apply`. This
|
|
will convert Zulip's main `nginx` configuration file to use your new
|
|
port.
|
|
|
|
We also have documentation for a Zulip server [using HTTP][using-http] for use
|
|
behind reverse proxies.
|
|
|
|
[using-http]: reverse-proxies.md#configuring-zulip-to-allow-http
|
|
|
|
## Customizing the outgoing HTTP proxy
|
|
|
|
To protect against [SSRF][ssrf], Zulip 4.8 and above default to
|
|
routing all outgoing HTTP and HTTPS traffic through
|
|
[Smokescreen][smokescreen], an HTTP `CONNECT` proxy; this includes
|
|
outgoing webhooks, website previews, and mobile push notifications.
|
|
By default, the Camo image proxy will be automatically configured to
|
|
use a custom outgoing proxy, but does not use Smokescreen by default
|
|
because Camo includes similar logic to deny access to private
|
|
subnets. You can [override][proxy.enable_for_camo] this default
|
|
configuration if desired.
|
|
|
|
To use a custom outgoing proxy:
|
|
|
|
1. Add the following block to `/etc/zulip/zulip.conf`, substituting in
|
|
your proxy's hostname/IP and port:
|
|
|
|
```ini
|
|
[http_proxy]
|
|
host = 127.0.0.1
|
|
port = 4750
|
|
```
|
|
|
|
1. As root, run
|
|
`/home/zulip/deployments/current/scripts/zulip-puppet-apply`. This
|
|
will reconfigure and restart Zulip.
|
|
|
|
If you have a deployment with multiple frontend servers, or wish to
|
|
install Smokescreen on a separate host, you can apply the
|
|
`zulip::profile::smokescreen` Puppet class on that host, and follow
|
|
the above steps, setting the `[http_proxy]` block to point to that
|
|
host.
|
|
|
|
If you wish to disable the outgoing proxy entirely, follow the above
|
|
steps, configuring an empty `host` value.
|
|
|
|
Optionally, you can also configure the [Smokescreen ACL
|
|
list][smokescreen-acls]. By default, Smokescreen denies access to all
|
|
[non-public IP
|
|
addresses](https://en.wikipedia.org/wiki/Private_network), including
|
|
127.0.0.1, but allows traffic to all public Internet hosts.
|
|
|
|
In Zulip 4.7 and older, to enable SSRF protection via Smokescreen, you
|
|
will need to explicitly add the `zulip::profile::smokescreen` Puppet
|
|
class, and configure the `[http_proxy]` block as above.
|
|
|
|
[proxy.enable_for_camo]: system-configuration.md#enable_for_camo
|
|
[smokescreen]: https://github.com/stripe/smokescreen
|
|
[smokescreen-acls]: https://github.com/stripe/smokescreen#acls
|
|
[ssrf]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
|
|
|
|
### S3 file storage requests and outgoing proxies
|
|
|
|
By default, the [S3 file storage backend][s3] bypasses the Smokescreen
|
|
proxy, because when running on EC2 it may require metadata from the
|
|
IMDS metadata endpoint, which resides on the internal IP address
|
|
169.254.169.254 and would thus be blocked by Smokescreen.
|
|
|
|
If your S3-compatible storage backend requires use of Smokescreen or
|
|
some other proxy, you can override this default by setting
|
|
`S3_SKIP_PROXY = False` in `/etc/zulip/settings.py`.
|
|
|
|
[s3]: upload-backends.md#s3-backend-configuration
|
|
|
|
## PostgreSQL warm standby
|
|
|
|
Zulip's configuration allows for [warm standby database
|
|
replicas][warm-standby] as a disaster recovery solution; see the
|
|
linked PostgreSQL documentation for details on this type of
|
|
deployment. Zulip's configuration builds on top of `wal-g`, our
|
|
[streaming database backup solution][wal-g], and thus requires that it
|
|
be configured for the primary and all secondary warm standby replicas.
|
|
|
|
In addition to having `wal-g` backups configured, warm standby
|
|
replicas should configure the hostname of their primary replica, and
|
|
username to use for replication, in `/etc/zulip/zulip.conf`:
|
|
|
|
```ini
|
|
[postgresql]
|
|
replication_user = replicator
|
|
replication_primary = hostname-of-primary.example.com
|
|
```
|
|
|
|
The `postgres` user on the replica will need to be able to
|
|
authenticate as the `replication_user` user, which may require further
|
|
configuration of `pg_hba.conf` and client certificates on the replica.
|
|
If you are using password authentication, you can set a
|
|
`postgresql_replication_password` secret in
|
|
`/etc/zulip/zulip-secrets.conf`.
|
|
|
|
[warm-standby]: https://www.postgresql.org/docs/current/warm-standby.html
|
|
[wal-g]: export-and-import.md#database-only-backup-tools
|