Cómo instalar Zulip Chat Server usando Docker en Rocky Linux 9
Zulip es un servidor de chat de código abierto similar a Microsoft Teams, Rocket Chat o Slack. Está escrito en Python y utiliza Django, PostgreSQL y JavaScript. Se integra con más de 90 plugins de terceros, como Github, Jira, Stripe, Zendesk, Sentry, etc. Puedes ampliar las integraciones conectándolas con Zapier e IFTTT. Incluye funciones como mensajería privada, chats de grupo, conversaciones hilvanadas, canales personalizados, videollamadas, carga de archivos mediante arrastrar y soltar, emojis personalizados, integración con Giphy, previsualización de imágenes y tweets, y muchas más. Zulip viene con aplicaciones de escritorio y móviles para todas las plataformas, por lo que es agnóstico en cuanto a plataformas.
Este tutorial te enseña a instalar y configurar Zulip Chat en un servidor Rocky Linux 9.
Requisitos previos
- Un servidor con Rocky Linux 9.
- Al menos 2 GB de RAM si esperas menos de 100 usuarios. Para más de 100 usuarios, consigue un servidor de 4 GB de RAM y 2 CPU.
- Un usuario no root con privilegios sudo.
- Un nombre de dominio configurado para apuntar al servidor,
zulip.example.com. - Todo actualizado.
$ sudo dnf update
- Pocos paquetes que necesite tu sistema.
$ sudo dnf install wget curl nano unzip yum-utils policycoreutils-python-utils -y
Puede que algunos de estos paquetes ya estén instalados en tu sistema.
Paso 1 – Configurar el cortafuegos
Antes de instalar ningún paquete, el primer paso es configurar el cortafuegos para abrir puertos para HTTP, y HTTPS. Rocky Linux utiliza el cortafuegos Firewalld. Comprueba el estado del cortafuegos.
$ sudo firewall-cmd --state running
El cortafuegos funciona con diferentes zonas, y la zona pública es la que utilizaremos por defecto. Enumera todos los servicios y puertos activos en el cortafuegos.
$ sudo firewall-cmd --zone=public --list-all
Debería mostrar la siguiente salida.
public target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client ssh ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
Abre los puertos HTTP y HTTPS en el cortafuegos.
$ sudo firewall-cmd --zone=public --add-service=http $ sudo firewall-cmd --zone=public --add-service=https
Vuelve a comprobar el estado del cortafuegos.
$ sudo firewall-cmd --zone=public --list-all
Deberías ver un resultado similar.
public target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client http https ssh ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
Haz permanentes todos los cambios y vuelve a cargar el cortafuegos para activar los cambios.
$ sudo firewall-cmd --runtime-to-permanent $ sudo firewall-cmd --reload
Paso 2 – Instala Docker y Docker Compose
Instala el repositorio oficial de Docker.
$ sudo dnf install yum-utils
$ sudo dnf config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Instala Docker.
$ sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Habilita y ejecuta el demonio Docker.
$ sudo systemctl enable docker --now
Comprueba el estado del servicio Docker.
$ sudo systemctl status docker
? docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled)
Active: active (running) since Tue 2024-02-06 07:17:33 UTC; 5s ago
TriggeredBy: ? docker.socket
Docs: https://docs.docker.com
Main PID: 22302 (dockerd)
Tasks: 10
Memory: 31.3M
CPU: 198ms
CGroup: /system.slice/docker.service
??22302 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Añade tu usuario de sistema al grupo Docker para evitar utilizar sudo para ejecutar comandos Docker.
$ sudo usermod -aG docker $(whoami)
Vuelve a acceder a tu servidor después de cerrar la sesión para activar el cambio.
Paso 3 – Instalar Nginx
Para el entorno de producción, se recomienda ejecutar el servidor Synapse utilizando un proxy Nginx.
Rocky Linux 9 viene con una versión antigua de Nginx. Necesitas utilizar el repositorio oficial de Nginx para instalar la última versión.
Crea y abre el archivo /etc/yum.repos.d/nginx.repo para editarlo.
$ sudo nano /etc/yum.repos.d/nginx.repo
Pega en él el siguiente código.
[nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true
Cuando hayas terminado, guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Vamos a instalar la versión principal de Nginx, así que habilita el paquete correspondiente.
$ sudo dnf config-manager --enable nginx-mainline
Instala Nginx.
$ sudo dnf install nginx -y
Verifica la instalación.
$ nginx -v nginx version: nginx/1.25.3
Habilita e inicia el servicio del servidor Nginx.
$ sudo systemctl enable nginx --now
Comprueba el estado del servicio.
$ sudo systemctl status nginx
? nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
Active: active (running) since Tue 2024-02-06 07:18:56 UTC; 5s ago
Docs: http://nginx.org/en/docs/
Process: 22762 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 22763 (nginx)
Tasks: 5 (limit: 50339)
Memory: 4.9M
CPU: 16ms
CGroup: /system.slice/nginx.service
??22763 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf"
??22764 "nginx: worker process"
??22765 "nginx: worker process"
??22766 "nginx: worker process"
??22767 "nginx: worker process"
Paso 4 – Instalar SSL
Necesitamos instalar Certbot para generar el certificado SSL. Para ello utilizaremos el instalador de paquetes Snapd. Como Rocky Linux no lo incluye, instala el instalador Snapd. Necesita el repositorio EPEL (Extra Packages for Enterprise Linux) para funcionar.
Instala el repositorio EPEL.
$ sudo dnf install epel-release -y
Instala el paquete Snapd.
$ sudo dnf install snapd -y
Activa e inicia el servicio Snap.
$ sudo systemctl enable snapd --now
Instala el paquete Snap core, y asegúrate de que tu versión de Snapd está actualizada.
$ sudo snap install core && sudo snap refresh core
Crea los enlaces necesarios para que Snapd funcione.
$ sudo ln -s /var/lib/snapd/snap /snap $ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
Instala Certbot.
$ sudo snap install --classic certbot
Asegúrate de que se puede ejecutar el comando Certbot creando un enlace simbólico al directorio /usr/bin.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Comprueba la versión de Certbot.
$ certbot --version certbot 2.8.0
Ejecuta el siguiente comando para generar un certificado SSL.
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d zulip.example.com
El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/zulip.example.com de tu servidor.
Genera un certificado de grupo Diffie-Hellman.
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
Comprueba el servicio programador de renovación de Certbot.
$ systemctl list-timers
Encontrarás snap.certbot.renew.service como uno de los servicios programados para ejecutarse.
NEXT LEFT LAST PASSED UNIT ACTIVATES ---------------------------------------------------------------------------------------------------------------------------------- Tue 2024-02-06 07:30:00 UTC 6min left Tue 2024-02-06 07:20:11 UTC 3min 41s ago sysstat-collect.timer sysstat-collect.service Tue 2024-02-06 08:22:43 UTC 58min left Tue 2024-02-06 07:22:39 UTC 1min 13s ago dnf-makecache.timer dnf-makecache.service Tue 2024-02-06 09:36:00 UTC 2h 12min left - - snap.certbot.renew.timer snap.certbot.renew.service
Realiza una ejecución en seco del proceso para comprobar si la renovación SSL funciona correctamente.
$ sudo certbot renew --dry-run
Si no ves ningún error, ya está todo listo. Tu certificado se renovará automáticamente.
Paso 5 – Configurar SELinux
Aplica la política para permitir conexiones a hosts externos.
$ sudo setsebool -P httpd_can_network_connect 1
Aplica la política para permitir que Nginx dé acceso a PostgreSQL.
$ sudo setsebool -P httpd_can_network_connect_db 1
Paso 6 – Preparar y configurar Zulip para la instalación
En primer lugar, crea una clave secreta para Zulip. Guarda la clave generada porque la necesitaremos más adelante.
$ openssl rand -base64 32 sLIeucGPMCNbR0LwcRhyXafXmputmtse6+EYU04+9JY=
Crea un directorio para el archivo Zulip Docker Compose y pasa a él.
$ mkdir ~/docker-zulip $ cd ~/docker-zulip
Crea y abre el archivo de entorno para editarlo.
$ nano .env
Pega en él el siguiente código.
[email protected] EXTERNAL_HOST=zulip.example.com ZULIP_AUTH_BACKENDS=EmailAuthBackend ZULIP_PUSH_NOTIFICATION_BOUNCER_URL=https://push.zulipchat.com DISABLE_HTTPS=true SSL_CERTIFICATE_GENERATION=self-signed EMAIL_HOST=email-smtp.us-west-2.amazonaws.com EMAIL_HOST_USER=AMAZONSESUSERNAME EMAIL_PASSWORD=AMAZONSESPASSWORD EMAIL_PORT=465 EMAIL_USE_SSL=True EMAIL_USE_TLS=False [email protected] ZULIP_GIT_URL=https://github.com/zulip/zulip.git ZULIP_GIT_REF=8.2 SECRET_KEY=sLIeucGPMCNbR0LwcRhyXafXmputmtse6+EYU04+9JY= POSTGRES_USER=zulip POSTGRES_DB=zulip POSTGRES_PASSWORD=REPLACE_WITH_SECURE_POSTGRES_PASSWORD REDIS_PASSWORD=REPLACE_WITH_SECURE_REDIS_PASSWORD MEMCACHED_PASSWORD=REPLACE_WITH_SECURE_MEMCACHED_PASSWORD RABBITMQ_DEFAULT_USER=zulip RABBITMQ_DEFAULT_PASS=REPLACE_WITH_SECURE_RABBITMQ_PASSWORD
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida una vez hayas terminado.
Repasemos todas las variables que hemos definido.
- ZULIP_ADMINISTRATOR – es la dirección de correo electrónico principal de la cuenta de administrador creada durante la instalación.
- EXTERNAL_HOST – es el nombre de dominio que utilizaremos para nuestra instalación de Zulip.
- ZULIP_AUTH_BACKENDS – define el método para iniciar sesión. Nosotros utilizamos
EmailAuthBackend, lo que significa que Zulip te pedirá una dirección de correo electrónico y una contraseña. Existen otros métodos de autenticación que utilizan credenciales de Google, GitHub y Apple para iniciar sesión. Puedes encontrar más información en la documentación de Zulip y en el archivo por defectosettings.pypor defecto. - ZULIP_PUSH_NOTIFICATION_BOUNCER_URL – es la URL que Zulip utilizará para enviar notificaciones push móviles. Para la versión comunitaria de Zulip para una organización con 10 o menos usuarios, las notificaciones push son gratuitas. Tu organización aún puede optar a notificaciones push ilimitadas gratuitas en función de los requisitos. Consulta la documentación de facturación de Z ulip para más detalles.
- DISABLE_HTTPS – Lo hemos puesto a true para desactivar SSL para Zulip porque lo gestionaremos fuera del contenedor.
- SSL_CERTIFICATE_GENERATION – Como hemos deshabilitado SSL para Zulip, necesitamos configurarlo para generar certificados autofirmados.
- EMAIL_HOST – El host de correo SMTP que necesitamos para activar las notificaciones por correo electrónico. Aquí estamos utilizando el servicio de correo electrónico Amazon SES para nuestro tutorial.
- EMAIL_HOST_USER – El nombre de usuario del correo SMTP.
- EMAIL_PASSWORD – La contraseña del correo electrónico SMTP.
- EMAIL_PORT – El puerto de correo SMTP.
- EMAIL_USE_SSL – Si el host SMTP admite autenticación SSL.
- EMAIL_USE_TLS – Si el host SMTP admite autenticación TLS.
- EMAIL_NOREPLY_ADD – La dirección de correo electrónico sin respuesta utilizada para enviar correos electrónicos de notificación.
- ZULIP_GIT_URL – Estamos utilizando la imagen docker de Zulip, pero si quieres crear una imagen personalizada, debes introducir la URL del repositorio Git de Zulip.
- ZULIP_GIT_REF – La versión de Zulip a utilizar del repositorio Git para construir la imagen docker.
- SECRET_KEY – Una clave secreta fuerte que Zulip necesita para la autenticación. Introduce la clave que hemos creado antes.
- POSTGRES_USER – Elige un nombre de usuario para tu usuario PostgreSQL.
- POSTGRES_DB – Elige el nombre de la base de datos para tu base de datos PostgreSQL.
- POSTGRES_PASSWORD – Elige una contraseña segura para la base de datos PostgreSQL.
- REDIS_PASSWORD – Elige una contraseña segura para la base de datos Redis.
- MEMCACHED_PASSWORD – Elige una contraseña segura para el servicio Memcached.
- RABBITMQ_DEFAULT_USER – Elige un nombre de usuario para el servicio RabbitMQ.
- RABBITMQ_DEFAULT_PASS – Elige una contraseña segura para el servicio RabbitMQ.
Crea y abre el archivo Docker compose para editarlo.
$ nano docker-compose.yml
Añade el siguiente código para definir el servicio database.
services:
database:
image: "zulip/zulip-postgresql:14"
container_name: zulip-db
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- "postgresql-14:/var/lib/postgresql/data:rw"
networks:
network:
ipv4_address: 10.5.0.2
El servicio database contiene las siguientes opciones:
- image – Indica a Docker que extraiga la imagen
zulip-postgresql:14. Aunque la última versión de Zulip admite PostgreSQL 16, la imagen docker correspondiente sólo admite PostgreSQL 14. - nombre_contenedor – especifica un nombre para el contenedor.
- reinicio – define la política de reinicio del contenedor. Hemos configurado el contenedor para que se reinicie automáticamente a menos que se detenga manualmente.
- environment – Debes establecer variables de entorno para el contenedor. Hemos establecido tres variables que definen la base de datos PostgreSQL, el nombre de usuario y la contraseña.
- volúmenes – Aquí creamos un volumen con nombre llamado
postgresql-14que apunta al directorio de datos PostgreSQL en el contenedor. - redes – utilizamos esto para dar al contenedor una dirección IP estática que pueda utilizarse para acceder a él desde otros contenedores.
A continuación, debajo de la sección del servicio database, añade la definición del servicio memcached.
memcached:
image: "memcached:alpine"
restart: unless-stopped
container_name: zulip-memcached
command:
- "sh"
- "-euc"
- |
echo 'mech_list: plain' > "$$SASL_CONF_PATH"
echo "zulip@$$HOSTNAME:$$MEMCACHED_PASSWORD" > "$$MEMCACHED_SASL_PWDB"
echo "zulip@localhost:$$MEMCACHED_PASSWORD" >> "$$MEMCACHED_SASL_PWDB"
exec memcached -S
environment:
SASL_CONF_PATH: "/home/memcache/memcached.conf"
MEMCACHED_SASL_PWDB: "/home/memcache/memcached-sasl-db"
MEMCACHED_PASSWORD: ${MEMCACHED_PASSWORD}
networks:
network:
ipv4_address: 10.5.0.3
El servicio memcached contiene las siguientes definiciones específicas para él:
- imagen – Aquí utilizaremos la imagen
memcached:alpinepara el contenedor. Una imagen alpina reduce el tamaño de la imagen, ya que sólo incluye lo esencial. - comando – Aquí ejecutaremos algunos comandos que se ejecutan tras la creación del contenedor para configurar Memcached y establecer las credenciales de Zulip. Estos comandos también anulan los comandos por defecto declarados por la imagen.
- entorno – Aquí establecemos la ubicación del archivo de configuración de Memcached, el archivo de la base de datos de contraseñas y la contraseña.
- red – Aquí establecemos una dirección IP privada única para el contenedor docker.
A continuación, añade la definición del servicio rabbitmq debajo de la sección memcached.
rabbitmq:
image: "rabbitmq:alpine"
restart: unless-stopped
container_name: zulip-rabbitmq
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
volumes:
- "rabbitmq:/var/lib/rabbitmq:rw"
networks:
network:
ipv4_address: 10.5.0.4
El servicio rabbitmq contiene las siguientes definiciones específicas para él:
- image – Al igual que antes, utilizaremos la imagen alpine para el contenedor RabbitMQ.
- entorno – Usamos la sección entorno para establecer el nombre de usuario y la contraseña por defecto de RabbitMQ.
- volúmenes – Aquí creamos un volumen con nombre llamado
rabbitmqque apunta al directorio RabbitMQ en el contenedor. - red – Igual que antes, establecemos una dirección IP única para el contenedor.
A continuación, añade la definición del servicio redis debajo de la sección rabbitmq.
redis:
image: "redis:alpine"
restart: unless-stopped
container_name: zulip-redis
command:
- "sh"
- "-euc"
- |
echo "requirepass '$$REDIS_PASSWORD'" > /etc/redis.conf
exec redis-server /etc/redis.conf
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD}
volumes:
- "redis:/data:rw"
networks:
network:
ipv4_address: 10.5.0.5
El servicio redis contiene las siguientes definiciones específicas para él:
- imagen – Aquí utilizaremos la imagen alpina para el contenedor Redis.
- comando – Utilizaremos los comandos para configurar la contraseña de Redis e iniciar el servidor con ella.
- volúmenes – Aquí creamos un volumen con nombre llamado
redisque apunta al directorio de datos del contenedor. - red – Igual que antes, establecemos una dirección IP única para el contenedor Redis.
Por último, añade la definición del servicio zulip debajo de la sección redis.
zulip:
image: "zulip/docker-zulip:8.2-0"
restart: unless-stopped
container_name: zulip
ports:
- "8080:80"
environment:
DB_HOST: "database"
DB_HOST_PORT: "5432"
DB_USER: ${POSTGRES_USER}
DISABLE_HTTPS: ${DISABLE_HTTPS}
SSL_CERTIFICATE_GENERATION: ${SSL_CERTIFICATE_GENERATION}
LOADBALANCER_IPS: 10.5.0.0/16
SETTING_MEMCACHED_LOCATION: "memcached:11211"
SETTING_RABBITMQ_HOST: "rabbitmq"
SETTING_REDIS_HOST: "redis"
SECRETS_email_password: ${EMAIL_PASSWORD}
SECRETS_rabbitmq_password: ${RABBITMQ_DEFAULT_PASS}
SECRETS_postgres_password: ${POSTGRES_PASSWORD}
SECRETS_memcached_password: ${MEMCACHED_PASSWORD}
SECRETS_redis_password: ${REDIS_PASSWORD}
SECRETS_secret_key: ${SECRET_KEY}
SETTING_EXTERNAL_HOST: ${EXTERNAL_HOST}
SETTING_ZULIP_ADMINISTRATOR: ${ZULIP_ADMINISTRATOR}
SETTING_EMAIL_HOST: ${EMAIL_HOST}
SETTING_EMAIL_HOST_USER: ${EMAIL_HOST_USER}
SETTING_EMAIL_PORT: ${EMAIL_PORT}
SETTING_EMAIL_USE_SSL: ${EMAIL_USE_SSL}
SETTING_EMAIL_USE_TLS: ${EMAIL_USE_TLS}
ZULIP_AUTH_BACKENDS: ${ZULIP_AUTH_BACKENDS}
SETTING_NOREPLY_EMAIL_ADDRESS: ${EMAIL_NOREPLY_ADD}
# Uncomment this when configuring the mobile push notifications service
# SETTING_PUSH_NOTIFICATION_BOUNCER_URL: ${ZULIP_PUSH_NOTIFICATION_BOUNCER_URL}
volumes:
- "zulip:/data:rw"
ulimits:
nofile:
soft: 1000000
hard: 1048576
networks:
network:
ipv4_address: 10.5.0.6
El servicio zulip contiene las siguientes definiciones específicas para él:
- puertos – El contenedor Zulip ejecuta nginx como parte del proceso. Aquí hemos asignado el puerto 80 del contenedor al puerto 8080 del servidor anfitrión. Lo utilizaremos más adelante para configurar Nginx como gestor proxy fuera del contenedor.
- entorno – Aquí configuramos variables de entorno para configurar Zulip. La mayoría de las variables de entorno se recogen del archivo
.envque hemos explicado antes. El host de la base de datos se establece en el servicio de contenedordatabasey el puerto en el puerto predeterminado PostgreSQL 5432. La variableLOADBALANCER_IPSse establece en la subred de red de Docker. Esto es necesario para que Zulip funcione desde detrás de un servidor proxy inverso. La variableMEMCACHED_LOCATIONse establece en el serviciomemcachedcon su puerto por defecto 11211. Del mismo modo, hemos configurado los hosts RabbitMQ y Redis para que apunten a sus respectivos servicios de contenedor. - volúmenes – Aquí establecemos un volumen con nombre y lo fijamos en el directorio
/dataen modo lectura-escritura. - ulimits – Aquí establecemos los límites blandos y duros para el uso de recursos del usuario para el contenedor.
- networks – Igual que antes, establecemos una dirección IP única para el contenedor Zulip.
Y por último, pega el siguiente código.
volumes:
zulip:
postgresql-14:
rabbitmq:
redis:
networks:
network:
driver: bridge
ipam:
config:
- subnet: 10.5.0.0/16
gateway: 10.5.0.1
Aquí definimos los volúmenes con nombre que creamos anteriormente para nuestros contenedores. A continuación, definimos la red puente para conectar todos los contenedores y proporcionamos las direcciones IP de subred y puerta de enlace.
Una vez terminado, guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida una vez terminado.
El archivo Docker compose terminado tendrá el siguiente aspecto.
services:
database:
image: "zulip/zulip-postgresql:14"
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- "postgresql-14:/var/lib/postgresql/data:rw"
networks:
network:
ipv4_address: 10.5.0.2
memcached:
image: "memcached:alpine"
restart: unless-stopped
command:
- "sh"
- "-euc"
- |
echo 'mech_list: plain' > "$$SASL_CONF_PATH"
echo "zulip@$$HOSTNAME:$$MEMCACHED_PASSWORD" > "$$MEMCACHED_SASL_PWDB"
echo "zulip@localhost:$$MEMCACHED_PASSWORD" >> "$$MEMCACHED_SASL_PWDB"
exec memcached -S
environment:
SASL_CONF_PATH: "/home/memcache/memcached.conf"
MEMCACHED_SASL_PWDB: "/home/memcache/memcached-sasl-db"
MEMCACHED_PASSWORD: ${MEMCACHED_PASSWORD}
networks:
network:
ipv4_address: 10.5.0.3
rabbitmq:
image: "rabbitmq:alpine"
restart: unless-stopped
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
volumes:
- "rabbitmq:/var/lib/rabbitmq:rw"
networks:
network:
ipv4_address: 10.5.0.4
redis:
image: "redis:alpine"
restart: unless-stopped
command:
- "sh"
- "-euc"
- |
echo "requirepass '$$REDIS_PASSWORD'" > /etc/redis.conf
exec redis-server /etc/redis.conf
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD}
volumes:
- "redis:/data:rw"
networks:
network:
ipv4_address: 10.5.0.5
zulip:
image: "zulip/docker-zulip:8.1-0"
restart: unless-stopped
#build:
# context: .
# args:
# ZULIP_GIT_URL: ${ZULIP_GIT_URL}
# ZULIP_GIT_REF: ${ZULIP_GIT_REF}
# Set this up if you plan to use your own CA certificate bundle for building
# CUSTOM_CA_CERTIFICATES: ${ZULIP_CUSTOM_CA_CERTIFICATES}
ports:
- "8080:80"
environment:
DB_HOST: 10.5.0.2
DB_HOST_PORT: "5432"
DB_USER: ${POSTGRES_USER}
DISABLE_HTTPS: ${DISABLE_HTTPS}
LOADBALANCER_IPS: 10.5.0.6
SSL_CERTIFICATE_GENERATION: ${SSL_CERTIFICATE_GENERATION}
SETTING_MEMCACHED_LOCATION: "memcached:11211"
SETTING_RABBITMQ_HOST: "rabbitmq"
SETTING_REDIS_HOST: "redis"
SECRETS_email_password: ${EMAIL_PASSWORD}
SECRETS_rabbitmq_password: ${RABBITMQ_DEFAULT_PASS}
SECRETS_postgres_password: ${POSTGRES_PASSWORD}
SECRETS_memcached_password: ${MEMCACHED_PASSWORD}
SECRETS_redis_password: ${REDIS_PASSWORD}
SECRETS_secret_key: ${SECRET_KEY}
SETTING_EXTERNAL_HOST: ${EXTERNAL_HOST}
SETTING_ZULIP_ADMINISTRATOR: ${ZULIP_ADMINISTRATOR}
SETTING_EMAIL_HOST: ${EMAIL_HOST}
SETTING_EMAIL_HOST_USER: ${EMAIL_HOST_USER}
SETTING_EMAIL_PORT: ${EMAIL_PORT}
SETTING_EMAIL_USE_SSL: ${EMAIL_USE_SSL}
SETTING_EMAIL_USE_TLS: ${EMAIL_USE_TLS}
ZULIP_AUTH_BACKENDS: ${ZULIP_AUTH_BACKENDS}
SETTING_NOREPLY_EMAIL_ADDRESS: ${EMAIL_NOREPLY_ADD}
# Uncomment this when configuring the mobile push notifications service
# SETTING_PUSH_NOTIFICATION_BOUNCER_URL: ${ZULIP_PUSH_NOTIFICATION_BOUNCER_URL}
volumes:
- "zulip:/data:rw"
ulimits:
nofile:
soft: 1000000
hard: 1048576
networks:
network:
ipv4_address: 10.5.0.6
volumes:
zulip:
postgresql-14:
rabbitmq:
redis:
networks:
network:
driver: bridge
ipam:
config:
- subnet: 10.5.0.0/16
gateway: 10.5.0.1
Paso 7 – Instalar Zulip
Inicia el contenedor Zulip utilizando el siguiente comando.
$ docker compose up -d
Comprueba el estado de los contenedores utilizando los siguientes comandos.
$ docker ps
Deberías ver una salida similar.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fea5d02f53d7 rabbitmq:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 4369/tcp, 5671-5672/tcp, 15691-15692/tcp, 25672/tcp zulip-rabbitmq 01cb77f16c1a zulip/zulip-postgresql:14 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5432/tcp zulip-db f5b6523a3a8c zulip/docker-zulip:8.2-0 "/sbin/entrypoint.sh…" 2 minutes ago Up 2 minutes 443/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp zulip c0a358209b09 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp zulip-redis 27be352a0a35 memcached:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 11211/tcp zulip-memcached
También puedes utilizar el siguiente comando para lo mismo.
$ docker compose ps
En este caso, tu salida sería como la siguiente.
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS zulip zulip/docker-zulip:8.2-0 "/sbin/entrypoint.sh…" zulip About a minute ago Up About a minute 443/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp zulip-db zulip/zulip-postgresql:14 "docker-entrypoint.s…" database About a minute ago Up About a minute 5432/tcp zulip-memcached memcached:alpine "docker-entrypoint.s…" memcached About a minute ago Up About a minute 11211/tcp zulip-rabbitmq rabbitmq:alpine "docker-entrypoint.s…" rabbitmq About a minute ago Up About a minute 4369/tcp, 5671-5672/tcp, 15691-15692/tcp, 25672/tcp zulip-redis redis:alpine "docker-entrypoint.s…" redis About a minute ago Up About a minute 6379/tcp
El contenedor Zulip tardará algún tiempo en empezar a funcionar. Puedes seguir el progreso utilizando el siguiente comando.
$ docker logs zulip --follow
Verás una larga lista de comandos que se ejecutan para configurar el contenedor. Una vez que veas la siguiente salida, significa que Zulip está instalado.
2024-02-21 09:02:55,310 INFO success: go-camo entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: smokescreen entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip-django entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip-tornado entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip_deliver_scheduled_emails entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip_deliver_scheduled_messages entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: process-fts-updates entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: cron entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip_events_deferred_work entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip_events_digest_emails entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,311 INFO success: zulip_events_email_mirror entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_embed_links entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_embedded_bots entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_invites entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_email_senders entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_missedmessage_emails entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_missedmessage_mobile_notifications entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_outgoing_webhooks entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_user_activity entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_user_activity_interval entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2024-02-21 09:02:55,312 INFO success: zulip_events_user_presence entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Pulsa Ctrl + C para salir de la pantalla. Zulip está instalado. Sin embargo, aún tenemos que configurar Nginx para que sirva a Zulip.
Paso 8 – Configurar Nginx
Abre el archivo /etc/nginx/nginx.conf para editarlo.
$ sudo nano /etc/nginx/nginx.conf
Añade la siguiente línea antes de la línea include /etc/nginx/conf.d/*.conf;.
server_names_hash_bucket_size 64;
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.
Crea y abre el archivo /etc/nginx/conf.d/zulip.conf para editarlo.
$ sudo nano /etc/nginx/conf.d/zulip.conf
Pega en él el siguiente código.
server {
listen 80;
listen [::]:80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name zulip.example.com;
ssl_certificate /etc/letsencrypt/live/zulip.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/zulip.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/zulip.example.com/chain.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] 8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=60s;
resolver_timeout 2s;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
tcp_nopush on;
gzip on;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_buffering off;
proxy_read_timeout 20m;
proxy_pass http://127.0.0.1:8080;
}
}
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite una vez hayas terminado.
Comprueba la sintaxis del archivo de configuración de Nginx.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Reinicia el servicio Nginx.
$ sudo systemctl restart nginx
Paso 9 – Acceder a la interfaz de Zulip
Visita https://zulip.example.com/ en tu navegador, y aparecerá la siguiente pantalla.

Utilizando el enlace Nueva Organización de la parte superior accederás a la siguiente página.

Como puedes ver, Zulip no te permite crear una organización desde el front-end. Vuelve al terminal y ejecuta el siguiente comando para crear la URL de la página de la nueva organización. Hablaremos más sobre cómo utilizar los comandos de Zulip en la siguiente sección.
$ docker compose exec -u zulip zulip /home/zulip/deployments/current/manage.py generate_realm_creation_link
Please visit the following secure single-use link to register your
new Zulip organization:
https://zulip.example.com/new/svvss33z4qmwewmanbbcalen
Abre la URL https://zulip.example.com/new/cjjivovgcillw44z7gsnobkv en tu navegador y accederás a la siguiente página.

Introduce el nombre de tu organización, el tipo de organización, el idioma y el ID de correo electrónico para empezar a crear tu organización. Haz clic en el botón Crear organización para continuar.
En la siguiente pantalla se te pedirá que configures una cuenta.

Introduce tu nombre, elige una contraseña para iniciar sesión y haz clic en el botón Registrarse para continuar.
Una vez terminado, se abrirá el panel de control de Zulip y podrás empezar a utilizarlo.

Paso 10 – Comandos del Servidor Zulip
De vez en cuando, para ejecutar comandos de Zulip Server, necesitarás acceder al shell del contenedor. Para acceder al shell como usuario zulip, utiliza el siguiente comando.
$ docker compose exec -u zulip zulip bash
O puedes utilizar el siguiente comando.
$ docker exec -itu zulip zulip bash
Para ejecutar un comando dentro de un contenedor, puedes ejecutarlo utilizando un único comando, como se indica a continuación.
$ docker compose exec -u zulip zulip \
/home/zulip/deployments/current/manage.py help <subcommand>
Sin embargo, hay un método más sencillo de hacerlo. Podemos crear un script de shell para ejecutar comandos. Crea y abre zulip_manage.sh para editarlo.
$ nano zulip_manage.sh
Pega en él el siguiente código.
#!/bin/sh docker compose exec -u zulip zulip /home/zulip/deployments/current/manage.py "$@"
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Haz que el script sea ejecutable.
$ chmod +x zulip_manage.sh
Para detener el servidor Zulip, utiliza el siguiente comando.
$ docker exec -u zulip zulip /home/zulip/deployments/current/scripts/stop-server process-fts-updates: stopped zulip-django: stopped zulip-tornado: stopped zulip-workers:zulip_events_deferred_work: stopped zulip-workers:zulip_events_digest_emails: stopped zulip-workers:zulip_events_email_mirror: stopped zulip-workers:zulip_events_email_senders: stopped zulip-workers:zulip_events_embed_links: stopped zulip-workers:zulip_events_embedded_bots: stopped zulip-workers:zulip_events_invites: stopped zulip-workers:zulip_events_missedmessage_emails: stopped zulip-workers:zulip_events_missedmessage_mobile_notifications: stopped zulip-workers:zulip_events_outgoing_webhooks: stopped zulip-workers:zulip_events_user_activity: stopped zulip-workers:zulip_events_user_activity_interval: stopped zulip-workers:zulip_events_user_presence: stopped zulip_deliver_scheduled_emails: stopped zulip_deliver_scheduled_messages: stopped Zulip stopped successfully!
Para volver a iniciar el servidor, utiliza el siguiente comando.
$ docker exec -u zulip zulip /home/zulip/deployments/current/scripts/start-server 2024-02-21 09:18:52,932 start-server: Running syntax and database checks System check identified no issues (28 silenced). 2024-02-21 09:18:54,944 start-server: Starting Tornado process zulip-tornado: started 2024-02-21 09:18:56,089 start-server: Starting django server zulip-django: started 2024-02-21 09:18:58,133 start-server: Starting workers process-fts-updates: started zulip-workers:zulip_events_deferred_work: started zulip-workers:zulip_events_digest_emails: started zulip-workers:zulip_events_email_mirror: started zulip-workers:zulip_events_email_senders: started zulip-workers:zulip_events_embed_links: started zulip-workers:zulip_events_embedded_bots: started zulip-workers:zulip_events_invites: started zulip-workers:zulip_events_missedmessage_emails: started zulip-workers:zulip_events_missedmessage_mobile_notifications: started zulip-workers:zulip_events_outgoing_webhooks: started zulip-workers:zulip_events_user_activity: started zulip-workers:zulip_events_user_activity_interval: started zulip-workers:zulip_events_user_presence: started zulip_deliver_scheduled_emails: started zulip_deliver_scheduled_messages: started 2024-02-21 09:19:19,571 start-server: Done! Zulip started successfully!
Reinicia el servidor de forma similar.
$ docker exec -u zulip zulip /home/zulip/deployments/current/scripts/restart-server
Hay muchas tareas de gestión que puedes realizar utilizando el script manage.py incluido con Zulip.
Puedes ejecutar el script utilizando el siguiente comando. Utilizaremos el subcomando help para enumerar todas las operaciones posibles que se pueden realizar.
$ ./zulip_manage.sh help
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
[analytics]
check_analytics_state
clear_analytics_tables
clear_single_stat
populate_analytics_db
update_analytics_counts
[django]
dbshell
makemigrations
migrate
shell
showmigrations
[zerver]
add_users_to_streams
archive_messages
audit_fts_indexes
backup
bulk_change_user_name
change_password
change_realm_subdomain
change_user_email
change_user_role
check_redis
checkconfig
compilemessages
convert_gitter_data
convert_mattermost_data
convert_rocketchat_data
convert_slack_data
create_default_stream_groups
create_realm
create_realm_internal_bots
create_stream
create_user
deactivate_realm
deactivate_user
delete_old_unclaimed_attachments
delete_realm
delete_user
deliver_scheduled_emails
deliver_scheduled_messages
edit_linkifiers
email_mirror
enqueue_digest_emails
enqueue_file
export
export_search
export_single_user
export_usermessage_batch
fetch_tor_exit_nodes
fill_memcached_caches
generate_realm_creation_link
get_migration_status
import
list_realms
logout_all_users
makemessages
merge_streams
process_queue
promote_new_full_members
purge_queue
query_ldap
rate_limit
reactivate_realm
realm_domain
register_server
remove_users_from_stream
reset_authentication_attempt_count
restore_messages
runtornado
scrub_realm
send_custom_email
send_password_reset_email
send_realm_reactivation_email
send_test_email
send_to_email_mirror
send_webhook_fixture_message
send_welcome_bot_message
show_admins
soft_deactivate_users
sync_ldap_user_data
transfer_uploads_to_s3
unarchive_stream
El archivo entrypoint.sh de Docker también proporciona algunas otras opciones. Ejecuta el siguiente comando para verlas.
$ docker exec -it zulip bash /sbin/entrypoint.sh app:help
Deberías ver el siguiente resultado.
Available commands: > app:help - Show this help menu and exit > app:version - Container Zulip server version > app:managepy - Run Zulip's manage.py script (defaults to "shell") > app:backup - Create backups of Zulip instances > app:restore - Restore backups of Zulip instances > app:certs - Create self-signed certificates > app:run - Run the Zulip server > [COMMAND] - Run given command with arguments in shell
Paso 11 – Prueba del correo electrónico saliente
Para probar tu configuración de correo saliente, puedes enviar un correo de prueba utilizando el siguiente comando.
$ ~/docker-zulip/zulip_manage.sh send_test_email [email protected] If you run into any trouble, read: https://zulip.readthedocs.io/en/latest/production/email.html#troubleshooting The most common error is not setting `ADD_TOKENS_TO_NOREPLY_ADDRESS=False` when using an email provider that doesn't support that feature. Sending 2 test emails from: * [email protected] * [email protected] Successfully sent 2 emails to [email protected]
Paso 12 – Actualizar Zulip
El primer paso para actualizar Zulip es detener los contenedores existentes.
$ cd ~/docker-zulip $ docker compose stop
Abre el archivo docker-compose.yml para editarlo.
$ nano docker-compose.yml
Comprueba la última versión disponible en la página de etiquetas DockerHub de Zulip. Modifica la versión en la sección siguiente.
.....
zulip:
image: "zulip/docker-zulip:8.2-0"
restart: unless-stopped
container_name: zulip
....
Realiza cualquier otro cambio que necesites. Tendrás que consultar el registro de cambios de Zulip y el repositorio Docker GitHub de Zulip para ello.
Cuando hayas terminado, guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Inicia de nuevo los contenedores. El contenedor Zulip se volverá a crear con los cambios.
$ docker compose up -d
Elimina los contenedores antiguos.
$ docker compose rm
Conclusión
Con esto concluye nuestro tutorial sobre la instalación y configuración del servidor de Chat Zulip en un servidor Rocky Linux 9. Puedes seguir la documentación oficial de Z ulip para explorar en detalle. Si tienes alguna pregunta, publícala en los comentarios a continuación.