Guía de despliegue

Centrifugo en un VPS: servidor de tiempo real autoalojado

Desplegar en un VPS Cloud →

Tutorial

Centrifugo en un VPS: servidor de tiempo real autoalojado

Autoalojamiento7 min de lectura3 pasos

Mostrar una notificación en el momento en que se paga un pedido, mantener un chat, actualizar un panel sin recargar la página: todo esto requiere una conexión abierta de forma permanente entre el servidor y el navegador. Servicios como Pusher o Ably lo hacen muy bien, pero facturan cada conexión y cada mensaje, y tus datos pasan por ellos. Centrifugo es un servidor de mensajería en tiempo real de código abierto (licencia Apache-2.0), escrito en Go, que hace el mismo trabajo en tu propio VPS. Esta guía lo instala con Docker Compose, lo coloca detrás de nginx con HTTPS y muestra cómo publicar desde tu backend y conectar un navegador con un JWT.

Contenido· Cómo funciona Centrifugo1/13
  1. 01Cómo funciona Centrifugo
  2. 02Lo que aporta Centrifugo
  3. 03Centrifugo frente a un servicio alojado
  4. 04Requisitos previos
  5. 05Instalar Centrifugo con Docker Compose
  6. 06Nunca publiques el puerto 8000 en la IP pública
  7. 07Colocar Centrifugo detrás de nginx
  8. 08Publicar desde tu backend
  9. 09Firmar los tokens de conexión
  10. 10Lo que un cliente puede hacer
  11. 11Conectar un navegador
  12. 12La consola de administración
  13. 13Escalado y actualizaciones

Cómo funciona Centrifugo

Centrifugo se sitúa entre tu aplicación y sus usuarios. Tu backend — Laravel, Django, Express, Rails u otro — no mantiene ninguna conexión abierta: firma un token para cada usuario y publica mensajes con una simple llamada HTTP. Centrifugo mantiene las conexiones WebSocket de los navegadores y las apps móviles, y entrega cada mensaje a los suscriptores del canal correspondiente.

Esta separación tiene una ventaja concreta: tu aplicación sigue sin estado y es fácil de desplegar, y la parte de tiempo real cabe en un único binario Go que consume unas decenas de MB de RAM en reposo.

Lo que aporta Centrifugo

  • Conexiones WebSocket — con SDK cliente oficiales para JavaScript, Dart/Flutter, Swift, Java/Android, Go y Python.
  • API de publicación — un POST HTTP con la cabecera X-API-Key, desde cualquier lenguaje.
  • Tokens JWT — tu backend decide quién se conecta y a qué canales, Centrifugo verifica la firma.
  • Suscripciones del lado del servidor — la lista de canales de un usuario viaja en su token.
  • Consola de administración — estado del nodo, clientes conectados y comandos de la API desde el navegador.
  • Valores por defecto prudentes — ninguna conexión anónima, ninguna publicación desde el navegador sin permiso explícito.

Centrifugo frente a un servicio alojado

Desplace la tabla

Centrifugo en un VPSPusher, Ably
FacturaciónPrecio del VPS, sin límite de mensajesPor conexiones y mensajes
Por dónde pasan los datosPor tu servidorPor el proveedor
Protocolo clienteWebSocket y SDK oficialesWebSocket y SDK propietarios
AutenticaciónJWT firmado por tu backendFirma propia del servicio
OperaciónA tu cargoA cargo del proveedor

Requisitos previos

Un VPS Ubuntu 24.04 con 1 GB de RAM y 10 GB de disco, Docker y el plugin Compose instalados, y un subdominio que apunte al VPS, por ejemplo rt.example.com. El HTTPS no es opcional: un sitio servido por HTTPS solo puede abrir conexiones wss://, y tu clave de API nunca debe circular en claro.

Instalar Centrifugo con Docker Compose

  1. Generar los secretos

    Crea el directorio de la aplicación y un archivo .env con cuatro secretos distintos: la contraseña de la consola, la clave que firma sus sesiones, la clave de la API de servidor y la clave HMAC de los tokens de cliente.

    mkdir -p /opt/centrifugo && cd /opt/centrifugo
    {
      echo "ADMIN_PASSWORD=$(openssl rand -hex 12)"
      echo "SECRET_KEY=$(openssl rand -hex 24)"
      echo "ENCRYPTION_KEY=$(openssl rand -hex 16)"
      echo "ENCRYPTION_KEY_HEX64=$(openssl rand -hex 32)"
    } > .env
    chmod 600 .env
  2. Escribir el archivo docker-compose.yml

    El puerto se publica solo en la interfaz local: únicamente nginx accede a él. Sustituye https://app.example.com por la dirección de tu sitio.

    services:
      centrifugo:
        image: centrifugo/centrifugo:v6.10.2
        restart: unless-stopped
        command: ["centrifugo"]
        ports:
          - "127.0.0.1:8000:8000"
        environment:
          CENTRIFUGO_ADMIN_ENABLED: "true"
          CENTRIFUGO_ADMIN_PASSWORD: "${ADMIN_PASSWORD}"
          CENTRIFUGO_ADMIN_SECRET: "${SECRET_KEY}"
          CENTRIFUGO_HTTP_API_KEY: "${ENCRYPTION_KEY}"
          CENTRIFUGO_CLIENT_TOKEN_HMAC_SECRET_KEY: "${ENCRYPTION_KEY_HEX64}"
          CENTRIFUGO_CLIENT_ALLOWED_ORIGINS: "https://app.example.com"
          CENTRIFUGO_HEALTH_ENABLED: "true"
        ulimits:
          nofile:
            soft: 65535
            hard: 65535
  3. Arrancar y comprobar

    Inicia el contenedor y consulta el punto de salud; debe responder {}.

    docker compose up -d
    curl -fsS http://127.0.0.1:8000/health

