NATS es un sistema de mensajería ligero escrito en Go que ofrece publicación/suscripción, request-reply y colas de trabajo con latencias de microsegundos y un único binario sin dependencias. Su capa JetStream añade persistencia: streams que guardan mensajes en disco y consumidores que los leen con confirmación. En este tutorial instalarás NATS Server en Ubuntu 24.04 como servicio systemd, lo configurarás con autenticación y JetStream, y probarás los patrones principales con la CLI oficial nats.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS de 64 bits (x86_64), por ejemplo un VPS de CubePath, con al menos 1 GB de RAM.
  • Un usuario no root con privilegios sudo.
  • UFW activo con SSH permitido.

Paso 1: Instalar NATS Server

NATS Server se distribuye como un binario estático en las releases de GitHub. Consulta la última versión estable en la página de releases de nats-io/nats-server y ajusta la variable:

NATS_VERSION=2.11.0
cd /tmp
curl -fLO "https://github.com/nats-io/nats-server/releases/download/v${NATS_VERSION}/nats-server-v${NATS_VERSION}-linux-amd64.tar.gz"

Comprueba el hash del archivo con sha256sum y compáralo con el que aparece en el archivo SHA256SUMS de la misma release:

sha256sum "nats-server-v${NATS_VERSION}-linux-amd64.tar.gz"

Extrae el binario e instálalo en /usr/local/bin:

tar -xzf "nats-server-v${NATS_VERSION}-linux-amd64.tar.gz"
sudo install -m 0755 "nats-server-v${NATS_VERSION}-linux-amd64/nats-server" /usr/local/bin/nats-server

Verifica la instalación:

nats-server --version
nats-server: v2.11.0

Paso 2: Instalar la CLI de NATS

La CLI nats sirve para publicar, suscribirse, gestionar streams y consultar el estado del servidor. El proyecto ofrece un script que descarga el binario compilado para tu plataforma en el directorio actual. Descárgalo primero, revísalo y ejecútalo:

cd /tmp
curl -sf https://binaries.nats.dev/nats-io/natscli/nats@latest -o install-nats-cli.sh
less install-nats-cli.sh
sh install-nats-cli.sh
sudo install -m 0755 nats /usr/local/bin/nats

Comprueba que funciona:

nats --version

Paso 3: Crear el usuario y los directorios

Ejecuta NATS con un usuario de sistema sin privilegios y crea los directorios de configuración y de datos de JetStream:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin nats
sudo install -d -m 0755 /etc/nats
sudo install -d -o nats -g nats -m 0750 /var/lib/nats/jetstream

Paso 4: Configurar NATS con autenticación y JetStream

No guardes contraseñas en claro en la configuración. La CLI genera un hash bcrypt a partir de la contraseña que escribas:

nats server passwd
? Enter password [? for help] ********************
? Reenter password [? for help] ********************

$2a$11$Ra9Jr0...

Guarda la contraseña en tu gestor de contraseñas y copia el hash. Repite el comando para un segundo usuario de administración. Después crea el archivo de configuración:

sudo nano /etc/nats/nats-server.conf
server_name: nats-1

# Puerto de clientes
listen: 0.0.0.0:4222

# Endpoint HTTP de monitorización, solo en local
http: 127.0.0.1:8222

jetstream {
  store_dir: /var/lib/nats/jetstream
  max_memory_store: 256MB
  max_file_store: 10GB
}

accounts {
  APP {
    jetstream: enabled
    users: [
      { user: app, password: "$2a$11$hash_del_usuario_app" }
    ]
  }
  SYS {
    users: [
      { user: admin, password: "$2a$11$hash_del_usuario_admin" }
    ]
  }
}
system_account: SYS

max_payload: 1MB

Qué define esta configuración:

  • La cuenta APP es un espacio aislado de mensajes para tu aplicación, con JetStream habilitado. Los usuarios de una cuenta no ven los subjects de otra.
  • La cuenta SYS es la cuenta de sistema: su usuario puede consultar el estado del servidor y de JetStream con la CLI.
  • max_memory_store y max_file_store limitan cuánto pueden ocupar los streams en memoria y en disco.
  • max_payload es el tamaño máximo de un mensaje. NATS está pensado para mensajes pequeños; para archivos grandes guarda el archivo en otro sitio y envía la referencia.

Protege el archivo, porque contiene los hashes:

sudo chown root:nats /etc/nats/nats-server.conf
sudo chmod 0640 /etc/nats/nats-server.conf

Comprueba que la sintaxis es correcta:

sudo -u nats nats-server -t -c /etc/nats/nats-server.conf

Si hay un error, el comando indica el archivo y la línea donde está; si no, termina sin mostrar errores.

Paso 5: Crear el servicio systemd

sudo nano /etc/systemd/system/nats.service
[Unit]
Description=NATS Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=nats
Group=nats
ExecStart=/usr/local/bin/nats-server -c /etc/nats/nats-server.conf
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

ExecReload envía la señal HUP, con la que NATS recarga la configuración (por ejemplo, usuarios nuevos) sin cortar conexiones. Arranca el servicio:

sudo systemctl daemon-reload
sudo systemctl enable --now nats
systemctl status nats --no-pager

Revisa el log de arranque:

sudo journalctl -u nats -n 20 --no-pager
[INF] Starting nats-server
[INF]   Version:  2.11.0
[INF] Starting JetStream
[INF] Starting http monitor on 127.0.0.1:8222
[INF] Listening for client connections on 0.0.0.0:4222
[INF] Server is ready

Consulta también el endpoint de salud:

curl -s http://127.0.0.1:8222/healthz
{"status":"ok"}

Paso 6: Configurar contextos en la CLI

