Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Zulip Ubuntu
GUIDEInstall Guides

How to Install Zulip on Ubuntu 24.04 — Self-Hosted Topic-Based Team Chat

24 min read

How to Install Zulip on Ubuntu 24.04 — Self-Hosted Topic-Based Team Chat

Team chat should not lock your conversations, files, and integration history inside a vendor that can raise prices, gate features behind enterprise tiers, or delete message history after 90 days. Zulip is an open-source team chat platform with a uniquely productive model: every message lives inside a named topic within a stream, so asynchronous conversations stay readable weeks later instead of scrolling into the void. This tutorial walks you through installing Zulip Server on a fresh Ubuntu 24.04 VPS, from downloading the installer to configuring SAML SSO with Keycloak.

Skip the setup? Deploy a production-tuned VPS for Zulip in under 60 seconds. Launch a Professional VPS now and start chatting today.

Table of Contents

  • What is Zulip?
  • Why Self-Host Topic-Based Chat Instead of Slack?
  • Prerequisites
  • Step 1: Prepare the Server
  • Step 2: Download the Zulip Installer
  • Step 3: Run the install-server Script
  • Step 4: Create Your First Organization
  • Step 5: Create Users with manage.py
  • Step 6: Master Streams and Topics
  • Step 7: Configure Bots and Integrations
  • Step 8: Configure SMTP and Mobile Push
  • Step 9: Enable SAML SSO
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Zulip?

    Zulip is an open-source team collaboration platform developed since 2012 and used by organizations like Recurse Center, Rust language team, Wikimedia, Lean theorem prover community, and the Asciidoctor project. It combines the immediacy of real-time chat with the structure of a threaded forum, letting teams juggle many conversations in parallel without the chaos that plagues single-timeline chat apps.

    The Zulip server is a Python/Django application with a Tornado-based real-time push layer, Postgres for persistence, Redis for caching, RabbitMQ for job queues, Memcached for session data, and Nginx as the front-end TLS terminator. Everything is self-contained — one install-server script wires all of that together, applies systemd units, requests a Let's Encrypt certificate, and hands you a working chat server.

    Zulip ships native clients for Web, macOS, Windows, Linux, iOS, and Android, plus a mature terminal client. All are open source. The protocol between client and server is a simple documented JSON REST + long-poll event queue, so writing custom clients, bots, or data exports is straightforward. The full Zulip server source lives at github.com/zulip/zulip, and comprehensive operator docs live at zulip.readthedocs.io.

    Why Self-Host Topic-Based Chat Instead of Slack?

    Slack works fine until your team crosses about 30 people or your message volume crosses a few hundred a day. Past that point, single-channel timelines become unreadable, messages get lost, and Slack's 90-day history limit on free plans starts erasing institutional knowledge. The paid tier fixes history but charges per active user per month, which for a 50-person team lands in the EUR 600–1000/month range before add-ons. Zulip, self-hosted on your own VPS, is a flat fee for the server — typically under EUR 25/month.

    The deeper reason to switch is the conversation model. In Slack, a channel is one endless timeline. If five people ask unrelated questions in the same hour, all five threads interleave, and by tomorrow nobody can find any of them. In Zulip, every message must be attached to a topic — a short subject line like "deploy pipeline failing on step 3" or "quarterly roadmap review". The topic becomes a first-class object you can mute, resolve, link to, or reopen a month later. This is how email used to work before threading got broken, and it maps far better to how distributed teams actually collaborate.

    Self-hosting also gives you:

    • Full data ownership — Messages, attachments, user list, and audit logs live on your server and nowhere else. No third-party retention policy, no surprise indexing for LLM training, no cross-border data transfer headaches.
    • Unlimited history forever — Search messages from three years ago the same way you search today's. No paywall.
    • No per-seat pricing — Adding the 200th user costs zero. Guests, bots, cross-functional stakeholders all included.
    • Unlimited integrations — Every webhook, every bot, every API token is free. No "premium integrations" tier.
    • Compliance control — For GDPR, HIPAA, SOC 2, or ISO 27001 audits, self-hosting puts you in charge of encryption at rest, backup geography, and access logs.
    • Custom SSO and provisioning — Bind to your existing identity provider (Keycloak, Okta, Azure AD) via SAML or LDAP. Automate account lifecycle with SCIM.
    • Open-source escape hatch — If Zulip as a project ever took a direction you disliked, you could fork it. You cannot fork Slack.
    For a 50-user team, self-hosted Zulip on a Professional VPS pays for itself against Slack Pro in the first week of the month.

    Zulip vs. Other Self-Hosted Chat

    Zulip is not the only game in town. If you are weighing alternatives, see our install guides for Mattermost on Ubuntu 24.04 (channel-based, closer to Slack's UX) and Rocket.Chat on Ubuntu 24.04 (omnichannel, includes livechat and video). Mattermost is the right pick for teams that want Slack without Slack. Rocket.Chat is the right pick if you need to merge customer-facing livechat and internal chat on one server. Zulip wins when your team does deep asynchronous work across time zones — engineering, research, open source, documentation, academia — where losing a conversation in a timeline costs real hours.

    Prerequisites

    Before you begin, you will need:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access and a clean install (Zulip's installer expects a fresh system and will refuse to run if ports 80/443/5432 are already bound).
    • A domain name (for example chat.example.com) with an A record pointing to your VPS IP. Zulip needs a real DNS name to request a Let's Encrypt certificate.
    • SSH access to your server.
    • At least 4 GB of RAM (8 GB+ strongly recommended for more than 20 active users).
    • At least 50 GB of disk space for Postgres, message history, and uploaded attachments.
    • SMTP credentials from a transactional provider like Mailgun, Amazon SES, Postmark, or a self-hosted Postfix relay — Zulip sends a lot of notification email.
    Recommended Plan: Professional
    >
    For a team of 20–100 active users, we recommend the Professional VPS:
    >
    - 4 vCPU cores
    - 8 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    - EUR 19.99/month
    >
    This gives Postgres, Redis, Tornado, RabbitMQ, and Nginx room to run comfortably alongside the Django application servers. Teams of 200+ should step up to 16 GB RAM.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Prepare the Server

    Zulip's installer manages Postgres, Redis, Nginx, and Memcached itself — do not install them manually. All you need to do first is apply security updates, set the hostname, and make sure the domain resolves.

    Update packages:

    bash
    apt update && apt upgrade -y

    Set the hostname to match your chat domain (replace chat.example.com):

    bash
    hostnamectl set-hostname chat.example.com

    Add a matching entry to /etc/hosts so sudo and local tools resolve the name without DNS:

    bash
    echo "127.0.1.1 chat.example.com chat" >> /etc/hosts

    Verify your domain resolves to this server externally:

    bash
    dig +short chat.example.com

    The returned IP must match the VPS public IP. If it does not, fix your DNS A record and wait for propagation before continuing — the installer will fail certificate issuance otherwise.

    Install a couple of packages the installer does not pull in itself:

    bash
    apt install -y wget ca-certificates curl

    Reboot if a new kernel was installed:

    bash
    reboot

    Step 2: Download the Zulip Installer

    Zulip distributes production releases as versioned tarballs at download.zulip.com/server. Always grab the latest stable build rather than cloning main from Git.

    Download and extract:

    bash
    cd /root
    wget -N https://download.zulip.com/server/zulip-server-latest.tar.gz
    tar -xf zulip-server-latest.tar.gz

    You will now have a directory like zulip-server-9.4 containing a scripts/setup/install executable, a requirements/ folder, and the full Zulip codebase.

    Verify the installer is there:

    bash
    ls zulip-server-*/scripts/setup/install

    Expected output:

    text
    zulip-server-9.4/scripts/setup/install

    Step 3: Run the install-server Script

    The installer accepts two required flags: --hostname (the fully-qualified chat domain) and --email (the email address used for your Let's Encrypt certificate renewal notices). It handles everything else automatically.

    Run it from inside the extracted directory:

    bash
    cd /root/zulip-server-*
    ./scripts/setup/install --certbot \
      --hostname=chat.example.com \
      [email protected]

    What the --certbot flag does: requests a TLS certificate from Let's Encrypt during install and configures automatic renewal via systemd timer. Skip it and add --self-signed-cert only if you are testing on a server without public DNS.

    The installer runs for 10–20 minutes and performs roughly these actions:

  • Installs system packages: nginx, postgresql-16, redis-server, memcached, rabbitmq-server, supervisor, python3-venv, libicu-dev, tesseract-ocr.
  • Creates a dedicated zulip Unix user and /home/zulip/deployments/ layout.
  • Builds a Python virtual environment in /srv/zulip-venv-cache/ and installs all Django + Tornado dependencies via pip.
  • Initializes the Postgres database zulip with the correct roles, search configuration, and extensions (pg_trgm, tsm_system_rows).
  • Configures Redis and Memcached with Zulip's tuned parameters.
  • Configures RabbitMQ with the zulip vhost and /var/lib/rabbitmq/.erlang.cookie permissions.
  • Generates /etc/zulip/zulip.conf and /etc/zulip/settings.py with a random SECRET_KEY and Postgres password.
  • Writes Nginx vhost config with HTTP/2, HSTS, and a WebSocket upgrade location for Tornado.
  • Runs certbot certonly and installs the certificate paths into Nginx.
  • Runs database migrations and populates initial fixture data.
  • Registers supervisord programs for all Zulip workers (Django, Tornado, queue workers, missedmessage emails, email mirror, etc).
  • Starts everything via supervisorctl start all and prints the organization creation URL.
  • Expected tail of output:

    text
    Zulip settings are in /etc/zulip/settings.py
    Please edit the file and fill in the values for EXTERNAL_HOST, ZULIP_ADMINISTRATOR, and EMAIL_HOST.

    Installer complete. Now visit:

    https://chat.example.com/new/<activation-token>

    to register your first Zulip organization.

    Note that URL — it is a single-use organization creation link with a signed token. If you lose it, regenerate with:

    bash
    su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'

    Step 4: Create Your First Organization

    Open the activation URL printed by the installer in a browser. You will see Zulip's organization setup wizard.

    Fill in:

    • Organization name — the display name shown in the top-left of every client (for example "Example Corp").
    • Organization type — Business, Open-source project, Education, Research, Community, etc. This preloads sensible stream defaults and privacy settings.
    • URL — leaves as chat.example.com since you already bound the hostname.
    • Your name and email — this account becomes the first organization owner, with full administrative rights.
    • Password — minimum 6 characters by default; you should configure a stronger policy in Organization Settings later.
    Submit the form. Zulip creates the realm (its internal term for an organization), your owner account, and three starter streams: #general, #new members, and #announce. You are dropped straight into the web client, already logged in.

    Take one minute now to set:

    • Organization Settings → Organization profile — add a description, logo, and time zone.
    • Organization Settings → Organization permissions — decide whether new users need an invite, whether the organization is publicly searchable, and the minimum password strength.
    • Organization Settings → Authentication methods — email+password is enabled by default; we will add SAML in Step 9.

    Step 5: Create Users with manage.py

    Zulip ships a Django management command surface at /home/zulip/deployments/current/manage.py. Running as the zulip user gives you scripted access to every administrative action — ideal for seeding the initial team or integrating with onboarding scripts.

    Create a new user from the command line:

    bash
    su zulip -c '/home/zulip/deployments/current/manage.py create_user \
      [email protected] \
      "correct horse battery staple" \
      "Alice Anderson" \
      --realm=example'

    Arguments are, in order: email, password, full name. The --realm flag targets your organization by its string_id (usually the subdomain prefix; check with manage.py list_realms).

    Useful related commands:

    bash
    # List all realms
    su zulip -c '/home/zulip/deployments/current/manage.py list_realms'

    Send a bulk invite via email

    su zulip -c '/home/zulip/deployments/current/manage.py send_invitation \ -r example \ --streams=general,engineering \ [email protected] [email protected]'

    Promote a user to organization administrator

    su zulip -c '/home/zulip/deployments/current/manage.py change_user_role \ -r example [email protected] admin'

    Deactivate (soft delete) a user

    su zulip -c '/home/zulip/deployments/current/manage.py deactivate_user \ -r example [email protected]'

    Export the entire realm for backup or migration

    su zulip -c '/home/zulip/deployments/current/manage.py export \ -r example --output=/tmp/example-export.tar.gz'

    For bulk onboarding of 50+ accounts, write a small shell loop around create_user or use the web-based bulk invite flow under Organization Settings → Invitations.

    Step 6: Master Streams and Topics

    This is the concept that makes Zulip Zulip. Spend five minutes getting it right up front and your team will thank you for months.

    A stream is the equivalent of a Slack channel — a persistent space that users subscribe to, named things like #engineering, #hiring, or #support. Permissions and notification policies attach to the stream.

    A topic is a short subject line attached to every message inside a stream — things like "deploy pipeline failing on step 3", "hire decision: Jamie Lin", or "customer ticket #4412". Topics are lightweight; anyone can create one by typing it in the compose box. They do not need to be pre-declared.

    When you read a stream, Zulip groups messages by topic, showing each topic as a small conversation block. You can:

    • Resolve a topic with a checkmark when the discussion is done — it stays searchable but drops off the active list.
    • Move a topic between streams if it was started in the wrong place.
    • Mute a topic you do not care about without muting the whole stream.
    • Link to a topic with a permalink that works forever.
    • Mark as unread from here to revisit a subthread later.
    Practical guidance for teams new to Zulip:

    • Keep stream count low (10–30 streams for a 50-person team). Topics do the fine-grained separation, not streams.
    • Use private streams for HR, finance, and security. Public streams for everything else.
    • Name topics like email subjects, not like tweets. "Q2 budget — engineering line items" beats "budget stuff".
    • Start a new topic when the subject shifts. Do not hijack an existing one.
    • Use @-mentions sparingly. The topic model means people can catch up asynchronously; you do not need to ping everyone every time.

    Step 7: Configure Bots and Integrations

    Zulip has over 100 built-in integrations for the services engineering teams actually use. Each one is a webhook endpoint on your server; you configure the source system to POST to it.

    Create a bot user

    Go to Personal Settings → Bots → Add a new bot. Choose Incoming webhook for simple one-way integrations, Generic bot for full API access.

    Copy the bot's API key and the incoming webhook URL — it looks like:

    text
    https://chat.example.com/api/v1/external/github?api_key=ABC123&stream=engineering&topic=deploys

    GitHub integration

    In your GitHub repository, go to Settings → Webhooks → Add webhook:

    • Payload URL: paste the bot URL from above with stream=engineering&topic=github appended.
    • Content type: application/json
    • Events: choose specific events (push, PR opened, issue comment) or "Send me everything".
    Every push, PR, and review comment now posts into the #engineering stream under a topic named after the PR title. Full configuration options live at zulip.com/integrations/doc/github.

    Jira integration

    In Jira, go to System Settings → Webhooks → Create webhook. Point it at your Zulip bot URL with ?stream=product&topic=jira. Select issue events (created, updated, assignee changed). Every Jira ticket change now lands in Zulip with a stable topic per issue key — search for "ENG-4412" and you see the full history.

    PagerDuty integration

    In PagerDuty, go to Service Directory → pick service → Integrations → Add integration → Zulip. Paste the Zulip bot URL. Incidents, acknowledgments, and resolutions stream into an #oncall stream with topic-per-incident, so the full incident conversation (commands run, rollback decisions, root cause) stays attached to the incident itself.

    Other useful integrations

    • Sentry — exception alerts with stack traces.
    • Stripe — subscription events, failed charges.
    • Prometheus Alertmanager — metric alerts to an #alerts stream.
    • Google Calendar — daily agenda digest.
    • Custom webhooks — Zulip's generic /api/v1/external/slack_incoming endpoint accepts Slack-format payloads, so most tools that "integrate with Slack" integrate with Zulip with a one-line URL change.
    Full catalog at zulip.com/integrations.

    Step 8: Configure SMTP and Mobile Push

    Outbound SMTP

    Zulip sends a lot of email: signup confirmations, password resets, missed-message digests, mention notifications, invitations. Configure a real SMTP relay before you invite users.

    Edit /etc/zulip/settings.py:

    bash
    nano /etc/zulip/settings.py

    Find and set:

    python
    EMAIL_HOST = "smtp.mailgun.org"
    EMAIL_HOST_USER = "[email protected]"
    EMAIL_PORT = 587
    EMAIL_USE_TLS = True
    DEFAULT_FROM_EMAIL = "Example Chat <[email protected]>"
    NOREPLY_EMAIL_ADDRESS = "[email protected]"

    Store the SMTP password in a separate secrets file:

    bash
    echo "email_password = your-mailgun-api-key" >> /etc/zulip/zulip-secrets.conf

    Restart Zulip to pick up the change:

    bash
    su zulip -c '/home/zulip/deployments/current/scripts/restart-server'

    Send a test:

    bash
    su zulip -c '/home/zulip/deployments/current/manage.py send_test_email [email protected]'

    You should receive a test message within seconds. If not, check /var/log/zulip/errors.log for SMTP errors.

    Mobile push notifications

    Zulip's iOS and Android apps require push notifications to be routed through Apple's APNs and Google's FCM. Because those gateways require Apple/Google developer credentials, Zulip runs a centralized push notification service that relays encrypted payloads for self-hosted installs — you register your server once and push just works.

    Register your server:

    bash
    su zulip -c '/home/zulip/deployments/current/manage.py register_server'

    Follow the prompts to link your email and accept the push service terms. Then in /etc/zulip/settings.py:

    python
    PUSH_NOTIFICATION_BOUNCER_URL = "https://push.zulipchat.com"
    SUBMIT_USAGE_STATISTICS = True

    Restart Zulip. Install the Zulip mobile app, sign in with your server URL (chat.example.com), and you will get push notifications for DMs and mentions. The service is free for organizations under 10 users and has modest fees above that; see zulip.com/plans for details.

    Step 9: Enable SAML SSO

    For any organization with more than 10 people, you want single sign-on. Zulip ships first-class SAML support that integrates with Keycloak, Okta, Azure AD, Google Workspace, and any other SAML 2.0 identity provider.

    Generate Zulip's SAML service-provider metadata

    In /etc/zulip/settings.py, enable the SAML backend:

    python
    AUTHENTICATION_BACKENDS = (
        "zproject.backends.EmailAuthBackend",
        "zproject.backends.SAMLAuthBackend",
    )

    SOCIAL_AUTH_SAML_SP_ENTITY_ID = "https://chat.example.com" SOCIAL_AUTH_SAML_ORG_INFO = { "en-US": { "displayname": "Example Corp", "name": "example", "url": "https://example.com", } } SOCIAL_AUTH_SAML_TECHNICAL_CONTACT = {"givenName": "Ops", "emailAddress": "[email protected]"} SOCIAL_AUTH_SAML_SUPPORT_CONTACT = {"givenName": "Support", "emailAddress": "[email protected]"}

    Generate the SP certificate pair that Zulip will use to sign SAML requests:

    bash
    cd /etc/zulip
    openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
      -keyout saml-private-key.key -out saml-public-cert.cert \
      -subj "/CN=chat.example.com"
    chown zulip:zulip saml-private-key.key saml-public-cert.cert
    chmod 640 saml-private-key.key

    Configure the identity provider

    In Keycloak (or your IdP of choice), create a new SAML client:

    • Client ID: https://chat.example.com
    • Valid Redirect URIs: https://chat.example.com/complete/saml/
    • Master SAML Processing URL: https://chat.example.com/complete/saml/
    • Sign assertions: on
    • Client signature required: on (paste saml-public-cert.cert as the client's signing cert)
    • Name ID format: email
    • Attribute mappers: add email, first_name, last_name attributes mapped from the user profile
    Export the IdP metadata XML or copy the IdP's entity ID, SSO URL, and X.509 signing certificate.

    Wire the IdP back into Zulip

    Add to /etc/zulip/settings.py:

    python
    SOCIAL_AUTH_SAML_ENABLED_IDPS = {
        "keycloak": {
            "entity_id": "https://auth.example.com/realms/example",
            "url": "https://auth.example.com/realms/example/protocol/saml",
            "x509cert": "MIIDazCCAlOgAwIBAgIUA... (paste full IdP cert) ...",
            "attr_user_permanent_id": "email",
            "attr_first_name": "first_name",
            "attr_last_name": "last_name",
            "attr_username": "email",
            "attr_email": "email",
            "display_name": "Example Keycloak",
        }
    }

    Restart Zulip:

    bash
    su zulip -c '/home/zulip/deployments/current/scripts/restart-server'

    Visit https://chat.example.com/login/ — you will see a new Sign in with Example Keycloak button. First sign-in provisions the user automatically, mapping their IdP email to a Zulip account. For a full guide on running Keycloak as the IdP, see our Keycloak on Ubuntu 24.04 install guide.

    Troubleshooting

    ProblemCauseSolution
    install-server fails at the certbot stepDNS A record not yet propagated, or port 80 blocked by firewallVerify dig +short chat.example.com matches the VPS IP. Ensure UFW allows 80/443: ufw allow 80,443/tcp. Rerun with ./scripts/setup/install --certbot --hostname=... --email=...
    502 Bad Gateway on first page loadDjango workers not yet started or supervisord still bootingWait 30 seconds, then check supervisorctl status. Restart with /home/zulip/deployments/current/scripts/restart-server
    Emails not sendingSMTP misconfigured or secrets file unreadablemanage.py send_test_email [email protected] and check /var/log/zulip/errors.log. Verify /etc/zulip/zulip-secrets.conf is owned by zulip:zulip mode 640
    register_server fails with "certificate verify failed"System CA bundle outdatedapt install -y ca-certificates && update-ca-certificates and rerun
    SAML login redirects back to login pageIdP not sending email attribute, or cert mismatchInspect /var/log/zulip/errors.log for the SAML debug trace. Verify attribute mappers in Keycloak and re-export the IdP cert
    High RAM usage after a weekPostgres cache growing, RabbitMQ queue backlogNormal up to ~70%. If over 90%, run supervisorctl status to find stuck workers and rabbitmqctl list_queues name messages to check queue depth

    Viewing logs

    bash
    tail -f /var/log/zulip/errors.log /var/log/zulip/server.log

    Nginx access log:

    bash
    tail -f /var/log/nginx/access.log

    FAQ

    How many users can a single Zulip server handle?

    A Professional VPS (4 vCPU, 8 GB RAM) comfortably handles 100 active concurrent users with typical chat traffic. Scaling past 500 concurrent users usually means moving Postgres to its own host, adding a second Tornado process for long-poll connections, and putting an Nginx load balancer in front of two Django app servers. The Zulip deployment documentation covers every scaling boundary in detail; most self-hosted installs never need to split components because Zulip is remarkably efficient per message.

    Can I migrate our existing Slack history into Zulip?

    Yes. Export your Slack workspace from Settings → Workspace settings → Import/Export Data, then run Zulip's built-in converter: manage.py convert_slack_data slack-export.zip --output zulip-import/ followed by manage.py import zulip-import/. Channels become streams, threads become topics (collapsed per thread), and user accounts are matched by email. The process preserves timestamps, attachments, and emoji reactions. Zulip also has converters for Mattermost, Rocket.Chat, and Gitter, making cross-tool migration straightforward.

    Does Zulip support end-to-end encryption?

    Zulip uses TLS in transit and encrypts uploaded files on disk if you configure it to, but messages are not end-to-end encrypted — the server can read them, which is what lets full-text search, mobile push notifications, and the email gateway work. If you need true E2EE for a subset of conversations, use Matrix via Element alongside Zulip for those specific channels. For the overwhelming majority of team-chat use cases — where the threat model is external attackers, not a compromised server admin — Zulip's architecture is appropriate and auditable.

    How do I back up Zulip?

    Zulip provides a one-command backup that captures the Postgres database, Redis state, uploaded files, and configuration: /home/zulip/deployments/current/manage.py backup --output /var/backups/zulip-$(date +%F).tar.gz. Schedule it via cron nightly and ship the tarball to object storage (S3, Backblaze B2, Wasabi). Restore is symmetric: manage.py restore /var/backups/zulip-2026-04-15.tar.gz on a fresh install. For point-in-time recovery, enable Postgres WAL archiving separately.

    Can bots read and post messages like Slack bots?

    Yes, more flexibly. Zulip bots get a full API token and can subscribe to streams, receive every message as an event via a long-poll endpoint, and post responses. The Python zulip library wraps this cleanly; JavaScript, Go, and Ruby libraries are community-maintained. Zulip also supports embedded bots — small Python scripts that run inside the Zulip server process itself, useful for workflows like "every time someone posts a URL, fetch the title and reply". Documentation lives at zulip.readthedocs.io/en/stable/production/bots.html.

    How does Zulip compare to Mattermost and Rocket.Chat?

    Mattermost is Slack-shaped: channels, timeline threads, Slack-compatible UX. Best pick if your team already uses Slack and just wants the same mental model without the vendor. Rocket.Chat is Slack-shaped plus customer-facing livechat, omnichannel, and video conferencing baked in. Best pick if chat is customer-touching and you want one tool for internal and external conversation. Zulip is the odd one out — topic-based threading is genuinely different and takes a week to internalize. Teams that make the switch rarely go back, but it is a switch, not a drop-in replacement. Pick Zulip when deep asynchronous work and multi-timezone coordination are core to how the team operates.

    How do I upgrade Zulip to a new version?

    Download the new tarball and run upgrade-zulip: wget -N https://download.zulip.com/server/zulip-server-latest.tar.gz && /home/zulip/deployments/current/scripts/upgrade-zulip zulip-server-latest.tar.gz. The script stops services, runs migrations, installs the new deployment under /home/zulip/deployments/<timestamp>/, and swaps the current symlink atomically. If anything goes wrong, /home/zulip/deployments/current/scripts/restart-server using the previous timestamp directory rolls back. Subscribe to zulip-announce for security release notifications.

    Next Steps

    Now that Zulip is running, these are the highest-value follow-ups:

    • Set up nightly backups to object storage so you can survive a disk failure without losing a week of conversations.
    • Deploy Keycloak on Ubuntu 24.04 as your identity provider and wire Zulip's SAML backend to it — one password policy, one 2FA config, one audit log across every internal tool.
    • Wire up Mattermost or Rocket.Chat in parallel if your team has both an engineering audience (Zulip) and a customer-support audience (Rocket.Chat livechat) — they can coexist on separate subdomains of the same VPS.
    • Read the official operator guide at zulip.readthedocs.io for tuning Postgres, configuring S3-backed file uploads, and splitting Tornado onto its own host once your team crosses 300 active users.
    • Turn on message retention policies per-stream if your compliance regime requires deletion after N days — Zulip supports this natively without losing topic structure.
    • Enable 2FA for all accounts under Organization Settings → Authentication methods → Two factor authentication.

    Skip the Manual Install — Deploy a VPS Tuned for Zulip
    >
    Our Professional VPS plans are sized exactly for self-hosted team chat: 4 vCPU, 8 GB RAM, 100 GB NVMe, and unmetered bandwidth. Everything you need to run Zulip plus Keycloak and a backup target on the same server.
    >
    - Ubuntu 24.04 LTS preinstalled and patched
    - NVMe storage for fast Postgres
    - Full root access and unlimited bandwidth
    - Free DDoS protection and IPv6
    >
    Deploy Your Professional VPS Now — plans start at EUR 19.99/month.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket