client2server
Lightweight event forwarder for OpenWrt routers to central server
Version 2.0 - Lua + WebSocket implementation
Overview
Lightweight Lua scripts that listen to OpenWrt events (WiFi, DHCP, network) and forward them to a central server via WebSocket with auto-reconnect and local buffering.
Why Lua + WebSocket?
| Feature |
Bash (v1) |
Lua + WS (v2) |
| Connection |
HTTP polling |
WebSocket (persistent) |
| Auto-reconnect |
Manual |
Built-in |
| Offline buffer |
File only |
In-memory + file |
| Error handling |
Basic |
Exception-safe |
| Size |
~20KB |
~30KB inc. deps |
Architecture
┌─────────────────┐ WebSocket ┌─────────────────┐
│ OpenWrt │ ════════════════► │ Central Server │
│ Router │ │ │
│ │ │ - Receive │
│ - DHCP │ │ - Store │
│ - WiFi │ │ - Real-time │
│ - Network │ │ - LuIS UI │
│ │ │ │
│ Buffer [offline]│─► sync when ──► │ │
└─────────────────┘ online └─────────────────┘
Installing
On OpenWrt Router
# Install dependencies
opkg update
opkg install lua luasocket
# Copy files
scp -r etc root@router:/etc/
scp -r usr root@router:/usr/
# Make executable
chmod +x /etc/init.d/event-forwarder
chmod +x /usr/sbin/event-forwarder.lua
# Configure
uci set event-forwarder.server.url='wss://your-server.com/ws'
uci set event-forwarder.server.token='your-secret-token'
uci set event-forwarder.general.enabled='1'
uci commit event-forwarder
# Enable and start
/etc/init.d/event-forwarder enable
/etc/init.d/event-forwarder start
# Check logs
logread -f -e client2server
On Central Server
cd server
npm install express ws
node server.js
Files
| File |
Purpose |
usr/sbin/client2server.lua |
Main Lua forwarder |
usr/sbin/event-forwarder.lua |
Original Lua prototype |
etc/init.d/event-forwarder |
Init script |
etc/config/event-forwarder |
UCI config |
server/index.js |
Central Node.js receiver |
README.md |
This file |
Configuration
UCI Config
# /etc/config/event-forwarder
config event-forwarder 'general'
option enabled '1'
config server
option url 'wss://your-server.com/ws'
option token 'CHANGE_ME_SECRET_TOKEN'
config router
option id 'router-hostname'
Environment Variables
export SERVER_URL="wss://your-server.com/ws"
export SERVER_TOKEN="your-token"
export ROUTER_ID="router-name"
Event Types
| Event |
Source |
Payload |
dhcp_lease |
dnsmasq |
mac, ip, hostname, action |
wifi_connect |
hostapd |
mac, signal, ssid |
wifi_disconnect |
hostapd |
mac, reason |
interface_up |
netifd |
device |
interface_down |
netifd |
device |
API Specification
WebSocket Message Format
{
"router_id": "router-name",
"hostname": "openwrt-device",
"event_type": "dhcp_lease",
"timestamp": "2026-06-04T18:00:00Z",
"payload": {
"mac": "AA:BB:CC:DD:EE:FF",
"ip": "192.168.1.100",
"hostname": "iphone",
"action": "new"
}
}
Server Endpoint
// Expects WebSocket connection
wss://your-server.com/ws
// Or HTTP POST fallback
POST /api/events
Authorization: Bearer <token>
Content-Type: application/json
Offline Behavior
- Internet disconnects → Events saved to local buffer
- Router reboots → Buffer persists in
/tmp/event_buffer
- Internet restores → Buffer flushed in order
- Never lose events ✓
Troubleshooting
# Check if running
pgrep -a client2server
# View logs
logread -f -e client2server
# Check buffer
cat /tmp/event_buffer
# Manual test
lua /usr/sbin/client2server.lua
# Force stop
killall -9 client2server
Dependencies
- OpenWrt:
lua, luasocket
- Server:
express, ws (npm)
License
MIT - Luis Rosales 2026