How to Deploy NATS – High-Performance Messaging
How to Deploy NATS – High-Performance Messaging
Deploy NATS with Docker Compose, JetStream persistence, secure authentication, and verified client connectivity.

NATS is a lightweight, high-performance messaging system designed for distributed and cloud-native applications. It supports publish-subscribe, request-reply, and streaming workloads through JetStream. NATS is widely used for microservices communication, event-driven systems, IoT messaging, and real-time data pipelines.
This article explains how to deploy NATS using Docker Compose, enable JetStream persistence, configure authentication and authorization, and verify client connectivity using the NATS CLI.
Prerequisites
Before you begin, you need to:
- Have access to an Ubuntu 24.04-based server as a non-root user with sudo privileges.
- Install Docker and Docker Compose.
Set Up the Directory Structure and Environment Variables
In this section, you create the required directory structure for NATS and define environment variables in a .env file that Docker Compose loads automatically.
- Create the project directory.
console
$ mkdir -p ~/nats-stack/{data,config}
- Navigate into the project directory.
console
$ cd ~/nats-stack
- Create and edit the
.envfile.console$ nano .envAdd the following variables:
iniNATS_CLIENT_PORT=4222 NATS_CLUSTER_PORT=6222
Replace:
NATS_CLIENT_PORTwith the client connection port.NATS_CLUSTER_PORTwith the cluster communication port.
Save and close the file.
Install NATS CLI and Create the NATS Configuration
In this section, you install the NATS CLI, generate secure credentials, and configure NATS with JetStream, authentication, and authorization.
- Download the NATS CLI binary.
console
$ curl -sf https://binaries.nats.dev/nats-io/natscli/nats@latest | sh
- Move the binary into your system PATH.
console
$ sudo mv nats /usr/local/bin/ - Verify the installation.
console
$ nats --version - Generate a password hash for the system or application user.
console
$ nats server passwdEnter the password twice and copy the generated hash.
Your output should be similar to the one below:
$2a$11$C6sj6xxxxx....Repeat this step for each user you want to define.
- Create the NATS configuration file.
console
$ nano config/nats.confAdd the following configuration:
ini# Client port port: 4222 monitor_port: 8222 server_name: "NATS_SERVER_NAME" # System account system_account: SYS accounts { SYS { users = [ { user: "sysadmin", password: "SYSTEM_PASSWORD_HASH" } ] } } # JetStream jetstream { store_dir: "/data/jetstream" max_mem_store: 1GB max_file_store: 5GB } authorization { default_permissions = { publish = "SANDBOX.*" subscribe = ["PUBLIC.>", "_INBOX.>"] } ADMIN = { publish = ">" subscribe = ">" } users = [ {user: USERNAME, password: "USER_PASSWORD_HASH", permissions: $ADMIN} ] }
In the above configuration:
server_nameidentifies the NATS server in logs, monitoring output, and system events.system_accountenables internal system features required for monitoring and JetStream management.accountsdefines authentication boundaries for system and application users.authorizationenforces subject-level access control, with an admin permission set that grants full publish and subscribe access.- JetStream enables message persistence with defined memory and disk limits.
Replace the following values before starting the service:
NATS_SERVER_NAMEwith a descriptive server name.SYSTEM_PASSWORD_HASHwith the bcrypt hash generated for the system user.USERNAMEwith your application user name.USER_PASSWORD_HASHwith the bcrypt hash generated for the application user.
Save and close the file.
Deploy with Docker Compose
In this section, you create the Docker Compose manifest that deploys NATS with JetStream persistence and monitoring enabled.
- Create the Docker Compose manifest.
console
$ nano docker-compose.yamlAdd the following content:
yamlservices: nats: image: nats:2.12 container_name: nats command: - "-c" - "/etc/nats/nats.conf" ports: - "${NATS_CLIENT_PORT}:4222" - "${NATS_CLUSTER_PORT}:6222" volumes: - "./data:/data" - "./config/nats.conf:/etc/nats/nats.conf:ro" restart: unless-stopped healthcheck: test: ["CMD", "nats", "server", "ping"] interval: 10s timeout: 5s retries: 5
Save and close the file.
In this manifest:
- image: Uses the official NATS 2.12 image.
- command: Loads the custom NATS configuration at startup.
- ports:
4222: Client connections.8222: Monitoring endpoint (localhost only).6222: Cluster communication.
- volumes:
./data: Persists JetStream messages../config/nats.conf: Injects the server configuration.
- healthcheck: Confirms the server responds to pings.
- restart: unless-stopped: Restarts the service automatically.
- Start the NATS service.
console
$ docker compose up -d - Verify that the NATS service is running.
console
$ docker compose psEnsure that the output shows the NATS container is healthy and running.
- View logs if needed.
console
$ docker compose logsFor more information on managing a Docker Compose stack, see the How To Use Docker Compose article.
Verify NATS Connectivity
In this section, you verify that the NATS server is reachable and accepting client connections.
Test connectivity using the NATS CLI.
$ nats --server nats://sysadmin:SYS_USER_PASSWORD@SERVER_IP:4222 server ping
Replace SYS_USER_PASSWORD and SERVER_IP with the system user password and server IP.
Output:
NATS_SERVER_NAME rtt=338.443125ms
---- ping statistics ----
1 replies max: 338.00 min: 338.00 avg: 338.00
Successful output confirms that the NATS server is reachable and authenticated correctly.
Conclusion
You successfully deployed NATS using Docker Compose with JetStream persistence enabled. You configured secure authentication and authorization, enabled persistent message storage, exposed the required messaging and verified client connectivity using the NATS CLI.