TypeScript-based FreeSWITCH Event Socket Layer (ESL) client with HTTP API
This service connects to FreeSWITCH via Event Socket, processes events, and provides an HTTP API for commands and monitoring. Designed for use with vgtpbx-switch.
- Event Processing - Subscribe to and handle FreeSWITCH events
- Event Forwarding - Forward selected events to PBX API
- HTTP API - RESTful endpoints for commands and status checks
- Auto-Reconnect - Automatic reconnection when FreeSWITCH disconnects
- Structured Logging - JSON logs via Pino
- TypeScript - Type-safe codebase
- bgapi Support - Async FreeSWITCH command execution
# Clone repository
git clone https://github.com/vogatpbx/vogat-eslserver.git
cd vogat-eslserver
# Install dependencies
npm install
# Configure environment (optional, see Configuration section)
export FREESWITCH_HOST=127.0.0.1
export FREESWITCH_ESL_PORT=8021
export FREESWITCH_ESL_PASSWORD=ClueCon
# Run in development mode
npm run dev
# Or build and run
npm run build
npm start# Build image
docker build -t vgtpbx-eslserver:latest .
# Run standalone (requires FreeSWITCH running)
docker run -d \
--name vgtpbx-eslserver \
--network host \
-e FREESWITCH_HOST=127.0.0.1 \
-e FREESWITCH_ESL_PORT=8021 \
-e FREESWITCH_ESL_PASSWORD=ClueCon \
vgtpbx-eslserver:latest
# Or use docker-compose
docker-compose up -d| Variable | Default | Description |
|---|---|---|
FREESWITCH_HOST |
127.0.0.1 |
FreeSWITCH server hostname/IP |
FREESWITCH_ESL_PORT |
8021 |
FreeSWITCH Event Socket port |
FREESWITCH_ESL_PASSWORD |
ClueCon |
ESL password (change in production!) |
NEXTJS_INTERNAL_API_URL |
http://localhost:3000/api/httpapihandler |
PBX API endpoint for event forwarding |
API_PORT |
8081 |
HTTP API port for this service |
NODE_ENV |
development |
Environment (production/development) |
Ensure FreeSWITCH Event Socket is configured in event_socket.conf.xml:
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="listen-ip" value="127.0.0.1"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
</settings>
</configuration>The service exposes an HTTP API on port 8081 (configurable via API_PORT).
GET http://127.0.0.1:8081/health
Response:
{
"status": "ok",
"eslConnected": <FreeSwitchClient object or null>
}POST http://127.0.0.1:8081/registrations/sofia-contact
Content-Type: application/json
{
"extension": "1001",
"profile": "internal",
"domain": "example.com"
}
Response:
{
"success": true,
"registrations": {
"extension": "1001",
"contact": "sofia/internal/1001@example.com",
"status": "Registered",
"agent": "Unknown",
"ip": "192.168.1.100"
}
}POST http://127.0.0.1:8081/commands/log
Content-Type: application/json
{
"level": "INFO",
"message": "Test log message"
}
Response:
{
"success": true,
"response": "..."
}By default, the following events are enabled:
CHANNEL_UNBRIDGE- Call legs disconnectedCHANNEL_EXECUTE- Dialplan app executionRECORD_START- Recording startedRECORD_STOP- Recording stoppedSHUTDOWN_REQUESTED- FreeSWITCH shutdownSTARTUP- FreeSWITCH startedRELOADXML- XML config reloadedREQUEST_PARAMS- Parameter requestsBACKGROUND_JOB- Async command results
Edit src/index.ts and uncomment desired events:
// Uncomment to enable
eslClient.on('CHANNEL_CREATE', handleChannelCreate);
eslClient.on('CHANNEL_ANSWER', handleChannelAnswer);
eslClient.on('CHANNEL_HANGUP', handleChannelHangup);
// ... etcAfter changes, rebuild:
npm run build
npm startOr rebuild Docker image:
docker build -t vgtpbx-eslserver:latest .Events are automatically forwarded to the PBX API configured in NEXTJS_INTERNAL_API_URL.
Payload format:
{
"eventName": "CHANNEL_ANSWER",
"subClass": null,
"eventData": {
"eventName": "CHANNEL_ANSWER",
"channelData": { /* FreeSWITCH channel data */ },
"rawEventData": { /* Full ESL event */ },
"timestamp": "2026-01-11T10:30:00.000Z"
},
"timestamp": "2026-01-11T10:30:00.000Z"
}┌─────────────────────────────────────────┐
│ FreeSWITCH │
│ Event Socket :8021 │
└────────────────┬────────────────────────┘
│
│ ESL Protocol
│
┌────────────────▼────────────────────────┐
│ vogat-eslserver │
│ │
│ ┌─────────────────────────────────┐ │
│ │ ESL Client (esl-lite) │ │
│ │ - Event subscriptions │ │
│ │ - Auto-reconnect │ │
│ │ - bgapi commands │ │
│ └──────────┬──────────────────────┘ │
│ │ │
│ ┌──────────▼──────────────────────┐ │
│ │ Event Handlers │ │
│ │ - Process events │ │
│ │ - Forward to PBX API │ │
│ └──────────┬──────────────────────┘ │
│ │ │
│ ┌──────────▼──────────────────────┐ │
│ │ HTTP API (Express) :8081 │ │
│ │ - /health │ │
│ │ - /registrations/sofia-contact │ │
│ │ - /commands/log │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
│
│ HTTP POST
│
┌────────────────▼────────────────────────┐
│ PBX API (Next.js) │
│ /api/httpapihandler │
└─────────────────────────────────────────┘
- esl-lite (^3.1.1) - FreeSWITCH ESL library
- express (^4.21.2) - HTTP server
- pino (^9.6.0) - Structured logging
- pino-pretty (^13.0.0) - Log formatting (dev)
# Install dependencies
npm install
# Run in development mode (auto-reload)
npm run dev
# Build TypeScript
npm run build
# Run production build
npm start
# View formatted logs
npm run dev | npx pino-pretty# Build and run
npm run build
NODE_ENV=production npm startdocker build -t vgtpbx-eslserver:latest .
docker run -d \
--name vgtpbx-eslserver \
--network host \
-e NODE_ENV=production \
-e FREESWITCH_ESL_PASSWORD=YourSecurePassword \
vgtpbx-eslserver:latestSee vgtpbx-switch deployment guide.
Structured JSON logs via Pino:
# View logs
docker logs vgtpbx-eslserver -f
# Pretty print
docker logs vgtpbx-eslserver -f | npx pino-pretty
# Filter by level (error and above)
docker logs vgtpbx-eslserver | jq 'select(.level >= 50)'
# Filter by event
docker logs vgtpbx-eslserver | jq 'select(.eventName == "CHANNEL_ANSWER")'# Check FreeSWITCH is running
docker ps | grep freeswitch
# Check ESL port
netstat -tlnp | grep 8021
telnet 127.0.0.1 8021
# Check password matches
echo $FREESWITCH_ESL_PASSWORD# Check logs
docker logs vgtpbx-eslserver | grep "Failed to notify"
# Test PBX endpoint
curl -X POST $NEXTJS_INTERNAL_API_URL \
-H "Content-Type: application/json" \
-d '{"eventName":"TEST","eventData":{}}'# Check event subscriptions
# Too many events can cause high CPU
# Disable unnecessary events in src/index.ts- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - See LICENSE file for details.
- vgtpbx-switch - FreeSWITCH Docker deployment
For issues, questions, or contributions, please open an issue on GitHub.