SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-26

Instalar Rocket.Chat con Docker Compose en un VPS

Guía para alojar Rocket.Chat con Docker Compose: replica set MongoDB de un nodo, TLS, copias de seguridad y errores habituales corregidos.

Qué va a implementar

Un chat privado para equipos bajo su control: Rocket.Chat ejecutándose en su propio VPS mediante Docker Compose, con terminación TLS y todos los mensajes almacenados en una base de datos MongoDB que puede respaldar y trasladar. Rocket.Chat es una alternativa madura y de código abierto a Slack y Teams. Incluye canales, mensajes directos, hilos, intercambio de archivos y funciones de voz y vídeo, todo en el hardware que alquila y administra. No es la única opción sólida. Si todavía está eligiendo, comparación entre Mattermost, Rocket.Chat, Synapse y Zulip las compara según los aspectos que suelen causar problemas más adelante: RAM, base de datos, notificaciones push móviles, SSO y actualizaciones. La aplicación es un único contenedor que se inicia en pocos minutos. Todo lo que suele fallar realmente está en la base de datos asociada. Por eso, la mayor parte de esta guía trata sobre MongoDB y, en particular, sobre el único requisito que sorprende a todo el mundo la primera vez: Rocket.Chat no funciona con una instancia independiente de MongoDB. Necesita un conjunto de réplicas, aunque ese «conjunto» tenga un solo nodo.

Requisitos previos y los cálculos de RAM que nadie explica

Dimensione el servidor de forma realista. El mínimo razonable para un equipo pequeño es 2 vCPU y 4 GB de RAM. El proceso de Node.js de Rocket.Chat necesita aproximadamente entre 1 y 1.5 GB por sí solo, y la caché WiredTiger de MongoDB usa de forma predeterminada cerca de la mitad de la RAM restante. En un VPS de 2 GB, ambos servicios caben al arrancar, pero entran en conflicto en cuanto llega tráfico real: MongoDB aumenta su caché, Node aumenta su heap, el kernel se queda sin páginas y el asesino de procesos por falta de memoria termina el proceso más grande, normalmente mongod. El contenedor muestra Killed, Docker lo reinicia y el servidor de chat se desconecta cada pocos minutos con una carga que debería poder manejar sin problemas. 2 GB son suficientes para probarlo con dos personas, pero no para un servidor de equipo. Empiece con 4 GB y asígnele 8 GB si espera decenas de usuarios simultáneos, videollamadas o un historial de archivos subidos que crece. Reserve también memoria para todo lo demás que deba ejecutar el servidor: alojar un espacio de trabajo AFFiNE de estilo Notion en el mismo VPS añade otros cuatro contenedores que compiten por las mismas páginas de memoria, por lo que su RAM debe sumarse a la de Rocket.Chat y no descontarse de ella.

También necesita tener preparados tres elementos antes de empezar. Un nombre de dominio con un registro A que apunte a la IP pública del VPS. Las funciones en tiempo real de Rocket.Chat y los clientes móviles necesitan un nombre de host estable, no una IP sin más. Los puertos 80 y 443 deben estar abiertos tanto en el firewall del servidor como en el firewall de red del proveedor, que suele ser un control independiente en la mayoría de los paneles. Por último, necesita un VPS KVM nuevo con Ubuntu 24.04 y acceso mediante root o sudo. Si todavía está decidiendo si un servidor de chat es el primer servicio adecuado para ejecutar, la guía sobre qué merece la pena alojar por cuenta propia en 2026 explica las ventajas y los inconvenientes.

Instale el motor de Docker y el plugin de Compose

Use el repositorio apt de Docker. No use el paquete docker.io que distribuye Ubuntu ni el antiguo binario independiente docker-compose de Python. Compose moderno es un plugin de Docker que se invoca como docker compose, con un espacio, no con un guion. La versión antigua docker-compose v1 está fuera de soporte y no gestiona correctamente la sintaxis de healthcheck y dependencias que se muestra a continuación.

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Confirme que ambos componentes estén instalados:

sudo docker version
sudo docker compose version

docker compose version, si muestra algo parecido a Docker Compose version v2.x, es la comprobación relevante. Si devuelve el error docker: 'compose' is not a docker command, el plugin no se instaló. Corríjalo ahora para evitar errores confusos más adelante.

El archivo compose: MongoDB como conjunto de réplicas de un solo nodo