Los contextos guardan servidor y credenciales para no repetirlos en cada comando. Crea uno para la aplicación y otro para el administrador, con las contraseñas en claro que generaste en el paso 4:

nats context save app --server nats://127.0.0.1:4222 --user app --password 'your_app_password' --select
nats context save sys --server nats://127.0.0.1:4222 --user admin --password 'your_admin_password'

Comprueba la conexión con el contexto activo (app):

nats account info

La salida muestra la cuenta APP conectada y el apartado de JetStream con los límites de memoria y disco.

Paso 7: Probar publicación/suscripción y request-reply

En NATS los mensajes se publican en subjects jerárquicos separados por puntos. El comodín * sustituye un nivel y > uno o más niveles al final.

Abre una segunda sesión SSH y suscríbete a todos los eventos de pedidos:

nats sub 'orders.>'

En la primera sesión, publica un mensaje:

nats pub orders.created '{"order_id": 1, "total": 19.90}'

En la sesión suscrita aparecerá:

[#1] Received on "orders.created"
{"order_id": 1, "total": 19.90}

Los mensajes de NATS básico no se guardan: si no hay nadie suscrito en ese momento, el mensaje se pierde. Para repartir trabajo entre varias instancias de un servicio, suscríbelas a un grupo de cola con --queue; cada mensaje llega solo a una de ellas:

nats sub 'orders.>' --queue workers

Para request-reply, deja un servicio respondiendo en la segunda sesión (detén antes la suscripción con Ctrl+C):

nats reply 'inventory.check' '{"available": true}'

Y envía una petición desde la primera:

nats request inventory.check '{"sku": "ABC-123"}'
Received with rtt 412µs
{"available": true}

Paso 8: Guardar mensajes con JetStream

Un stream de JetStream captura los mensajes publicados en unos subjects y los conserva según su política de retención, aunque no haya consumidores conectados. Crea un stream ORDERS que guarde en disco todo lo publicado en orders.> durante 7 días:

nats stream add ORDERS --subjects 'orders.>' --storage file --retention limits \
  --max-age 7d --discard old --replicas 1 --defaults

Publica tres mensajes y consulta el stream:

for i in 1 2 3; do nats pub orders.created "{\"order_id\": $i}"; done
nats stream info ORDERS
State:

             Messages: 3
                Bytes: 213 B
       First Sequence: 1 @ 2026-09-25 10:20:01 UTC
        Last Sequence: 3 @ 2026-09-25 10:20:01 UTC
     Active Consumers: 0

Crea un consumidor duradero de tipo pull. Recuerda su posición y exige confirmación explícita de cada mensaje:

nats consumer add ORDERS billing --pull --deliver all --ack explicit --defaults

Lee y confirma los mensajes pendientes:

nats consumer next ORDERS billing --count 3
[10:21:14] subj: orders.created / tries: 1 / cons seq: 1 / str seq: 1 / pending: 2
{"order_id": 1}
Acknowledged message
...

Si vuelves a ejecutar el comando, no quedarán mensajes pendientes para billing, pero los mensajes siguen en el stream hasta que caduquen. Otro consumidor nuevo podría leerlos desde el principio.

Con el contexto de sistema puedes ver el uso de JetStream del servidor:

nats server report jetstream --context sys

Paso 9: Abrir el puerto a los clientes

Permite el puerto 4222 solo desde las IPs de tus aplicaciones:

sudo ufw allow from app_server_ip to any port 4222 proto tcp
sudo ufw status

El puerto 8222 de monitorización escucha solo en 127.0.0.1 y no necesita regla.

Formar un clúster de tres nodos

Para alta disponibilidad, repite la instalación en tres servidores de la misma red privada y añade un bloque cluster a cada configuración. Cada nodo necesita un server_name distinto (nats-1, nats-2, nats-3) y las mismas cuentas:

cluster {
  name: nats-cluster
  listen: 0.0.0.0:6222
  routes: [
    nats-route://10.0.0.11:6222
    nats-route://10.0.0.12:6222
    nats-route://10.0.0.13:6222
  ]
}

Abre el puerto 6222 solo entre los nodos:

sudo ufw allow from 10.0.0.0/24 to any port 6222 proto tcp

Tras reiniciar los tres servicios, nats server list --context sys debe mostrar los tres servidores. Los streams creados con --replicas 3 se replican en los tres nodos y siguen disponibles si cae uno. Los clientes deben recibir la lista de los tres servidores (nats://10.0.0.11:4222,nats://10.0.0.12:4222,nats://10.0.0.13:4222) para reconectar a otro nodo automáticamente.

Solución de problemas

  • Authorization Violation al conectar: usuario o contraseña incorrectos. Recuerda que en la configuración va el hash bcrypt y en el cliente la contraseña en claro.
  • JetStream not enabled for account: falta jetstream: enabled en la cuenta del usuario o el bloque jetstream del servidor.
  • El servicio no arranca con un error de permisos en /var/lib/nats/jetstream: el directorio debe pertenecer al usuario nats. Corrígelo con sudo chown -R nats:nats /var/lib/nats.
  • Maximum Payload Violation: el mensaje supera max_payload. Reduce el tamaño del mensaje en lugar de subir el límite.

Conclusión

Tienes NATS Server funcionando como servicio systemd con autenticación por cuentas, contraseñas en bcrypt, JetStream en disco y la monitorización restringida a localhost, y has probado pub/sub, grupos de cola, request-reply y consumidores persistentes. Como siguientes pasos, añade TLS a las conexiones de clientes, forma un clúster de tres nodos con streams replicados y conecta tus servicios con una de las librerías oficiales (Go, Python nats-py, Node.js, Java o Rust).