Skip to content

Self-host Zulip

updated Sep 2026prices checked · Jul 2026Install verified on Ubuntu 26.04 · Sep 2026 · how we test
We earn commissions when you shop through the links below. Full disclosure →

An open-source team chat server that organizes every conversation into topics within channels, so discussions stay threaded. It ships web, desktop and mobile apps.

Key facts

CategoryTeam chat
LicenseApache-2.0
StackPython, Django, PostgreSQL, RabbitMQ
Min RAM4096 MB
Official imageyes
Measured idle RAM3259 MB
Difficulty

What you need

  • Any VPS with at least 4096 MB of RAM
  • A domain you control — most self-hosted setups need HTTPS in front of them
  • About an afternoon — budget time for troubleshooting
Where to host itaffiliate disclosure
Hetzner Cloudrun it on
From $23.59/mo · 2 vCPU / 4 GB / 80 GB · EU + US
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
From $4/mo · 1 vCPU / 1 GB / 20 GB · US + EU + Asia
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
From $6/mo · 1 vCPU / 1 GB / 25 GB · US + EU + Asia
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Install

Run these commands on your server:

# Zulip — official docker-zulip compose (Zulip + PostgreSQL + memcached + RabbitMQ + Redis)
git clone https://github.com/zulip/docker-zulip.git
cd docker-zulip
cp compose.override.yaml.example compose.override.yaml
# set your own values: Zulip refuses to start on the file's example.com defaults. EXTERNAL_HOST is the DNS name users type (not an IP)
ZULIP_HOST=chat.example.net; ZULIP_ADMIN=admin@example.net
# Zulip only serves clients over HTTPS: with no TLS proxy in front, let the container make a self-signed cert (or use "certbot" with real DNS)
sed -i "s/zulip.example.com/$ZULIP_HOST/; s/zulip-admin@example.com/$ZULIP_ADMIN/; s/# CERTIFICATES: \"certbot\"/CERTIFICATES: \"self-signed\"/" compose.override.yaml
# the six secrets the compose file reads from .env
for s in POSTGRES_PASSWORD MEMCACHED_PASSWORD RABBITMQ_PASSWORD REDIS_PASSWORD SECRET_KEY EMAIL_PASSWORD; do echo "ZULIP__$s=$(openssl rand -hex 24)" >> .env; done
# run that loop once: a re-run appends new secrets that no longer match the initialised database
docker compose pull
docker compose run --rm zulip app:init
docker compose up -d --wait
# serves HTTPS on port 443 only  →  https://SERVER_IP:443 (browse to it by the EXTERNAL_HOST name; click past the self-signed warning)
# then create your organization: ./manage.py generate_realm_creation_link
# the compose file also publishes port 25 for the incoming-email gateway: remove it from ports if you do not use it

An alternative to

Head-to-head

More self-hosted tools

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.