Esta es la parte que suele configurarse mal, así que léala despacio. Rocket.Chat usa change streams de MongoDB para enviar mensajes nuevos a los clientes conectados en tiempo real, y los change streams sólo están disponibles en un conjunto de réplicas. Si apunta Rocket.Chat a un mongod independiente, se conectará, no podrá abrir un change stream y entrará en un bucle de reinicios permanente. La solución no es compleja: ejecute un contenedor normal de MongoDB, pero inícielo con --replSet y después inicialice un conjunto de un solo miembro.

Cree un directorio de trabajo y un compose.yml:

services:
  mongodb:
    image: mongo:8.0
    restart: always
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--oplogSize", "128"]
    volumes:
      - mongodb_data:/data/db
      - mongodb_config:/data/configdb
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 12

  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:8.5.1
    restart: always
    depends_on:
      mongodb:
        condition: service_healthy
    environment:
      MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
      MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
      ROOT_URL: "https://chat.example.com"
      PORT: "3000"
    ports:
      - "127.0.0.1:3000:3000"

volumes:
  mongodb_data:
  mongodb_config:

Algunas decisiones son deliberadas. El puerto de Rocket.Chat se publica en 127.0.0.1:3000, no en 0.0.0.0. La aplicación no usa TLS, por lo que sólo el proxy inverso del mismo servidor debe acceder a ella; enlazarla con todas las interfaces expondría directamente una página de inicio de sesión sin cifrado en Internet pública. MongoDB no se publica en el host; sólo se puede acceder a él a través de la red interna de Compose con el nombre mongodb, que es exactamente el nombre de host que usa MONGO_URL. MONGO_URL transporta ?replicaSet=rs0. Si se omite, el controlador trata el servidor como independiente aunque sea un conjunto de réplicas, y los change streams siguen fallando. MONGO_OPLOG_URL apunta a la base de datos local, donde se almacena el oplog. Las versiones modernas de Rocket.Chat prefieren los change streams, pero configurarlo no causa problemas y mantiene operativas las rutas de código antiguas. depends_on usa condition: service_healthy, por lo que Compose espera hasta que MongoDB responda a un ping antes de iniciar Rocket.Chat. Para eso sirve la comprobación de estado.

Fije etiquetas de versión reales en ambas imágenes, mongo:8.0 y una versión explícita de Rocket.Chat, como 8.5.1 en este caso, y no use nunca :latest, porque convierte una docker pull desatendida en una actualización accidental que no se puede migrar. Compruebe la versión estable actual de Rocket.Chat y las versiones de MongoDB compatibles antes de fijar las versiones. Rocket.Chat publica un documento de información legible por máquinas para cada versión: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' devuelve compatibleMongoVersions: ["8.0"] para 8.5.1, por lo que mongo:8.0 es el único motor compatible, además de un indicador lts que señala si esa versión pertenece a la rama de soporte a largo plazo y conviene fijarla en un servidor que no quiera supervisar continuamente. No todos los proyectos publican una imagen versionada. En ese caso, la fijación se aplica al código fuente: alojar el rastreador de entrenamientos openGym implica cambiar a una etiqueta específica de git y compilar desde ella, en lugar de seguir una rama que cambia.

Inicialice el conjunto de réplicas

Inicie la pila:

sudo docker compose up -d

Rocket.Chat comenzará a fallar de inmediato y Docker lo reiniciará continuamente. Esto es normal porque el conjunto de réplicas todavía no existe. Créelo una vez, manualmente:

sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'

El resultado correcto es { ok: 1 }. En pocos segundos, el nodo único se elige como primary. Confírmelo con:

sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'

Debe ver PRIMARY. El detalle más importante de toda esta página es el argumento host: "mongodb:27017". Si ejecuta un rs.initiate() sin una lista de miembros, MongoDB anuncia el conjunto de réplicas usando el nombre de host interno del contenedor, un hash aleatorio como a1b2c3d4e5f6. Rocket.Chat, que se conecta desde su propio contenedor, no puede resolver ese nombre. Por eso el controlador de MongoDB falla al resolverlo mediante DNS y queda registrando MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6 en un bucle infinito. Inicialice siempre el conjunto con el nombre explícito del servicio que coincide con su MONGO_URL.

Primer arranque: supervise el inicio

Cuando el conjunto ya es el principal, el siguiente reinicio de Rocket.Chat se conecta correctamente e inicia sus migraciones de primer arranque. Siga los registros:

sudo docker compose logs -f rocketchat

La línea que debe esperar es el aviso de inicio:

+--------------------------------------------+
        SERVER RUNNING
   Rocket.Chat Version: 8.5.1
        NodeJS Version: 22.22.3 - x64
+--------------------------------------------+

