Self-host Zulip
updated Sep 2026deployed by usprices 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
Websitezulip.com (opens in new tab)
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 + USKamaterafree trial
From $4/mo · 1 vCPU / 1 GB / 20 GB · US + EU + AsiaDigitalOceanalso works on
From $6/mo · 1 vCPU / 1 GB / 25 GB · US + EU + AsiaPaid 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 itdeploy guideHow to Deploy Zulip on a VPSvps picksBest VPS for self-hostingbenchmarked quarterly · re-priced monthly
An alternative to
Head-to-head
More self-hosted tools
Team chat
Mattermost
GoReactPostgreSQL
moderateRead guide →
Team chat
Rocket.Chat
Node.jsMongoDB
moderateRead guide →
Team chat
Synapse
PythonRustSQLitePostgreSQL
easyRead guide →
Error tracking
GlitchTip
PythonDjangoAngular
moderateRead guide →