---
title: "Deploy Zulip — Self-Hosted Topic-Based Team Chat"
description: "Self-host Zulip — async team chat organized by topics"
category: "Other"
url: https://railway.com/deploy/zulip-topic-team-chat
---

# Deploy Zulip — Self-Hosted Topic-Based Team Chat

Self-host Zulip — async team chat organized by topics

**[Deploy Zulip — Self-Hosted Topic-Based Team Chat on Railway](https://railway.com/template/zulip-topic-team-chat)**

- **Creator:** SilverBanana
- **Category:** Other

## Template content

### PostgreSQL https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/postgres.svg

- **Image:** zulip/zulip-postgresql:14

### Redis https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg

- **Image:** redis:8.2.1
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### Zulip https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/zulip.svg

- **Image:** ghcr.io/zulip/zulip-server

### RabbitMQ https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/rabbitmq.svg

- **Image:** rabbitmq:4.0

### Memcached https://cdn.worldvectorlogo.com/logos/memcached.svg

- **Image:** memcached:alpine

## Documentation

# Deploy and Host Zulip on Railway

Zulip is the open-source team chat built around topics — a Slack alternative designed for asynchronous, distributed teams. Unlike Slack, Mattermost, or Teams, where messages flow in one chronological stream, every Zulip message lives under a named topic within a channel. You can follow, catch up on, or mute individual conversations without scrolling an entire channel — the reason remote teams across time zones prefer it. This template deploys Zulip's full five-service stack, correctly wired with matched secrets, so it works on the first deploy.

---

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| **Zulip** | The chat application server, web UI, and API |
| **PostgreSQL** | Messages and data, on Zulip's full-text-search Postgres image |
| **RabbitMQ** | Async task queue — email, notifications, webhooks |
| **Memcached / Redis** | Object caching, rate limiting, and session caching |

All five run on Railway's private network; only Zulip is public. This is the same architecture Zulip's own maintainers ship — the complexity is what enables the real-time features and reliability.

---

## About Hosting

Zulip is the most capable self-hosted async chat, and its two defining traits — the topic model and the five-service stack — are worth understanding.

**Topics are the whole point — and why async teams choose it.** In Zulip, every message belongs to a named topic inside a channel, so a channel is a set of threaded conversations rather than one endless stream. Someone catching up hours later reads only the topics that matter and mutes the rest, instead of scrolling a firehose. For distributed teams spanning time zones, this changes how communication scales. If your team is co-located and wants a flat Slack-style feed, a simpler chat server fits better; if you're async, Zulip is purpose-built for you.

**Five services with matched secrets — the wiring that trips up manual setups.** Zulip runs as an app server plus PostgreSQL, Memcached, RabbitMQ, and Redis. The critical detail: each backend service's password must match the corresponding `SECRETS_*` value in the Zulip container — Postgres, RabbitMQ, Memcached, and Redis passwords are all paired, and a single mismatch breaks startup. This template generates and matches all of them, the exact step a hand-rolled deploy gets wrong.

**Set `SECRETS_secret_key` and keep it stable.** Zulip needs a 64-character Django secret key (`openssl rand -hex 32`) to sign sessions. This template generates it; keep it stable across redeploys, or active sessions are invalidated.

**`SETTING_EXTERNAL_HOST` must be your Railway domain, with `DISABLE_HTTPS=True`.** Zulip builds links against `SETTING_EXTERNAL_HOST`, so it must be your Railway domain. Set `DISABLE_HTTPS=True` because Railway terminates TLS at its edge — Zulip serves HTTP internally while Railway provides HTTPS.

**It's the heaviest chat option — size it right.** Five services and a 2 GB RAM minimum make Zulip more resource-hungry than simpler chat servers. Allocate accordingly and scale as your team grows.

Typical cost: **~$15–25/month** on Railway across the five services. Zulip is Apache-2.0 licensed and free — no per-user fees, ever.

---

## How It Compares

| | Zulip (self-hosted) | Slack | Mattermost | Microsoft Teams |
| --- | --- | --- | --- | --- |
| Conversation model | Topic threads | Chronological | Chronological | Chronological |
| Best for | Async / distributed | Real-time teams | Slack-style self-host | Enterprise |
| Cost model | Flat infra | Per user | Flat infra | Per user |
| Integrations | 120+ | Many | Many | Many |
| Data ownership | Full — your infra | Vendor | Full | Microsoft |
| Self-hostable | Yes | No | Yes | No |

Slack and Teams are polished but bill per user and keep your data on their servers. Mattermost is a great self-hosted choice if you want a familiar flat Slack-style feed with a lighter footprint. Zulip is different by design: its topic-threading model is purpose-built for asynchronous, distributed teams who catch up on specific conversations across time zones — self-hosted, with 120+ integrations, at flat cost.

---

## Deploy in Under 5 Minutes

1. Click **Deploy on Railway** — all five services build and wire together with matched secrets (~5 minutes)
2. Confirm `SETTING_EXTERNAL_HOST` is your Railway domain and `DISABLE_HTTPS=True`
3. Confirm `SECRETS_secret_key` is set and the backend passwords are matched (handled by the template)
4. Open your Railway domain and create your organization and first admin account
5. Create channels, define topics, and invite your team

Set the `SETTING_EMAIL_*` variables to enable invitations and notifications.

---

## Common Use Cases

- **Async chat for distributed teams** — topic threading so people across time zones catch up on what matters
- **Slack alternative without per-user fees** — unlimited members at flat infrastructure cost
- **Open-source communities** — large public communities use Zulip's topics to keep discussions organized
- **Data-sovereign team chat** — messages and files stay entirely on your own infrastructure

---

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `SETTING_EXTERNAL_HOST` | Required | Your Railway public domain — used for links and request validation |
| `DISABLE_HTTPS` | Required | `True` — Railway terminates TLS, so Zulip serves HTTP internally |
| `SECRETS_secret_key` | Required | 64-char Django secret (`openssl rand -hex 32`) — keep stable |
| `SETTING_ZULIP_ADMINISTRATOR` | Recommended | Admin email — receives server notifications, becomes first admin |
| `SECRETS_postgres_password` | Auto-matched | Must match the PostgreSQL service password |
| `SECRETS_rabbitmq_password` / `_memcached_password` / `_redis_password` | Auto-matched | Must match their service passwords |
| `SETTING_EMAIL_*` | Optional | SMTP settings for invitations and notifications |

> **The backend passwords must match, and the secret key must be stable.** Each `SECRETS_*` password has to equal its service's password, or Zulip won't start — this template matches all of them. `SECRETS_secret_key` signs sessions; keep it constant across redeploys.

> **Set the external host and disable HTTPS in-app.** `SETTING_EXTERNAL_HOST` must be your Railway domain, and `DISABLE_HTTPS=True` because Railway handles TLS at its edge.

---

## Dependencies for Zulip Hosting

- Railway account — ~$15–25/month across the five services
- PostgreSQL (Zulip's search image), Memcached, RabbitMQ, and Redis (all included and wired)
- At least 2 GB RAM — Zulip is the heaviest self-hosted chat option
- Optional: SMTP credentials for invitations and email notifications

### Deployment Dependencies

- [Zulip GitHub Repository](https://github.com/zulip/zulip)
- [Zulip Docker Documentation](https://github.com/zulip/docker-zulip)
- [Zulip Production Settings](https://zulip.readthedocs.io/en/stable/production/settings.html)
- [Railway Private Networking](https://docs.railway.com/guides/private-networking)

### Implementation Details

The template runs the official `ghcr.io/zulip/zulip-server` image alongside four backend services: PostgreSQL (Zulip's full-text-search image), Memcached with SASL auth, RabbitMQ for the async task queue, and Redis for rate limiting and caching. All five communicate over the private network, with only the Zulip app exposed.

The defining requirement is secret matching: each backend password must equal the corresponding `SECRETS_postgres_password`, `SECRETS_rabbitmq_password`, `SECRETS_memcached_password`, and `SECRETS_redis_password` in the Zulip container, and a mismatch prevents startup. This template pairs all of them, along with the 64-character `SECRETS_secret_key` that signs sessions and must stay stable. `SETTING_EXTERNAL_HOST` is set to the Railway domain and `DISABLE_HTTPS=True` because Railway terminates TLS while Zulip serves HTTP internally. The entrypoint generates config from these variables on first boot and runs migrations. Messages persist in PostgreSQL — the component to back up. The five-service architecture and 2 GB RAM minimum make Zulip the most resource-intensive self-hosted chat, a trade for its topic-threading model.

---

## Frequently Asked Questions

**How is Zulip different from Slack or Mattermost?** Zulip organizes messages by named topics within channels, not one chronological stream. This makes catching up on specific conversations easy for async, distributed teams — where flat Slack-style chat forces you to scroll everything. Mattermost is the better pick if you specifically want a familiar flat feed.

**Why won't a manual Zulip deploy start?** Usually mismatched secrets — each backend password must equal its `SECRETS_*` value in the Zulip container. This template matches them automatically, the most common manual-setup failure.

**Why `DISABLE_HTTPS=True`?** Railway terminates TLS at its edge, so Zulip serves plain HTTP internally while Railway provides HTTPS externally. `SETTING_EXTERNAL_HOST` must be your Railway domain for links to resolve.

**Does my data persist?** Yes. Messages live in PostgreSQL, which survives redeploys. Back it up regularly since it holds your team's history.

**How many integrations does it have?** Over 120, plus a full API and webhooks, so alerts and events route into the relevant topics.

---

## Why Deploy Zulip on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Zulip on Railway you get topic-based team chat with the hard part solved — all five services wired, the backend secrets matched, the external host and TLS settings correct, and automatic HTTPS. Async-first communication with 120+ integrations, self-hosted on infrastructure you own.

## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — [Jul'26] Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/zulip-topic-team-chat