El primer arranque es lento. La aplicación ejecuta migraciones de la base de datos y crea índices, así que espere uno o dos minutos antes de investigar. Si el registro repite MongoServerSelectionError: Server selection timed out after 30000 ms con una descripción de topología de tipo ReplicaSetNoPrimary, el conjunto de réplicas no está iniciado. Si repite getaddrinfo ENOTFOUND con un hash aleatorio, se inició con el host incorrecto. En ambos casos, vuelva al paso anterior. Cuando vea SERVER RUNNING, Rocket.Chat estará escuchando en 127.0.0.1:3000 y será el momento de configurarle un nombre de host real y TLS.

Ponlo detrás de TLS

Nunca expongas Rocket.Chat mediante HTTP sin cifrar. Si inicias sesión una vez a través de http://, habrás entregado tu contraseña de administrador a cualquiera que pueda interceptar el tráfico. Termina TLS en un reverse proxy del mismo servidor y reenvía las solicitudes a 127.0.0.1:3000. Hay dos aspectos importantes: el proxy debe reenviar las cabeceras de actualización de WebSocket, porque Rocket.Chat funciona en tiempo real y deja de funcionar sin ellas, y ROOT_URL del contenedor debe coincidir exactamente con la dirección HTTPS pública que introducen los usuarios.

Empieza con un bloque de servidor HTTP sin cifrar de nginx que haga proxy hacia la aplicación y reenvíe las cabeceras de actualización. Guárdalo como /etc/nginx/sites-available/rocketchat, crea un enlace simbólico en sites-enabled y recarga nginx:

server {
    listen 80;
    server_name chat.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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_set_header X-Forwarded-Proto $scheme;
    }
}

Déjalo en el puerto 80 por ahora. Un bloque con listen 443 ssl; y sin certificado ni siquiera superará sudo nginx -t. Recarga nginx (sudo nginx -t && sudo systemctl reload nginx) y emite el certificado. En Ubuntu, la opción más sencilla es certificados TLS de Let's Encrypt con Certbot y nginx: certbot --nginx reescribe el bloque anterior en el mismo archivo. Añade listen 443 ssl;, las líneas ssl_certificate y una redirección automática de 80 a 443. También programa la renovación por ti. Si ya ejecutas varios contenedores detrás de un único proxy, Traefik con TLS automático para varias aplicaciones Docker es una opción más ordenada. Añade las etiquetas del router y del servicio al servicio rocketchat. Traefik solicitará y renovará el certificado por ti, sin ningún bloque de nginx. En ambos casos, establece ROOT_URL en https://chat.example.com dentro de compose.yml y vuelve a ejecutar sudo docker compose up -d para que el contenedor aplique el cambio. Si quieres que el servidor sólo sea accesible desde tu propia red y no desde Internet pública, colócalo detrás de una VPN WireGuard autohospedada en el VPS y vincula el proxy a la dirección del túnel.

El asistente de configuración inicial

Vaya a https://chat.example.com y Rocket.Chat le guiará por un asistente breve. Primero, la cuenta de administrador, el nombre real, el nombre de usuario, el correo electrónico y una contraseña segura; esta es la única cuenta que existe, así que no la pierda. Después, la información de la organización y del servidor, como el nombre, el sector, el tamaño, el nombre del sitio y el idioma predeterminado; son datos principalmente visuales, complételos y continúe. Luego aparece la decisión importante: registrar este espacio de trabajo en Rocket.Chat Cloud o mantenerlo independiente.

El registro habilita las notificaciones push móviles mediante la pasarela de Rocket.Chat y el marketplace de complementos, a cambio de establecer una relación con el plano de control de la nube de Rocket.Chat. El modo independiente mantiene el servidor completamente privado y sin dependencias externas, pero las notificaciones push de iOS y Android dejan de funcionar porque Apple y Google no permiten que una aplicación compilada por el usuario gestione los certificados push; las aplicaciones oficiales pasan por la pasarela de la nube. Elija el modo independiente si la privacidad es el objetivo principal y sus usuarios utilizan la aplicación web; elija el registro si las notificaciones push móviles son imprescindibles. Puede cambiar esta opción más adelante en Admin.

Bloquéelo antes de invitar a alguien

