Matrix es un protocolo abierto de mensajería descentralizada: cada organización puede tener su propio servidor y comunicarse con los usuarios de cualquier otro servidor Matrix mediante la federación. Synapse es el servidor de referencia y Element es el cliente más usado, con cifrado de extremo a extremo activado por defecto en los chats privados. En este tutorial instalarás Synapse en Ubuntu 24.04 con PostgreSQL, lo publicarás con Nginx y HTTPS, configurarás la delegación con .well-known para que tus usuarios tengan direcciones del tipo @ana:your_domain, y servirás Element Web desde tu propio subdominio.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios sudo.
  • Al menos 2 GB de RAM (4 GB si tus usuarios van a unirse a salas grandes federadas) y 20 GB libres en disco.
  • Un dominio, your_domain en los ejemplos, con tres registros DNS de tipo A que apunten a la IP del servidor:
    • your_domain: el nombre que aparecerá en las direcciones de usuario.
    • matrix.your_domain: donde escuchará Synapse.
    • chat.your_domain: donde se servirá Element Web.

El server_name que elijas en el paso 2 forma parte de todos los identificadores de usuario y salas y no se puede cambiar después sin perder los datos. Usa el dominio principal (your_domain), no el subdominio.

Paso 1: Instalar PostgreSQL y crear la base de datos

Synapse funciona con SQLite, pero solo para pruebas: en producción se queda sin rendimiento en cuanto hay federación. Instala PostgreSQL:

sudo apt update
sudo apt install postgresql

Crea un usuario de base de datos para Synapse. El comando pedirá la contraseña dos veces; guárdala, la necesitarás en el paso 3:

sudo -u postgres createuser --pwprompt synapse_user

Crea la base de datos. Synapse exige codificación UTF8 y collation C, por eso se usa template0:

sudo -u postgres createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse_user synapse

Comprueba que la base de datos existe con los parámetros correctos:

sudo -u postgres psql -c '\l synapse'
                                                  List of databases
  Name   |    Owner     | Encoding | Locale Provider | Collate | Ctype | ...
---------+--------------+----------+-----------------+---------+-------+----
 synapse | synapse_user | UTF8     | libc            | C       | C     |
(1 row)

Paso 2: Instalar Synapse

El proyecto publica paquetes para Debian y Ubuntu en packages.matrix.org, más recientes que los de Ubuntu. Descarga la clave del repositorio:

sudo apt install lsb-release wget
sudo mkdir -p /etc/apt/keyrings
sudo wget -O /etc/apt/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg

Añade el repositorio e instala el paquete:

echo "deb [signed-by=/etc/apt/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/matrix-org.list
sudo apt update
sudo apt install matrix-synapse-py3

El instalador pregunta dos cosas:

  1. Name of the server: escribe your_domain (el dominio principal, sin matrix.).
  2. Report homeserver usage statistics: elige lo que prefieras.

El paquete guarda el nombre en /etc/matrix-synapse/conf.d/server_name.yaml, crea la configuración principal en /etc/matrix-synapse/homeserver.yaml y arranca el servicio escuchando solo en localhost:8008. Compruébalo:

curl -s http://localhost:8008/_matrix/client/versions | head -c 120; echo
{"versions":["r0.0.1","r0.1.0","r0.2.0","r0.3.0","r0.4.0","r0.5.0","r0.6.0","r0.6.1","v1.1","v1.2","v1.3","v1.4","v1.5",

Paso 3: Conectar Synapse con PostgreSQL

En lugar de editar homeserver.yaml, que el paquete puede actualizar, pon tus cambios en archivos propios dentro de /etc/matrix-synapse/conf.d/. Synapse lee todos los .yaml de ese directorio y los combina con la configuración principal.

Primero, comenta el bloque database que trae homeserver.yaml y que apunta a SQLite, para que no entre en conflicto:

sudo nano /etc/matrix-synapse/homeserver.yaml
#database:
#  name: sqlite3
#  args:
#    database: /var/lib/matrix-synapse/homeserver.db

Crea el archivo con la conexión a PostgreSQL:

sudo nano /etc/matrix-synapse/conf.d/database.yaml
database:
  name: psycopg2
  args:
    user: synapse_user
    password: your_db_password
    dbname: synapse
    host: localhost
    cp_min: 5
    cp_max: 10

Sustituye your_db_password por la contraseña del paso 1. Crea también el archivo con el resto de ajustes. El registration_shared_secret permite crear usuarios desde la línea de comandos; genera uno aleatorio:

openssl rand -hex 32
sudo nano /etc/matrix-synapse/conf.d/local.yaml
public_baseurl: "https://matrix.your_domain/"

# Sin registro público: los usuarios los creas tú
enable_registration: false

# Secreto para register_new_matrix_user (pega el valor generado)
registration_shared_secret: "pega_aqui_el_valor_generado"

max_upload_size: 50M

Protege los dos archivos, ya que contienen secretos, y reinicia Synapse:

sudo chown root:matrix-synapse /etc/matrix-synapse/conf.d/database.yaml /etc/matrix-synapse/conf.d/local.yaml
sudo chmod 640 /etc/matrix-synapse/conf.d/database.yaml /etc/matrix-synapse/conf.d/local.yaml
sudo systemctl restart matrix-synapse
sudo systemctl status matrix-synapse

Synapse crea las tablas en PostgreSQL la primera vez que arranca. Comprueba en el registro que usa el motor correcto:

sudo journalctl -u matrix-synapse -n 100 --no-pager | grep -i postgres

Deberías ver una línea que menciona psycopg2 o PostgresEngine. Si el servicio no arranca, el registro indica el error de conexión (contraseña o nombre de base de datos incorrectos).

Paso 4: Configurar Nginx y los certificados HTTPS

Instala Nginx y Certbot, y abre los puertos web en el cortafuegos:

sudo apt install nginx certbot python3-certbot-nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Crea un archivo con los tres sitios. De momento solo escuchan en el puerto 80; Certbot añadirá HTTPS después:

sudo nano /etc/nginx/sites-available/matrix
# Synapse: API de clientes y de federación
server {
    listen 80;
    listen [::]:80;
    server_name matrix.your_domain;

    client_max_body_size 50M;

    location ~ ^(/_matrix|/_synapse/client) {
        proxy_pass http://127.0.0.1:8008;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Dominio principal: solo publica la delegación .well-known
server {
    listen 80;
    listen [::]:80;
    server_name your_domain;

    location = /.well-known/matrix/server {
        default_type application/json;
        return 200 '{"m.server": "matrix.your_domain:443"}';
    }

    location = /.well-known/matrix/client {
        default_type application/json;
        add_header Access-Control-Allow-Origin *;
        return 200 '{"m.homeserver": {"base_url": "https://matrix.your_domain"}}';
    }
}

# Element Web
server {
    listen 80;
    listen [::]:80;
    server_name chat.your_domain;

    root /var/www/element;
    index index.html;

    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header Content-Security-Policy "frame-ancestors 'self'";
}

El bloque location de Synapse solo reenvía las rutas /_matrix y /_synapse/client; el resto de rutas de administración de Synapse quedan sin publicar.

Crea el directorio de Element para que Nginx no dé error al validar, activa el sitio y recarga:

sudo mkdir -p /var/www/element
sudo ln -s /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Solicita un certificado para los tres nombres. Certbot modificará los bloques para escuchar en el puerto 443 y redirigir HTTP a HTTPS:

sudo certbot --nginx -d matrix.your_domain -d your_domain -d chat.your_domain

Comprueba que Synapse responde por HTTPS:

curl -s https://matrix.your_domain/_matrix/federation/v1/version
{"server":{"name":"Synapse","version":"1.138.0"}}

Paso 5: Verificar la delegación y la federación

Los otros servidores Matrix buscan tu servidor en https://your_domain/.well-known/matrix/server, y los clientes descubren la URL de Synapse en /.well-known/matrix/client. Así los usuarios tienen direcciones cortas (@ana:your_domain) mientras Synapse vive en matrix.your_domain por el puerto 443, sin necesidad de abrir el 8448. Comprueba ambos archivos:

curl -s https://your_domain/.well-known/matrix/server
curl -s https://your_domain/.well-known/matrix/client
{"m.server": "matrix.your_domain:443"}
{"m.homeserver": {"base_url": "https://matrix.your_domain"}}

Si tu web principal está en otro servidor, publica en él esos dos archivos con el mismo contenido, Content-Type: application/json y, en el de cliente, la cabecera Access-Control-Allow-Origin: *.

Comprueba la federación con el comprobador público de Matrix. El campo FederationOK debe ser true:

curl -s "https://federationtester.matrix.org/api/report?server_name=your_domain" | grep -o '"FederationOK":[a-z]*'
"FederationOK":true

Paso 6: Instalar Element Web

Element Web es una aplicación estática: solo hay que descargar la versión publicada y darle un archivo de configuración. Consulta la última versión en la página de releases de Element Web y descárgala (sustituye 1.11.112 por la versión actual):

cd /tmp
ELEMENT_VERSION=1.11.112
wget "https://github.com/element-hq/element-web/releases/download/v${ELEMENT_VERSION}/element-v${ELEMENT_VERSION}.tar.gz"

Descomprime el contenido en el directorio que sirve Nginx:

sudo tar -xzf "element-v${ELEMENT_VERSION}.tar.gz" -C /var/www/element --strip-components=1

Crea la configuración a partir del ejemplo incluido:

sudo cp /var/www/element/config.sample.json /var/www/element/config.json
sudo nano /var/www/element/config.json

Cambia el bloque default_server_config para que apunte a tu servidor:

"default_server_config": {
    "m.homeserver": {
        "base_url": "https://matrix.your_domain",
        "server_name": "your_domain"
    }
},

Valida que el archivo sigue siendo JSON correcto:

python3 -m json.tool /var/www/element/config.json > /dev/null && echo "JSON válido"
JSON válido

Abre https://chat.your_domain. Verás la pantalla de inicio de sesión de Element con tu servidor ya seleccionado.

Paso 7: Crear usuarios

Como el registro público está desactivado, crea las cuentas con register_new_matrix_user, que usa el secreto del paso 3. Crea primero una cuenta de administrador:

sudo register_new_matrix_user -c /etc/matrix-synapse/conf.d/local.yaml -u ana --admin http://localhost:8008
Password:
Confirm password:
Sending registration request...
Success!

Para usuarios normales, omite --admin. Inicia sesión en https://chat.your_domain con el usuario ana y la contraseña elegida. Para comprobar la federación desde el cliente, inicia un chat con un usuario de otro servidor, por ejemplo uno tuyo en matrix.org.

Element te pedirá configurar la copia de seguridad de claves en el primer inicio de sesión. Hazlo: las claves de cifrado de extremo a extremo solo están en tus dispositivos, y sin esa copia perderás el historial cifrado si cierras todas las sesiones.

Solución de problemas

Synapse no arranca tras configurar PostgreSQL. Revisa el registro completo:

sudo journalctl -u matrix-synapse -n 50 --no-pager

Si aparece Database has incorrect collation, la base de datos no se creó con --locale=C y template0: bórrala con sudo -u postgres dropdb synapse y repite el paso 1. Si aparece un error de autenticación, revisa la contraseña de database.yaml.

La federación falla. Comprueba que https://your_domain/.well-known/matrix/server devuelve el JSON del paso 5 y que el certificado de matrix.your_domain es válido. El comprobador de federación indica el error concreto si abres en el navegador https://federationtester.matrix.org/#your_domain.

Element muestra "Your Element is misconfigured". El config.json tiene un error de sintaxis o base_url no es accesible. Valida el JSON como en el paso 6 y abre https://matrix.your_domain/_matrix/client/versions en el navegador.

No se pueden subir archivos grandes. Tanto max_upload_size en Synapse como client_max_body_size en Nginx deben permitir el tamaño deseado.

Conclusión

Tienes un servidor Matrix propio en Ubuntu 24.04 con Synapse y PostgreSQL, publicado con HTTPS, federado con el resto de la red Matrix y con Element Web en tu propio subdominio. Como siguientes pasos puedes programar copias de seguridad de la base de datos con pg_dump y del directorio /var/lib/matrix-synapse/media, conectar puentes (bridges) como mautrix-telegram para hablar con otras plataformas, o instalar un servidor TURN como coturn para que las llamadas de voz y vídeo funcionen detrás de NAT.