Railway

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

Just deployed

/var/lib/postgresql/data

Just deployed

/data

Just deployed

/data

RabbitMQ

rabbitmq:4.0

Just deployed

/var/lib/rabbitmq

Just deployed

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

ServicePurpose
ZulipThe chat application server, web UI, and API
PostgreSQLMessages and data, on Zulip's full-text-search Postgres image
RabbitMQAsync task queue — email, notifications, webhooks
Memcached / RedisObject 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)SlackMattermostMicrosoft Teams
Conversation modelTopic threadsChronologicalChronologicalChronological
Best forAsync / distributedReal-time teamsSlack-style self-hostEnterprise
Cost modelFlat infraPer userFlat infraPer user
Integrations120+ManyManyMany
Data ownershipFull — your infraVendorFullMicrosoft
Self-hostableYesNoYesNo

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

VariableRequiredDescription
SETTING_EXTERNAL_HOSTRequiredYour Railway public domain — used for links and request validation
DISABLE_HTTPSRequiredTrue — Railway terminates TLS, so Zulip serves HTTP internally
SECRETS_secret_keyRequired64-char Django secret (openssl rand -hex 32) — keep stable
SETTING_ZULIP_ADMINISTRATORRecommendedAdmin email — receives server notifications, becomes first admin
SECRETS_postgres_passwordAuto-matchedMust match the PostgreSQL service password
SECRETS_rabbitmq_password / _memcached_password / _redis_passwordAuto-matchedMust match their service passwords
SETTING_EMAIL_*OptionalSMTP 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

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.


Template Content

RabbitMQ

rabbitmq:4.0

More templates in this category

View Template
Rocky Linux
[Jul'26] Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
36
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51