Rocket.Chat se distribuye con el registro abierto activado. De forma predeterminada, Registration Form está configurado como Public, por lo que cualquiera que encuentre la URL puede crear una cuenta. En un hostname público, esto deja el servicio expuesto. Vaya a Admin → Settings → Accounts → Registration y configure Registration Form como Disabled, para crear cuentas manualmente o mediante un enlace de invitación, o como Secret URL. Mientras está allí, desactive Allow Anonymous Read y Allow Anonymous Write, salvo que necesite específicamente un canal público de solo lectura. Si crear cada cuenta manualmente resulta tedioso y este no es el único servicio al que inicia sesión su equipo, configure el inicio de sesión OAuth de Rocket.Chat para usar un servidor SSO Authentik autohospedado. Así, las altas y las bajas se gestionan una sola vez y desde un único lugar, en vez de servicio por servicio.

Decida también dónde se almacenan las cargas. El almacenamiento predeterminado de File Upload es GridFS, que guarda cada imagen y archivo adjunto dentro de MongoDB. Es sencillo, pero significa que la base de datos, y cada mongodump que cree, crece sin límite a medida que las personas pegan capturas de pantalla. En Admin → Settings → File Upload puede cambiar el almacenamiento al sistema de archivos local o a un bucket compatible con S3, y establecer un tamaño máximo razonable para los archivos. Si su equipo intercambia bibliotecas fotográficas completas en lugar de alguna captura ocasional, esas bibliotecas deben estar en un servidor de fotos dedicado y no en una base de datos de chat. Comparación de PhotoPrism e Immich analiza el consumo de RAM de cada opción y los comandos de backup que necesita. Para un equipo pequeño, GridFS es adecuado; tenga en cuenta que sus backups serán cada vez más pesados.

Copias de seguridad con mongodump

Todos los datos están en el volumen mongodb_data. No copie el volumen mientras la base de datos está en ejecución. Cree un volcado coherente con mongodump y transmítalo a un archivo en el host:

sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gz

Ese único archivo comprimido con gzip contiene todo el espacio de trabajo: usuarios, canales, mensajes, configuración y, si dejó las cargas en GridFS, también los archivos. Si trasladó las cargas al sistema de archivos o a S3, haga una copia de seguridad de ese almacenamiento por separado. Para restaurar en una pila nueva, inicialice primero el conjunto de réplicas y después:

sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gz

Copie el archivo fuera del servidor, en un almacenamiento de objetos, otro servidor o cualquier ubicación donde la caída del VPS no destruya también la copia de seguridad. Ejecute el volcado cada noche desde cron. Una copia de seguridad que nunca ha restaurado es una esperanza, no una copia de seguridad. Practique la restauración una vez en un VPS desechable para confirmar que funciona antes de necesitarla.

Actualizaciones: fije las etiquetas, lea las notas y respete la matriz de MongoDB

Dos reglas hacen que las actualizaciones sean rutinarias. Primero, actualice Rocket.Chat una versión principal cada vez. Ejecuta migraciones de esquema durante el arranque y rechaza deliberadamente saltar versiones principales; si intenta pasar directamente de 6.x a 8.x, se detiene con un error de migración en lugar de corromper los datos. Cambie la etiqueta de la imagen a la última versión de la siguiente versión principal, lea las notas de esa versión para conocer los cambios incompatibles, ejecute docker compose up -d y supervise los registros hasta que finalice la migración antes de continuar. Segundo, respete la matriz de compatibilidad de MongoDB. Cada versión de Rocket.Chat admite un conjunto específico de versiones de MongoDB, y curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions le indica cuáles. Cuando actualice MongoDB, por ejemplo de 7.0 a 8.0, avance una versión principal cada vez y establezca la versión de compatibilidad de funciones después de cada paso. En MongoDB 8.0, ese comando requiere un confirm: true explícito; de lo contrario, se rechaza y muestra un mensaje que indica que debe volver a ejecutarlo con el indicador de confirmación:

sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'

Haga un mongodump antes de actualizar cualquiera de los dos componentes. Esa es toda la protección necesaria.

Modos de fallo, con las cadenas exactas

Rocket.Chat entra en un bucle de reinicios justo después de docker compose up, y docker compose logs rocketchat se llena con un MongoServerSelectionError. MongoDB está en ejecución, pero el controlador no puede seleccionar un primario. La cadena exacta indica qué error se cometió. Server selection timed out after 30000 ms con un tipo de topología ReplicaSetNoPrimary significa que nunca se ejecutó rs.initiate(). El conjunto todavía no tiene configuración. getaddrinfo ENOTFOUND seguido de un hash aleatorio significa que se inició sin especificar host: "mongodb:27017". Por eso MongoDB anunció un nombre de host de contenedor que no se puede resolver. Diagnostique el problema con sudo docker compose exec mongodb mongosh --eval 'rs.status()': si devuelve el error MongoServerError: no replset config has been received, inicialice el conjunto; si muestra un miembro cuyo name es un hash aleatorio, vuelva a inicializarlo con el nombre del servicio.