Nunca publiques el puerto 8000 en la IP pública

El mismo puerto sirve las conexiones de clientes, la API de servidor y la consola de administración. Mantenlo en 127.0.0.1 y pasa siempre por el proxy inverso HTTPS. Y nunca pongas ENCRYPTION_KEY ni ENCRYPTION_KEY_HEX64 en código enviado al navegador: la primera permite publicar en cualquier canal, la segunda fabricar tokens para cualquier usuario.

Colocar Centrifugo detrás de nginx

Una conexión WebSocket empieza con una petición HTTP que pide cambiar de protocolo. nginx debe transmitir esa petición y no cortar una conexión que permanece en silencio unos minutos. En el bloque server de tu subdominio, con un certificado Let's Encrypt:

location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout 3600s;
}

Tras nginx -t y una recarga, https://rt.example.com muestra la pantalla de inicio de sesión de la consola.

Publicar desde tu backend

Publicar es enviar un objeto JSON a un canal. Sirve cualquier lenguaje capaz de hacer una petición HTTP:

curl -X POST https://rt.example.com/api/publish \
  -H "X-API-Key: $ENCRYPTION_KEY" \
  -d '{"channel": "commandes", "data": {"id": 1042, "statut": "payee"}}'

La respuesta {"result":{}} confirma que el mensaje se aceptó. Sin la cabecera X-API-Key, o con una clave incorrecta, Centrifugo responde 401.

Firmar los tokens de conexión

Un navegador solo se conecta con un JWT firmado por tu backend con ENCRYPTION_KEY_HEX64. El claim sub lleva el identificador del usuario, exp la fecha de caducidad y channels la lista de canales a los que queda suscrito de oficio. Ejemplo en Python:

import time, jwt  # pip install pyjwt

def centrifugo_token(user_id: str) -> str:
    claims = {"sub": user_id, "exp": int(time.time()) + 3600, "channels": ["commandes"]}
    return jwt.encode(claims, ENCRYPTION_KEY_HEX64, algorithm="HS256")

Expón esta función detrás de una ruta autenticada de tu aplicación: solo un usuario con sesión iniciada en tu app debe poder obtener un token.

Lo que un cliente puede hacer

Los ajustes de esta instalación están cerrados a propósito. Un navegador no puede suscribirse por su cuenta a un canal ni publicar en él: solo recibe los canales listados en el claim channels de su token. Tu backend decide, cada vez que emite un token, quién escucha qué — un cliente solo ve sus propios pedidos, un agente de soporte solo la cola de su equipo.

Para un chat, la publicación pasa también por tu backend: el navegador envía el mensaje a tu aplicación, que lo valida, lo guarda en la base de datos y lo publica por la API. Este rodeo cuesta unos milisegundos y te deja el control de la moderación y del historial.

Por último, da a los tokens una duración corta, una hora por ejemplo. En lugar de pasar un token fijo, deja que el SDK pida uno nuevo a tu aplicación cuando caduque:

const client = new Centrifuge('wss://rt.example.com/connection/websocket', {
  getToken: async () => {
    const res = await fetch('/realtime/token', { credentials: 'include' });
    return (await res.json()).token;
  },
});

La ruta /realtime/token es de tu aplicación; comprueba la sesión del usuario antes de firmar nada.

Conectar un navegador

En el lado cliente, el SDK oficial centrifuge (npm) abre la conexión y entrega los mensajes:

import { Centrifuge } from 'centrifuge';

const client = new Centrifuge('wss://rt.example.com/connection/websocket', {
  token: tokenFromYourBackend,
});
client.on('publication', (ctx) => console.log(ctx.channel, ctx.data));
client.connect();

Si la conexión falla, mira primero los registros (docker compose logs centrifugo). El mensaje «request Origin is not authorized» indica que falta el origen de tu sitio en CENTRIFUGO_CLIENT_ALLOWED_ORIGINS; «invalid token» apunta a un token mal firmado o caducado.

La consola de administración

Abre https://rt.example.com e introduce ADMIN_PASSWORD: la consola no pide usuario. Muestra la versión del nodo, el número de clientes y usuarios conectados, y permite enviar comandos de la API — publicar un mensaje de prueba, listar los canales activos — sin escribir código. Es la forma más rápida de comprobar que un mensaje sale antes de buscar el fallo en el navegador.

Escalado y actualizaciones

Esta guía usa el motor en memoria: un solo nodo, sin dependencias. Sirve para la mayoría de las aplicaciones, y un VPS modesto ya sostiene un gran número de conexiones simultáneas, de ahí el límite de archivos abiertos ampliado en el docker-compose.yml. El día en que un nodo no baste, Centrifugo puede repartir la carga entre varios nodos unidos por Redis. Para actualizar, cambia la etiqueta de la imagen tras leer las notas de versión y ejecuta docker compose pull && docker compose up -d; las conexiones se restablecen solas, porque los SDK cliente se reconectan automáticamente.

Tu servidor de tiempo real en tu VPS

Un VPS ServOrbit Ubuntu 24.04 con 1 GB de RAM basta para arrancar Centrifugo. Instalación en un clic desde el Marketplace, HTTPS y WebSocket en tu dominio o en el subdominio gratuito del VPS, contraseña y claves generadas para ti.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva