Deployment Guide

    Zulip Team Chat

    Deploy a self-hosted Zulip instance on your RamNode VPS. Topic-based threaded conversations, no per-seat pricing, and full control of your data.

    Ubuntu 22.04
    PostgreSQL + Redis + RabbitMQ
    ⏱️ 20–30 minutes

    Why Self-Host Zulip on RamNode?

    Self-hosting Zulip gives you full control over your data, no per-seat pricing, and the ability to customize the platform to fit your team's workflow. RamNode's SSD VPS plans are a cost-effective fit with NVMe-backed storage, generous bandwidth, and straightforward pricing starting at $4/month.

    Small Teams

    $12/month plan (2 vCPU / 2GB RAM)

    Larger Organizations

    4GB RAM tier for sustained load

    Prerequisites

    • • A RamNode VPS running Ubuntu 22.04 LTS (recommended by the Zulip project)
    • • A domain name pointed to your VPS IP (e.g., chat.yourdomain.com)
    • • Root or sudo access to your server
    • • A working email address for the initial admin account

    Important: Zulip's installer requires a fresh OS install and will configure Nginx, PostgreSQL, Redis, and RabbitMQ automatically. Do not run this on a server with existing web services.

    2

    Provision Your RamNode VPS

    Log into your RamNode control panel and deploy a new VPS:

    1. Select Ubuntu 22.04 LTS as your OS
    2. Choose at minimum 2GB RAM (4GB recommended for production)
    3. Select your preferred datacenter location
    4. Set a strong root password or add your SSH public key

    Once provisioned, note your server's IP address.

    3

    Point Your Domain to the VPS

    In your DNS provider, create an A record pointing your desired subdomain to your VPS IP:

    DNS A Record
    Type: A
    Name: chat
    Value: YOUR_VPS_IP
    TTL: 300

    Allow a few minutes for DNS propagation before proceeding. Zulip's installer will attempt to verify DNS and provision a Let's Encrypt TLS certificate automatically.

    4

    Initial Server Setup

    SSH and Update
    ssh root@YOUR_VPS_IP
    apt update && apt upgrade -y
    apt install -y curl wget git

    Set Hostname

    Configure Hostname
    hostnamectl set-hostname chat.yourdomain.com
    echo "127.0.1.1 chat.yourdomain.com chat" >> /etc/hosts
    5

    Download the Zulip Installer

    Download the latest Zulip Server release. Always check zulip.com/server for the latest version before installing.

    Download Zulip
    cd /root
    wget https://download.zulip.com/server/zulip-server-latest.tar.gz
    tar -xf zulip-server-latest.tar.gz
    cd zulip-server-*/
    6

    Run the Zulip Installer

    The installer handles the entire stack configuration. Run it with your domain and admin email:

    Install Zulip
    ./scripts/setup/install --certbot-email=you@yourdomain.com \
                            --hostname=chat.yourdomain.com

    What this does:

    • • Installs and configures Nginx as a reverse proxy with TLS via Certbot
    • • Sets up PostgreSQL for the Zulip database
    • • Configures Redis for caching and session storage
    • • Installs RabbitMQ for background job processing
    • • Deploys the Zulip Django application with Supervisor

    The installation typically takes 5 to 10 minutes.

    💡 Note: If DNS has not fully propagated yet, Let's Encrypt certificate issuance may fail. You can skip TLS during setup with --no-init-db and configure it manually afterward, or wait and re-run the installer once DNS resolves.

    7

    Create Your Organization

    Once the installer completes, generate a one-time organization creation link:

    Generate Organization Link
    su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'

    Open the output URL in your browser. You will be prompted to:

    1. Set your organization name
    2. Create the admin user account
    3. Choose your organization type (company, community, education, etc.)
    8

    Configure Email (SMTP)

    Zulip requires a working SMTP connection for invitations, password resets, and notifications. Edit the configuration file:

    Edit Settings
    nano /etc/zulip/settings.py

    Example using a generic SMTP provider (Mailgun, Postmark, or Amazon SES recommended):

    /etc/zulip/settings.py (email section)
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = 'smtp.yourprovider.com'
    EMAIL_HOST_USER = 'you@yourdomain.com'
    EMAIL_HOST_PASSWORD = 'your-smtp-password'
    EMAIL_PORT = 587
    EMAIL_USE_TLS = True

    Restart Zulip to apply changes:

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

    Test email delivery from the Zulip admin panel under Server settings → Email.

    9

    Configure the Firewall

    UFW Rules
    ufw allow OpenSSH
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw enable
    ufw status verbose

    Zulip's Nginx configuration already handles HTTP to HTTPS redirection. Port 80 only needs to be open for Certbot's certificate renewal challenge.

    10

    Enable Automatic Certificate Renewal

    Certbot installs a systemd timer for automatic renewal. Verify it is active:

    Check Certbot Timer
    systemctl status certbot.timer

    Do a dry run to confirm renewal will work:

    Dry Run
    certbot renew --dry-run
    11

    Set Up Automated Backups

    Zulip includes a built-in backup utility. Create a full backup:

    Manual Backup
    /home/zulip/deployments/current/manage.py backup --output=/root/zulip-backup.tar.gz

    Schedule Daily Backups

    Add to Crontab
    crontab -e

    Add the following line to run a backup every day at 2:00 AM:

    Cron Entry
    0 2 * * * /home/zulip/deployments/current/manage.py backup --output=/root/backups/zulip-$(date +\%F).tar.gz

    Tip: For off-server backup storage, sync your backup directory to an S3-compatible bucket using rclone or aws-cli. Keeping backups only on the same VPS is not a disaster recovery strategy.

    12

    Keeping Zulip Updated

    Upgrade Zulip
    # Download the latest release
    wget https://download.zulip.com/server/zulip-server-latest.tar.gz -O /tmp/zulip.tar.gz
    
    # Run the upgrade script
    /home/zulip/deployments/current/scripts/upgrade-zulip /tmp/zulip.tar.gz

    The upgrade script handles database migrations and service restarts automatically. Always read the Zulip changelog before major version upgrades.

    Performance Tuning for RamNode VPS

    PostgreSQL (2GB RAM VPS)

    /etc/postgresql/*/main/postgresql.conf
    shared_buffers = 256MB
    work_mem = 4MB
    maintenance_work_mem = 64MB
    effective_cache_size = 768MB
    Restart PostgreSQL
    systemctl restart postgresql

    Add Swap Space

    Zulip can spike in memory usage during heavy indexing. Adding swap provides a safety buffer on lower-RAM plans:

    Create Swap File
    fallocate -l 2G /swapfile
    chmod 600 /swapfile
    mkswap /swapfile
    swapon /swapfile
    echo '/swapfile none swap sw 0 0' >> /etc/fstab

    Architecture Summary

    ComponentHandled By
    Web server / TLSNginx + Certbot
    Application serverDjango + Supervisor
    DatabasePostgreSQL
    Message queueRabbitMQ
    Cache / sessionsRedis
    BackupsZulip built-in CLI

    Troubleshooting

    Installer fails at Let's Encrypt step

    DNS has not propagated yet. Wait a few minutes and re-run the installer, or use --no-init-db to skip TLS and configure Certbot manually afterward.

    Zulip services are not starting

    Check supervisor status for individual service errors:

    Check Services
    supervisorctl status
    supervisorctl tail -f zulip-django

    Email is not being delivered

    Verify SMTP credentials in /etc/zulip/settings.py and use the admin panel's built-in email test. Check that port 587 is not blocked at the network level.

    High memory usage

    Zulip runs several worker processes. On a 2GB VPS, reduce Tornado workers in /etc/zulip/zulip.conf under [application_server] by setting tornado_processes = 1.