La interfaz web carga, pero el inicio de sesión gira indefinidamente y nunca termina. Abra la consola del navegador. Allí verá WebSocket connection to 'wss://chat.example.com/websocket' failed. Casi siempre se debe a una discrepancia de ROOT_URL o a un proxy que no reenvía las cabeceras de actualización. Confirme que ROOT_URL coincide exactamente con la dirección pública, incluido https://, y que el bloque location de nginx establece Upgrade y Connection "upgrade" con proxy_http_version 1.1. Cambie uno de los dos valores y vuelva a ejecutar docker compose up -d.

Un contenedor sigue terminándose y docker compose ps muestra Restarting. docker compose logs se interrumpe a mitad de una línea y sudo dmesg | tail muestra Out of memory: Killed process 12345 (mongod) del oom-killer; el código de salida es 137. El servidor se ha quedado sin RAM. La solución real es usar un VPS más grande, con 4 GB como mínimo. Como medida provisional, añada swap y limite la caché de MongoDB con --wiredTigerCacheSizeGB 1 en su command, pero la swap sólo retrasa el siguiente OOM con carga real:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

docker compose up falla con Error response from daemon: driver failed programming external connectivity ... bind: address already in use. Ya hay otro proceso usando el puerto 3000. Suele ser un contenedor anterior de Rocket.Chat que no se detuvo correctamente u otra aplicación. Localícelo con sudo ss -ltnp | grep :3000. Detenga ese proceso o contenedor, o cambie el lado del host de la asignación a 127.0.0.1:3001:3000 y actualice proxy_pass en el proxy para que coincida.

FAQ

¿Rocket.Chat necesita realmente un replica set de MongoDB?

Sí, incluso en un solo servidor con un único nodo de base de datos. Rocket.Chat entrega los mensajes en tiempo real mediante change streams de MongoDB, y los change streams sólo están disponibles en un replica set; un mongod independiente no puede abrirlos. No necesita varias máquinas: ejecute un contenedor de MongoDB iniciado con --replSet rs0 e inicialice un conjunto de un solo miembro con rs.initiate(). Si omite este paso, el driver nunca encuentra un primary, por lo que Rocket.Chat entra en un bucle de reinicios con MongoServerSelectionError: Server selection timed out y nunca termina de arrancar.

¿Cuánta RAM necesita Rocket.Chat autohospedado?

Planifique 4 GB como mínimo práctico y 8 GB para un equipo con carga elevada. El proceso de Node de Rocket.Chat usa aproximadamente entre 1 y 1.5 GB, y MongoDB reserva aproximadamente la mitad de la RAM restante para su caché de WiredTiger. En un equipo con 2 GB, ambos compiten por la memoria y el out-of-memory killer termina mongod con cualquier carga real. En los registros aparece Killed y el código de salida es 137. Dos GB sólo bastan para evaluar el software con un par de usuarios de prueba.

¿Cómo pongo Rocket.Chat detrás de HTTPS?

Ejecute un reverse proxy en la misma VPS. El proxy debe terminar TLS y reenviar las solicitudes a 127.0.0.1:3000. Configure ROOT_URL del contenedor con la dirección pública https://. El proxy debe reenviar las cabeceras de actualización de WebSocket; de lo contrario, el inicio de sesión se quedará bloqueado. Certbot con nginx es la configuración más sencilla para una sola aplicación. Traefik resulta más práctico si ejecuta varios contenedores detrás de un único proxy y quiere gestionar los certificados automáticamente.

¿Cómo hago una copia de seguridad de un Rocket.Chat autohospedado?

Cree un volcado coherente de la base de datos con mongodump en lugar de copiar el volumen: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. El archivo contiene usuarios, canales, mensajes y configuración, además de los archivos cargados si mantiene el almacenamiento en GridFS. Cópielo fuera del servidor, automatice la tarea cada noche con cron y pruebe una mongorestore en un equipo desechable para confirmar que la restauración funciona realmente.

¿Cómo actualizo Rocket.Chat sin romper MongoDB?

Actualice Rocket.Chat una versión principal cada vez. El programa ejecuta migraciones durante el arranque y no permite omitir versiones principales. Lea las notas de cada versión antes de cambiar la etiqueta de imagen fijada. Compruebe qué versiones de MongoDB admite la versión de destino con curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. Al actualizar MongoDB, avance una versión principal cada vez y establezca setFeatureCompatibilityVersion con confirm: true después de cada salto. Haga siempre una mongodump antes de empezar.