|
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
# NATS Expert
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This project deploys a NATS server behind Coolify, reachable **over WebSockets** only. NATS' native TCP port (4222) is not exposed to the outside — the WS endpoint is the sole entry point for both applications and the managing agent.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Deployment target
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- **Coolify project:** `Volcanic MFEs` (`p4fts5a0kv3tahzjtbtfequk`)
|
|
|
|
|
|
|
|
- **Server:** `localhost` (`d0c4owww4kwo0ow08wws4ss8`)
|
|
|
|
|
|
|
|
- **Build pack:** `dockercompose`
|
|
|
|
|
|
|
|
- **Compose file:** `/docker-compose.yml`
|
|
|
|
|
|
|
|
- **Public domain:** `https://nats.volcanic.tes.gd` → routed by Traefik to `nats:8080` (WebSocket listener)
|
|
|
|
|
|
|
|
- **TLS:** terminated at Traefik. NATS itself runs with `no_tls: true` on the WS listener.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Coolify's non-secret app config (project/server UUIDs, name, domain) lives in `deploy.json` at the repo root and is **gitignored** — it is regenerated locally when needed by the `deploying-to-coolify-via-api` skill flow.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Connection details (for agents managing this NATS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Both are populated from the two env vars set on the Coolify application:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- `NATS_USER` — admin username (default: `admin`)
|
|
|
|
|
|
|
|
- `NATS_PASSWORD` — admin password (generated at deploy time, stored in the Coolify app's env vars)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The current live values are printed by:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
: "${COOLIFY_URL:?}" "${COOLIFY_KEY:?}"
|
|
|
|
|
|
|
|
APP_UUID=$(jq -r '.app.uuid' deploy.json) # from local deploy.json
|
|
|
|
|
|
|
|
curl -sS -H "Authorization: Bearer $COOLIFY_KEY" \
|
|
|
|
|
|
|
|
"$COOLIFY_URL/api/v1/applications/$APP_UUID/envs" \
|
|
|
|
|
|
|
|
| jq -r '.[] | select(.is_preview==false) | "\(.key)=\(.value)"'
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
If `deploy.json` is not present, list applications under the Volcanic MFEs project and find the one named `nats`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
curl -sS -H "Authorization: Bearer $COOLIFY_KEY" \
|
|
|
|
|
|
|
|
"$COOLIFY_URL/api/v1/projects/p4fts5a0kv3tahzjtbtfequk" \
|
|
|
|
|
|
|
|
| jq '.applications[] | {uuid, name}'
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### WebSocket URL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
wss://nats.volcanic.tes.gd
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The NATS server accepts standard NATS-over-WebSocket framing (RFC 6455 with the `nats` subprotocol). No custom path; connect to the root URL.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### With `nats` CLI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
nats \
|
|
|
|
|
|
|
|
--server=wss://nats.volcanic.tes.gd \
|
|
|
|
|
|
|
|
--user="$NATS_USER" --password="$NATS_PASSWORD" \
|
|
|
|
|
|
|
|
server info
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### With `nats.js` / `nats.ws` (Node/browser)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
|
|
import { connect } from 'nats.ws'; // browser
|
|
|
|
|
|
|
|
// import { connect } from 'nats'; // node with ws
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const nc = await connect({
|
|
|
|
|
|
|
|
servers: 'wss://nats.volcanic.tes.gd',
|
|
|
|
|
|
|
|
user: process.env.NATS_USER,
|
|
|
|
|
|
|
|
pass: process.env.NATS_PASSWORD,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### With `nats-py`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
import asyncio, os
|
|
|
|
|
|
|
|
from nats.aio.client import Client as NATS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def main():
|
|
|
|
|
|
|
|
nc = NATS()
|
|
|
|
|
|
|
|
await nc.connect(
|
|
|
|
|
|
|
|
servers=['wss://nats.volcanic.tes.gd'],
|
|
|
|
|
|
|
|
user=os.environ['NATS_USER'],
|
|
|
|
|
|
|
|
password=os.environ['NATS_PASSWORD'],
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
await nc.publish('hello', b'world')
|
|
|
|
|
|
|
|
await nc.drain()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
asyncio.run(main())
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## What's inside the server
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- **Listeners**
|
|
|
|
|
|
|
|
- `4222` — native NATS protocol, `expose`d only inside the compose network. Not reachable from outside.
|
|
|
|
|
|
|
|
- `8080` — WebSocket listener, `no_tls: true`. Traefik terminates TLS and forwards `ws://nats:8080` from the public `wss://nats.volcanic.tes.gd`.
|
|
|
|
|
|
|
|
- `8222` — HTTP monitoring (`/healthz`, `/varz`, `/jsz`), internal only. Used by the compose healthcheck.
|
|
|
|
|
|
|
|
- **JetStream**: enabled, persisted to the named volume `nats-data` mounted at `/data`. Limits: 256MB memory / 4GB file. Bump `max_file_store` in `nats-server.conf` if you need more.
|
|
|
|
|
|
|
|
- **Auth**: a single user, whose name and password come from the `NATS_USER` / `NATS_PASSWORD` env vars via NATS' native `$VAR` substitution in the config. No accounts, no operator/JWT mode.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Managing / redeploying
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Config or compose changes → commit and push to `main`, then trigger a Coolify deploy (fire-and-forget):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
: "${COOLIFY_URL:?}" "${COOLIFY_KEY:?}"
|
|
|
|
|
|
|
|
APP_UUID=$(jq -r '.app.uuid' deploy.json) # or look it up as shown above
|
|
|
|
|
|
|
|
curl -sS -X POST "$COOLIFY_URL/api/v1/deploy?uuid=$APP_UUID" \
|
|
|
|
|
|
|
|
-H "Authorization: Bearer $COOLIFY_KEY"
|
|
|
|
|
|
|
|
# → { "deployments": [ { "deployment_uuid": "…" } ] } done, don't poll
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rotating the password: PATCH the `NATS_PASSWORD` env on the Coolify app, then redeploy. Do not edit `nats-server.conf` — auth is env-driven.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To add a second user (e.g. a scoped app account), edit the `authorization.users` array in `nats-server.conf`, wire the new credential env vars into `docker-compose.yml`, and set them in Coolify.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Files in this repo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| File | Purpose |
|
|
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
|
|
| `docker-compose.yml` | Single `nats` service, exposes 4222/8080/8222 internally; only 8080 is routed publicly via `SERVICE_FQDN_NATS_8080` + Coolify's `docker_compose_domains`. |
|
|
|
|
|
|
|
|
| `nats-server.conf` | NATS config: JetStream, WebSocket listener (`no_tls`), env-driven auth. |
|
|
|
|
|
|
|
|
| `.gitignore` | Keeps `deploy.json` out of git. |
|
|
|
|
|
|
|
|
| `deploy.json` (local only) | Coolify app config used by the `deploying-to-coolify-via-api` skill. |
|