docs/production/system-configuration.md
The file /etc/zulip/zulip.conf is an INI
format configuration file
used to configure properties of the system and deployment;
/etc/zulip/settings.py is used to configure the application
itself. The zulip.conf sections and settings are
described below. Changes to zulip.conf generally do not take effect
until you run zulip-puppet-apply as root:
# /home/zulip/deployments/current/scripts/zulip-puppet-apply
The zulip-puppet-apply command will display the configuration
changes it will make and prompt for you to confirm you'd like to make
those changes, before executing them (if you approve).
When a setting refers to "set to true" or "set to false", the values
true and false are canonical, but any of the following values will
be considered "true", case-insensitively:
Any other value (including the empty string) is considered false.
[machine]puppet_classesA comma-separated list of the Puppet classes to install on the server.
The most common is zulip::profile::standalone, used for a
stand-alone single-host deployment.
Components of
that include:
zulip::profile::app_frontendzulip::profile::memcachedzulip::profile::postgresqlzulip::profile::rabbitmqzulip::profile::rediszulip::profile::smokescreenIf you are using a Apache as a single-sign-on
authenticator,
you will need to add zulip::apache_sso to the list.
pgroongaSet to true if enabling the multi-language PGroonga search extension.
timesyncWhat time synchronization daemon to use; defaults to chrony, but also supports
ntpd and none. Installations should not adjust this unless they are aligning
with a fleet-wide standard of ntpd. none is only reasonable in containers
like LXC which do not allow adjustment of the clock; a Zulip server will not
function correctly without an accurate clock.
[deployment]deploy_optionsOptions passed by upgrade-zulip and upgrade-zulip-from-git into
upgrade-zulip-stage-2. These might be any of:
--skip-puppet skips doing Puppet/apt upgrades. The user will need
to run zulip-puppet-apply manually after the upgrade.--skip-migrations skips running database migrations. The
user will need to run ./manage.py migrate manually after the upgrade.--skip-purge-old-deployments skips purging old deployments;
without it, only deployments with the last two weeks are kept.Generally installations will not want to set any of these options; the
--skip-* options are primarily useful for reducing upgrade downtime
for servers that are upgraded frequently by core Zulip developers.
git_repo_urlDefault repository URL used when upgrading from a Git repository.
[application_server]http_onlyIf set to true, configures Zulip to allow HTTP access; use if Zulip is deployed behind a reverse proxy that is handling SSL/TLS termination.
nginx_listen_portSet to the port number if you prefer to listen on a port other than 443.
nginx_worker_processesAdjusts the worker_processes setting in
the nginx server. This defaults to auto, which nginx treats as the
number of available CPU cores.
nginx_worker_connectionsAdjust the worker_connections setting in
the nginx server. This defaults to 10000; increasing it allows more
concurrent connections per worker process, at the cost of more memory
consumed by nginx. This number, times the number of worker processes
(above), should be more than twice the concurrent number of users.
queue_workers_multiprocessBy default, Zulip automatically detects whether the system has enough memory to run Zulip queue processors in the higher-throughput but more multiprocess mode (or to save 1.5GiB of RAM with the multithreaded mode). The calculation is based on whether the system has enough memory (currently 3.5GiB) to run a single-server Zulip installation in the multiprocess mode.
Set explicitly to true or false to override the automatic calculation. This override is useful for Docker systems, where the above algorithm will see the host's memory size, not the container's, unless a memory limit is set, as well as when using remote servers for PostgreSQL, memcached, Redis, and RabbitMQ.
rolling_restartIf set to true, when using ./scripts/restart-server to restart
Zulip, restart the uwsgi processes one-at-a-time, instead of all at
once. This decreases the number of 502's served to clients, at the
cost of slightly increased memory usage, and the possibility that
different requests will be served by different versions of the code.
service_file_descriptor_limitThe number of file descriptors which Supervisor is configured to allow processes to use; defaults to 40000. If your Zulip deployment is very large (hundreds of thousands of concurrent users), your Django processes hit this limit and refuse connections to clients. Raising it above this default may require changing system-level limits, particularly if you are using a virtualized environment (e.g., Docker, or Proxmox LXC).
s3_memory_cache_sizeUsed only when the S3 storage backend is in use. Controls the in-memory size of the cache index; the default is 1MB, which is enough to store about 8 thousand entries.
s3_disk_cache_sizeUsed only when the S3 storage backend is in use. Controls the on-disk size of the cache contents; the default is 200MB.
s3_cache_inactive_timeUsed only when the S3 storage backend is in use.
Controls the longest amount of time an entry will be cached since last
use; the default is 30 days. Since the contents of the cache are
immutable, this serves only as a potential additional limit on the
size of the contents on disk; s3_disk_cache_size is expected to be
the primary control for cache sizing.
thumbnail_workersHow many image-thumbnailing workers to run. Defaults to 1; adding more workers can prevent the image-thumbnailing queue backlogging when large numbers of very large image files are uploaded at once. (When backlogged, image previews for images that have not yet been thumbnailed will appear as loading spinners).
email_senders_workersHow many email-sending workers to run. Defaults to 1; adding more workers can prevent email-sending queue backlogging when large numbers of very large emails are enqueued at once. This is generally only necessary on quite large installs.
nameserverWhen the S3 storage backend is in use, downloads from S3 are
proxied from nginx, whose configuration requires an explicit value of a DNS
nameserver to resolve the S3 server's hostname. Zulip defaults to using the
resolver found in /etc/resolv.conf; this setting overrides any value found
there.
uwsgi_listen_backlog_limitOverride the default uwsgi backlog of 128 connections.
uwsgi_processesOverride the default uwsgi (Django) process count. It defaults to a sliding
scale between 3 workers for hosts with under 3GB RAM, up to 16 workers for hosts
with more than 24GB of RAM.
access_log_retention_daysNumber of days of access logs to keep, for both nginx and the application. Defaults to 14 days.
katex_serverSet to a false value to disable the separate service for rendering math with LaTeX. Disabling this service will save a small amount of memory, at the cost of making math blocks significantly slower to render, to the point that using dozens of them in a single message may cause the message to fail to send.
katex_server_portSet to the port number for the KaTeX server; defaults to port 9700.
custom_ca_pathIf you use a custom certificate authority for your authentication provider, you will need to provide the certificate of the signing CA so Zulip can successfully make requests to it.
Set this to the fully-qualified path to the .crt file containing the
PEM-encoded CA certificate to trust; we suggest storing this in
/etc/zulip/.
Setting this path also means that Zulip will use the operating system's CA certificate store, and not its built-in one. There may be minor differences in trusted root CA sets.
[postgresql]effective_io_concurrencyOverride PostgreSQL's effective_io_concurrency
setting.
listen_addressesOverride PostgreSQL's listen_addresses
setting.
random_page_costOverride PostgreSQL's random_page_cost
setting.
Zulip defaults this value to 1.1, which is an appropriate value for
SSDs; if your server uses spinning disks, you should set this back to
the upstream default of 4.0.
replication_primaryOn the warm standby replicas, set to the hostname of the primary PostgreSQL server that streaming replication should be done from.
replication_userOn the warm standby replicas, set to the
username that the host should authenticate to the primary PostgreSQL
server as, for streaming replication. Authentication will be done
based on the pg_hba.conf file; if you are using password
authentication, you can set a postgresql_replication_password secret
for authentication.
skip_backupsIf set to as true value, inhibits the nightly wal-g backups which
would be taken on all non-replicated hosts and all warm standby
replicas. This is generally only set if you have
multiple warm standby replicas, in order to avoid taking multiple backups, one
per replica.
backups_disk_concurrencyNumber of concurrent disk reads to use when taking backups. Defaults to 1; you may wish to increase this if you are taking backups on a replica, so can afford to affect other disk I/O, and have an SSD which is good at parallel random reads.
backups_directoryIf S3 secrets are not configured, perform daily database backups to this path on
disk instead. It should be owned by the postgres user.
This option is not recommended for disaster recovery purposes, since unless the directory is on a different disk from the database itself, backups will likely also be lost if the database is lost. This setting can be useful if the path is on a NAS mountpoint, or if some other process copies this data off the disk; or if backups are purely for point-in-time historical analysis of recent application-level data changes.
backups_incrementalThe number of delta (incremental) database backups to take between full backups. Defaults to 0 for S3 backups, and 6 for local-disk backups.
backups_storage_classWhat storage class to use when
uploading database backups. Defaults to STANDARD, meaning "S3
standard", but many deployments will have overall lower costs if
"S3 Standard - Infrequent Access" is used, via the STANDARD_IA
value. Also supported is "S3 Reduced Redundancy", by setting
REDUCED_REDUNDANCY, but this is not suggested for production use.
backups_compression_methodWhat compression method to use when storing backups; defaults to lz4, which is
fast but does not compress particularly well. Other options are lzma, zstd,
and brotli; lzma provides the best (and slowest) compression, while zstd
and brotli are middling compromises.
missing_dictionariesIf set to a true value during initial database creation, uses PostgreSQL's
standard pg_catalog.english text search configuration, rather than Zulip's
improved set of stopwords. Has no effect after initial database construction.
ssl_ca_fileSet to the path to the PEM-encoded certificate authority used to authenticate client connections.
ssl_cert_fileSet to the path to the PEM-encoded public certificate used to secure client connections.
ssl_key_fileSet to the path to the PEM-encoded private key used to secure client connections.
ssl_modeThe mode that should be used to verify the server certificate. The
PostgreSQL default is prefer, which provides no security benefit; we
strongly suggest setting this to require or better if you are using
certificate authentication. See the PostgreSQL
documentation
for potential values.
versionThe version of PostgreSQL that is in use. Do not set by hand; use the PostgreSQL upgrade tool.
[memcached]memoryOverride the number of megabytes of memory that memcached should be configured to consume; defaults to 1/8th of the total server memory.
max_item_sizeOverride the maximum size that an item in memcached can store. This defaults to 1m; adjusting it should only be necessary if your Zulip server has organizations which have more than 20k users.
size_reportingSet to a true value to enable object size reporting in memcached. This incurs a small overhead for every store or delete operation, but allows a memcached_exporter to report precise item size distribution.
[tornado_sharding]Keys in this section are used to configure how many Tornado instances are started, and which users are mapped to which of those instances. Each Tornado instance listens on a separate port, starting at 9800 and proceeding upwards from there. A single Tornado instance can usually handle 1000-1500 concurrent active users, depending on message sending volume.
Individual organizations may be assigned to ports, either via their
subdomain names, or their fully-qualified hostname (for organizations
using REALM_HOSTS):
[tornado_sharding]
9800 = realm-a realm-b
9801 = realm-c
9802 = realm-host.example.net
Organizations can also be assigned to ports via regex over their fully-qualified hostname:
[tornado_sharding]
9800_regex = ^realm-(a|b)\.example\.com$
9801_regex = ^other(-option)?\.example.com$
Extremely large organizations can be distributed across multiple
Tornado shards by joining the ports in the key with _:
[tornado_sharding]
9800 = small-realm
9801_9802 = very-large-realm
After running scripts/zulip-puppet-apply, a separate step to run
scripts/refresh-sharding-and-restart is required for any sharding
changes to take effect.
[loadbalancer]ipsComma-separated list of IP addresses or netmasks of external load balancers
whose X-Forwarded-For and X-Forwarded-Proto should be respected. These can
be individual IP addresses, or CIDR IP address ranges.
rejects_http_requestsSet to a true value if incoming requests from load loadbalancer's IP addresses
which do not contain an X-Forwarded-Proto should be assumed to have come into
them over HTTPS. This setting is a security vulnerability unless the load
balancer unilaterally rejects unencrypted HTTP connections, or responds to them
with 301 status codes. Note that Zulip's HSTS headers are not sufficient
protection here, since API clients do not respect them; the load balancer must
not send any requests to Zulip which came in unencrypted.
[http_proxy]See "Customizing the outgoing HTTP proxy" for general instructions on the outgoing proxy.
hostThe hostname or IP address of an outgoing HTTP CONNECT. Defaults to
localhost if unspecified.
portThe TCP port of the HTTP CONNECT proxy on the host specified above.
Defaults to 4750 if unspecified.
listen_addressThe IP address that Smokescreen should bind to and listen on.
Defaults to 127.0.0.1.
enable_for_camoBecause Camo includes logic to deny access to private subnets, routing its requests through Smokescreen is generally not necessary. Set to true or false to override the default, which uses the proxy only if it is not the default of Smokescreen on a local host.
allow_addresses, allow_ranges, deny_addresses, deny_rangesComma-separated lists of IP addresses or CIDR range rules. All private IP addresses (e.g., 127.0.0.0/8, 192.168.0.0/16) are denied by default; allow rules override deny rules.
[sentry]organizationThe Sentry organization used for the Sentry deploy hook.
projectThe Sentry project used for the Sentry deploy hook.