|
@@ -1,54 +1,80 @@
|
|
|
# client2server
|
|
# client2server
|
|
|
|
|
|
|
|
-> **Lightweight bi-directional event forwarder for OpenWrt routers**
|
|
|
|
|
|
|
+> **Bi-directional event forwarder + Apple-style dashboard for OpenWrt router fleets**
|
|
|
|
|
|
|
|
[](LICENSE)
|
|
[](LICENSE)
|
|
|
|
|
|
|
|
|
|
+Lightweight OpenWrt event forwarder with a real-time web dashboard.
|
|
|
|
|
+Routers stream DHCP, WiFi, and WAN events over WebSocket; the Go server
|
|
|
|
|
+fans them out to Redpanda and persists them to SQLite; a React/TypeScript
|
|
|
|
|
+SPA gives you live visibility and command control from any browser.
|
|
|
|
|
+
|
|
|
## Overview
|
|
## Overview
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
-┌─────────────────────────────────────────────────────────────┐
|
|
|
|
|
-│ client2server Architecture │
|
|
|
|
|
-├─────────────────────────────────────────────────────────────┤
|
|
|
|
|
-│ │
|
|
|
|
|
-│ OpenWrt Routers │
|
|
|
|
|
-│ │ │
|
|
|
|
|
-│ ▼ WebSocket :3843 │
|
|
|
|
|
-│ ┌──────────────────────────────────────────┐ │
|
|
|
|
|
-│ │ Caddy Load Balancer │ │
|
|
|
|
|
-│ │ - Health checks │ │
|
|
|
|
|
-│ │ - Auto-failover │ │
|
|
|
|
|
-│ └──────────────────┬───────────────────┘ │
|
|
|
|
|
-│ │ │
|
|
|
|
|
-│ ┌───────────┴───────────┐ │
|
|
|
|
|
-│ ▼ ▼ │
|
|
|
|
|
-│ ┌─────────────┐ ┌─────────────┐ │
|
|
|
|
|
-│ │ server1 │ │ server2 │ │
|
|
|
|
|
-│ │ (Go) │ │ (Go) │ │
|
|
|
|
|
-│ └─────┬───────┘ └─────┬───────┘ │
|
|
|
|
|
-│ │ │ │
|
|
|
|
|
-│ └────────┬─────────┘ │
|
|
|
|
|
-│ │ │
|
|
|
|
|
-│ ▼ │
|
|
|
|
|
-│ ┌─────────────────┐ │
|
|
|
|
|
-│ │ Redpanda │ Events stored │
|
|
|
|
|
-│ │ (Kafka) │ Persisted │
|
|
|
|
|
-│ └───────────────┘ │
|
|
|
|
|
-│ │
|
|
|
|
|
-└─────────────────────────────────────────────────────────────┘
|
|
|
|
|
|
|
+┌────────────────────────────────────────────────────────────────┐
|
|
|
|
|
+│ client2server Architecture │
|
|
|
|
|
+├────────────────────────────────────────────────────────────────┤
|
|
|
|
|
+│ │
|
|
|
|
|
+│ OpenWrt Routers │
|
|
|
|
|
+│ │ WebSocket :3843 + Hotplug (curl) │
|
|
|
|
|
+│ ▼ │
|
|
|
|
|
+│ ┌──────────────┐ │
|
|
|
|
|
+│ │ Caddy LB │ ────────────────┐ │
|
|
|
|
|
+│ │ :80/443 UI │ :3843 API/WS │ │
|
|
|
|
|
+│ └──────┬───────┘ └──────┬────────┘ │
|
|
|
|
|
+│ │ │ │
|
|
|
|
|
+│ ▼ ▼ │
|
|
|
|
|
+│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
|
|
|
+│ │ Dashboard │ │ server1 │ │ server2 │ │
|
|
|
|
|
+│ │ (React) │ │ (Go) │ │ (Go) │ │
|
|
|
|
|
+│ │ /login │ │ SQLite │ │ SQLite │ │
|
|
|
|
|
+│ │ /routers │ │ JWT │ │ JWT │ │
|
|
|
|
|
+│ │ /events │ │ SSE │ │ SSE │ │
|
|
|
|
|
+│ │ /commands │ │ WebSocket │ │ WebSocket │ │
|
|
|
|
|
+│ │ /alerts │ └──────┬──────┘ └──────┬──────┘ │
|
|
|
|
|
+│ └─────────────┘ │ │ │
|
|
|
|
|
+│ └────────┬─────────┘ │
|
|
|
|
|
+│ │ │
|
|
|
|
|
+│ ▼ │
|
|
|
|
|
+│ ┌─────────────────┐ │
|
|
|
|
|
+│ │ Redpanda │ Kafka protocol │
|
|
|
|
|
+│ │ :9092 │ Persisted │
|
|
|
|
|
+│ └─────────────────┘ │
|
|
|
|
|
+│ │
|
|
|
|
|
+└────────────────────────────────────────────────────────────────┘
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## Features
|
|
## Features
|
|
|
|
|
|
|
|
-- ✅ **WebSocket connection** with auto-reconnect
|
|
|
|
|
-- ✅ **Local buffer** (store-and-forward while offline)
|
|
|
|
|
-- ✅ **DHCP lease events** (new/expire)
|
|
|
|
|
-- ✅ **WAN link state** (up/down monitoring)
|
|
|
|
|
-- ✅ **WAN IP changes** (new ISP detection)
|
|
|
|
|
-- ✅ **Bidirectional** (receive commands from server)
|
|
|
|
|
-- ✅ **Command executor** (uci_set, shell, reboot, status)
|
|
|
|
|
-- ✅ **Load balancer** ready (Caddy)
|
|
|
|
|
-- ✅ **Event persistence** (Redpanda)
|
|
|
|
|
|
|
+### Server (Go)
|
|
|
|
|
+- ✅ **WebSocket** connection with auto-reconnect from routers
|
|
|
|
|
+- ✅ **HTTP POST** fallback for hotplug scripts
|
|
|
|
|
+- ✅ **Redpanda** (Kafka) event fan-out for downstream consumers
|
|
|
|
|
+- ✅ **SQLite** persistence (events, commands, alerts, users)
|
|
|
|
|
+- ✅ **JWT auth** with role-based access (system_admin / project_admin / user)
|
|
|
|
|
+- ✅ **Server-Sent Events** for real-time dashboard feed
|
|
|
|
|
+- ✅ **Time-series metrics** (1-min buckets, 24h retention)
|
|
|
|
|
+- ✅ **Alerts** for offline routers (auto-clear on reconnect)
|
|
|
|
|
+- ✅ **Command queue** for offline routers (auto-flush on reconnect)
|
|
|
|
|
+- ✅ **Idempotency** (5-min TTL on command IDs)
|
|
|
|
|
+- ✅ **Load balanced** behind Caddy (2× Go servers, health checks)
|
|
|
|
|
+
|
|
|
|
|
+### Router client (Lua)
|
|
|
|
|
+- ✅ **Hotplug-driven** WiFi connect/disconnect + DHCP lease events (instant, no polling)
|
|
|
|
|
+- ✅ **luv-based** async state-diff for WAN link, DHCP renew, IP changes (≤1s latency)
|
|
|
|
|
+- ✅ **UCI-configurable** server URL, token, check intervals
|
|
|
|
|
+- ✅ **Event buffer** for store-and-forward while offline
|
|
|
|
|
+- ✅ **Bidirectional** command execution (uci_set, shell, reboot, wifi_restart, status)
|
|
|
|
|
+
|
|
|
|
|
+### Dashboard (React)
|
|
|
|
|
+- ✅ **Apple-style** dark theme (frosted glass surfaces, gradient hero, tabular stat numbers)
|
|
|
|
|
+- ✅ **Live event feed** via Server-Sent Events
|
|
|
|
|
+- ✅ **Real-time charts** of events and commands over time
|
|
|
|
|
+- ✅ **Router list** with online/offline status and queued command count
|
|
|
|
|
+- ✅ **Command console** with target router picker and one-click reboot/wifi_restart/status
|
|
|
|
|
+- ✅ **Alerts inbox** with one-click acknowledgement
|
|
|
|
|
+- ✅ **Event history** with router-id and event-type filters
|
|
|
|
|
|
|
|
## Quick Start
|
|
## Quick Start
|
|
|
|
|
|
|
@@ -59,8 +85,18 @@
|
|
|
git clone https://git3.techno-world.net/lrosales/client2server.git
|
|
git clone https://git3.techno-world.net/lrosales/client2server.git
|
|
|
cd client2server
|
|
cd client2server
|
|
|
|
|
|
|
|
|
|
+# Set secrets (use any 32+ byte strings)
|
|
|
|
|
+cat > .env <<EOF
|
|
|
|
|
+TOKEN=replace-with-router-shared-secret
|
|
|
|
|
+JWT_SECRET=$(openssl rand -hex 32)
|
|
|
|
|
+EOF
|
|
|
|
|
+
|
|
|
# Start all services
|
|
# Start all services
|
|
|
-TOKEN=your-secret-token docker-compose up -d
|
|
|
|
|
|
|
+docker-compose up -d
|
|
|
|
|
+
|
|
|
|
|
+# Open the dashboard
|
|
|
|
|
+open http://localhost/
|
|
|
|
|
+# Login: admin / admin (CHANGE IN PRODUCTION)
|
|
|
|
|
|
|
|
# Check status
|
|
# Check status
|
|
|
docker-compose ps
|
|
docker-compose ps
|
|
@@ -69,12 +105,22 @@ docker-compose ps
|
|
|
### Option 2: Manual (Development)
|
|
### Option 2: Manual (Development)
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-# Go server
|
|
|
|
|
|
|
+# 1. Go server (with Redpanda running locally)
|
|
|
cd server
|
|
cd server
|
|
|
go build -o server .
|
|
go build -o server .
|
|
|
-REDPANDA_BROKERS=localhost:9092 TOKEN=*** ./server
|
|
|
|
|
-
|
|
|
|
|
-# On OpenWrt router (copy all files)
|
|
|
|
|
|
|
+REDPANDA_BROKERS=localhost:9092 \
|
|
|
|
|
+ TOKEN=replace-me \
|
|
|
|
|
+ JWT_SECRET=replace-me \
|
|
|
|
|
+ PORT=3843 \
|
|
|
|
|
+ ./server
|
|
|
|
|
+
|
|
|
|
|
+# 2. Dashboard (Vite dev server)
|
|
|
|
|
+cd dashboard
|
|
|
|
|
+npm install
|
|
|
|
|
+VITE_API_TARGET=http://localhost:3843 npm run dev
|
|
|
|
|
+# → http://localhost:5173
|
|
|
|
|
+
|
|
|
|
|
+# 3. On OpenWrt router (copy all files)
|
|
|
scp package/src/client2server-unified.lua root@router:/usr/sbin/
|
|
scp package/src/client2server-unified.lua root@router:/usr/sbin/
|
|
|
scp package/files/etc/init.d/client2server root@router:/etc/init.d/
|
|
scp package/files/etc/init.d/client2server root@router:/etc/init.d/
|
|
|
scp package/files/etc/config/client2server root@router:/etc/config/
|
|
scp package/files/etc/config/client2server root@router:/etc/config/
|
|
@@ -88,17 +134,21 @@ ssh root@router "/etc/init.d/client2server enable && /etc/init.d/client2server s
|
|
|
|
|
|
|
|
| Service | Port | Protocol |
|
|
| Service | Port | Protocol |
|
|
|
|----------|------|----------|
|
|
|----------|------|----------|
|
|
|
-| WebSocket + HTTP | 3843 | WS + HTTP (unified) |
|
|
|
|
|
-| Redpanda | 9092 | Kafka (Redpanda) |
|
|
|
|
|
|
|
+| Dashboard (web UI) | 80 / 443 | HTTP(S) |
|
|
|
|
|
+| WebSocket + HTTP API | 3843 | WS + HTTP (unified) |
|
|
|
|
|
+| Redpanda Kafka | 9092 | Kafka (Redpanda) |
|
|
|
|
|
+| Dashboard dev (Vite) | 5173 | HTTP (local dev only) |
|
|
|
|
|
|
|
|
## Configuration
|
|
## Configuration
|
|
|
|
|
|
|
|
### Environment Variables
|
|
### Environment Variables
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-TOKEN=*** # Authentication token
|
|
|
|
|
-REDPANDA_BROKERS=redpanda:9092 # Redpanda address
|
|
|
|
|
-PORT=3843 # Server port
|
|
|
|
|
|
|
+TOKEN=replace-with-shared-secret # Legacy router/hotplug shared token
|
|
|
|
|
+JWT_SECRET=replace-with-32+bytes # JWT signing key for dashboard auth
|
|
|
|
|
+REDPANDA_BROKERS=redpanda:9092 # Comma-separated Redpanda addresses
|
|
|
|
|
+PORT=3843 # Server listen port
|
|
|
|
|
+DB_PATH=/var/lib/c2s/client2server.db # SQLite path
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
### UCI Config (on Router)
|
|
### UCI Config (on Router)
|
|
@@ -110,43 +160,63 @@ config client2server 'general'
|
|
|
|
|
|
|
|
config server
|
|
config server
|
|
|
option url 'wss://your-server.com:3843'
|
|
option url 'wss://your-server.com:3843'
|
|
|
- option token '***'
|
|
|
|
|
|
|
+ option token 'replace-me'
|
|
|
|
|
|
|
|
config wan
|
|
config wan
|
|
|
option interface 'wan'
|
|
option interface 'wan'
|
|
|
option device 'eth0'
|
|
option device 'eth0'
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+## HTTP API
|
|
|
|
|
+
|
|
|
|
|
+All endpoints on `:3843`. The dashboard uses JWT (from `/api/auth/login`); routers use the legacy shared `TOKEN` directly.
|
|
|
|
|
+
|
|
|
|
|
+| Method | Path | Auth | Purpose |
|
|
|
|
|
+|--------|------|------|---------|
|
|
|
|
|
+| GET | `/health` | none | Liveness + router stats |
|
|
|
|
|
+| POST | `/api/auth/login` | none | `{username,password}` → JWT |
|
|
|
|
|
+| GET | `/api/auth/me` | JWT | Current user info |
|
|
|
|
|
+| POST | `/api/events` | token or JWT | Ingest event from router/hotplug |
|
|
|
|
|
+| GET | `/api/events/list` | JWT | Historical events (filterable) |
|
|
|
|
|
+| GET | `/api/events/stream` | token or JWT | Server-Sent Events live feed |
|
|
|
|
|
+| GET | `/api/routers` | none | Known routers |
|
|
|
|
|
+| POST | `/api/command` | token or JWT | Send command, awaits result |
|
|
|
|
|
+| GET | `/api/commands` | JWT | Command history |
|
|
|
|
|
+| GET | `/api/metrics?since=1h` | JWT | Time-series metrics |
|
|
|
|
|
+| GET | `/api/alerts?unack=1` | JWT | Alerts list |
|
|
|
|
|
+| POST | `/api/alerts/{id}/ack` | JWT | Acknowledge alert |
|
|
|
|
|
+| GET | `/ws` | token | WebSocket from router |
|
|
|
|
|
+
|
|
|
## Commands
|
|
## Commands
|
|
|
|
|
|
|
|
Send from server to router via WebSocket or HTTP API:
|
|
Send from server to router via WebSocket or HTTP API:
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-# UCI set
|
|
|
|
|
|
|
+# Reboot
|
|
|
curl -X POST http://localhost:3843/api/command \
|
|
curl -X POST http://localhost:3843/api/command \
|
|
|
-H "Authorization: Bearer TOKEN" \
|
|
-H "Authorization: Bearer TOKEN" \
|
|
|
- -d '{"router_id":"router1","command":"uci_set","args":{"config":"network","section":"lan","option":"ipaddr","value":"192.168.1.1"}}'
|
|
|
|
|
|
|
+ -d '{"router_id":"router1","command":"reboot"}'
|
|
|
|
|
|
|
|
-# Shell
|
|
|
|
|
|
|
+# UCI set
|
|
|
curl -X POST http://localhost:3843/api/command \
|
|
curl -X POST http://localhost:3843/api/command \
|
|
|
-H "Authorization: Bearer TOKEN" \
|
|
-H "Authorization: Bearer TOKEN" \
|
|
|
- -d '{"router_id":"router1","command":"shell","args":{"command":"reboot"}}'
|
|
|
|
|
|
|
+ -d '{"router_id":"router1","command":"uci_set","args":{"config":"network","section":"lan","option":"ipaddr","value":"192.168.1.1"}}'
|
|
|
|
|
|
|
|
-# Reboot
|
|
|
|
|
|
|
+# Shell
|
|
|
curl -X POST http://localhost:3843/api/command \
|
|
curl -X POST http://localhost:3843/api/command \
|
|
|
-H "Authorization: Bearer TOKEN" \
|
|
-H "Authorization: Bearer TOKEN" \
|
|
|
- -d '{"router_id":"router1","command":"reboot"}'
|
|
|
|
|
|
|
+ -d '{"router_id":"router1","command":"shell","args":{"command":"uptime"}}'
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
### Available Commands
|
|
### Available Commands
|
|
|
|
|
|
|
|
-| Command | Description | Arguments |
|
|
|
|
|
-|---------|-------------|-----------|
|
|
|
|
|
-| `uci_set` | Set UCI config value | `config`, `section`, `option`, `value` |
|
|
|
|
|
-| `shell` | Run shell command | `command` |
|
|
|
|
|
-| `reboot` | Reboot router | - |
|
|
|
|
|
-| `wifi_restart` | Restart WiFi | - |
|
|
|
|
|
-| `status` | Get router status | - |
|
|
|
|
|
|
|
+| Command | Description | Arguments | Dangerous |
|
|
|
|
|
+|---------|-------------|-----------|-----------|
|
|
|
|
|
+| `reboot` | Reboot router | — | ⚠️ |
|
|
|
|
|
+| `wifi_restart` | Restart WiFi | — | |
|
|
|
|
|
+| `status` | Get router status | — | |
|
|
|
|
|
+| `shell` | Run shell command | `command` | ⚠️ |
|
|
|
|
|
+| `uci_set` | Set UCI config value | `config,section,option,value` | ⚠️ |
|
|
|
|
|
|
|
|
## Events
|
|
## Events
|
|
|
|
|
|
|
@@ -168,24 +238,39 @@ Router sends these events to server:
|
|
|
```
|
|
```
|
|
|
client2server/
|
|
client2server/
|
|
|
├── ARCHITECTURE.md # Architecture docs
|
|
├── ARCHITECTURE.md # Architecture docs
|
|
|
-├── README.md # This file
|
|
|
|
|
-├── MEMORY.md # Project memory (AI/agent context)
|
|
|
|
|
-├── Caddyfile # Caddy load balancer
|
|
|
|
|
-├── docker-compose.yml # Full stack
|
|
|
|
|
-├── package/
|
|
|
|
|
-│ ├── Makefile # IPK build
|
|
|
|
|
|
|
+├── README.md # This file
|
|
|
|
|
+├── MEMORY.md # Project memory (AI/agent context)
|
|
|
|
|
+├── Caddyfile # Caddy load balancer
|
|
|
|
|
+├── docker-compose.yml # Full stack
|
|
|
|
|
+├── package/ # OpenWrt IPK build
|
|
|
|
|
+│ ├── Makefile
|
|
|
│ ├── src/
|
|
│ ├── src/
|
|
|
│ │ └── client2server-unified.lua # Router script (canonical)
|
|
│ │ └── client2server-unified.lua # Router script (canonical)
|
|
|
│ ├── files/
|
|
│ ├── files/
|
|
|
│ │ ├── etc/init.d/client2server
|
|
│ │ ├── etc/init.d/client2server
|
|
|
│ │ └── etc/config/client2server
|
|
│ │ └── etc/config/client2server
|
|
|
│ └── hotplug/
|
|
│ └── hotplug/
|
|
|
-│ ├── 01-wifi # /etc/hotplug.d/wireless/ - instant WiFi events
|
|
|
|
|
-│ └── 02-dhcp # /etc/hotplug.d/dhcp/ - instant DHCP events
|
|
|
|
|
-└── server/
|
|
|
|
|
- ├── main.go
|
|
|
|
|
- ├── go.mod
|
|
|
|
|
- └── Dockerfile
|
|
|
|
|
|
|
+│ ├── 01-wifi # /etc/hotplug.d/wireless/ - instant WiFi events
|
|
|
|
|
+│ └── 02-dhcp # /etc/hotplug.d/dhcp/ - instant DHCP events
|
|
|
|
|
+├── server/ # Go server
|
|
|
|
|
+│ ├── main.go # WS handler + HTTP API + ingestEvent
|
|
|
|
|
+│ ├── auth.go # JWT + scrypt + login + middleware
|
|
|
|
|
+│ ├── consumer.go # Redpanda → SQLite consumer
|
|
|
|
|
+│ ├── metrics.go # 1-min buckets, 24h retention
|
|
|
|
|
+│ ├── sse.go # SSE broadcaster
|
|
|
|
|
+│ ├── store.go # SQLite (users, events, commands, alerts)
|
|
|
|
|
+│ ├── go.mod
|
|
|
|
|
+│ └── Dockerfile
|
|
|
|
|
+└── dashboard/ # React SPA (Apple-style)
|
|
|
|
|
+ ├── src/
|
|
|
|
|
+ │ ├── App.tsx # Routes + auth gate
|
|
|
|
|
+ │ ├── styles.css # Apple design tokens
|
|
|
|
|
+ │ ├── lib/{api,types,sse}.ts
|
|
|
|
|
+ │ ├── components/{Shell,ui}.tsx
|
|
|
|
|
+ │ └── pages/{Login,Overview,Routers,Events,Commands,Alerts}.tsx
|
|
|
|
|
+ ├── screenshots/ # Visual reference (6 retina PNGs)
|
|
|
|
|
+ ├── Dockerfile # Node builder + Caddy runtime
|
|
|
|
|
+ └── Caddyfile.production # /api + /ws proxy, SPA fallback
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## Building IPK
|
|
## Building IPK
|
|
@@ -201,6 +286,16 @@ make package/client2server-unified/ipk
|
|
|
# bin/packages/*/client2server-unified_*.ipk
|
|
# bin/packages/*/client2server-unified_*.ipk
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+## Building Dashboard
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd dashboard
|
|
|
|
|
+npm install
|
|
|
|
|
+npm run build # → dist/ (static files)
|
|
|
|
|
+# Or development server:
|
|
|
|
|
+VITE_API_TARGET=http://localhost:3843 npm run dev
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
## Monitoring
|
|
## Monitoring
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
@@ -218,13 +313,27 @@ curl http://localhost:3843/api/routers
|
|
|
curl http://localhost:3843/api/events
|
|
curl http://localhost:3843/api/events
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+## Default Credentials
|
|
|
|
|
+
|
|
|
|
|
+The Go server creates a default admin user on first run:
|
|
|
|
|
+
|
|
|
|
|
+- **Username:** `admin`
|
|
|
|
|
+- **Password:** `admin`
|
|
|
|
|
+
|
|
|
|
|
+**Change this immediately in production.** Connect to the SQLite database
|
|
|
|
|
+and replace the password hash, or extend the `/api/auth` endpoints to
|
|
|
|
|
+expose a user-management UI.
|
|
|
|
|
+
|
|
|
## Security
|
|
## Security
|
|
|
|
|
|
|
|
-- Token-based auth on both WS and HTTP
|
|
|
|
|
-- Use TLS (wss://) in production
|
|
|
|
|
-- Firewalls: Only allow port 3843 from router network
|
|
|
|
|
-- Redpanda: Enable auth for production
|
|
|
|
|
|
|
+- **JWT auth** for dashboard access (HS256, 24h tokens)
|
|
|
|
|
+- **Legacy shared token** for router/hotplug access (simpler on minimal OpenWrt)
|
|
|
|
|
+- **Use TLS** (`wss://`, `https://`) in production
|
|
|
|
|
+- **Firewalls**: Only allow port 3843 from router network
|
|
|
|
|
+- **Redpanda**: Enable auth for production
|
|
|
|
|
+- **JWT_SECRET**: Must be 32+ random bytes in production
|
|
|
|
|
+- **Bind Caddy to a reverse proxy** (Cloudflare, nginx) for HTTPS termination
|
|
|
|
|
|
|
|
## License
|
|
## License
|
|
|
|
|
|
|
|
-MIT - Luis Rosales 2026
|
|
|
|
|
|
|
+MIT - Luis Rosales 2026
|