- Create docs/ with 7 focused files: architecture, api, scoring, agent, deployment, freeswitch, development - Rewrite README.md as concise overview with links to docs/ - Remove AGENTS.md (content merged into docs/ and README)
4.3 KiB
4.3 KiB
Deployment
Quick Deploy
make deploy # full deploy to /opt/pulse-lets-go
make install-systemd # install systemd unit
Directory Structure (after deploy)
/opt/pulse-lets-go/
├── bin/pulse-lets-go # Binary
├── data/
│ ├── config.json # Configuration
│ ├── trunks.json # Trunks
│ └── users.json # Users
├── web/ # SvelteKit static files
└── log/
└── metrics.YYYY-MM-DD.log # ASCII metrics log
systemd Unit
# deploy/pulse-lets-go.service
[Unit]
Description=Pulse Lets Go — Telephone Load Balancer
After=network.target
[Service]
User=pulse
Group=pulse
ExecStart=/opt/pulse-lets-go/bin/pulse-lets-go
WorkingDirectory=/opt/pulse-lets-go
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/pulse-lets-go/data /opt/pulse-lets-go/log
[Install]
WantedBy=multi-user.target
Security
NoNewPrivileges=true— privilege escalation blockedProtectSystem=strict— system directories read-onlyProtectHome=yes— home directory isolatedPrivateTmp=true— isolated /tmp- JWT secret and API-key auto-generated on first run
Production Deployment (8 Steps)
Step 1 — Deploy to Server
make deploy
scp -r /opt/pulse-lets-go devadmin@10.101.60.81:/opt/
scp contrib/route.lua devadmin@10.101.60.81:/tmp/
Step 2 — NATS Server (if not installed)
ssh devadmin@10.101.60.81
sudo mkdir -p /opt/nats
# Install nats-server from repository or copy binary
# Run: nats-server -p 4222 -D &
Step 3 — Deploy Agent on PBX Nodes
Repeat for each UC/Asterisk node:
# Copy binary and config to each PBX:
scp bin/pulse-lets-go-agent devadmin@PBX_IP:/usr/local/bin/
scp contrib/agent-uc.json devadmin@PBX_IP:/etc/pulse-lets-go-agent/agent.json
# Start:
ssh devadmin@PBX_IP "systemctl start pulse-lets-go-agent"
# Check log:
# journalctl -u pulse-lets-go-agent -f
# → [ami] connected to 127.0.0.1:6154
# → [agent] published metric: calls=0/150 load=0.28 cpu=99% status=ok
Step 4 — route.lua in FS Scripts
sudo mkdir -p /etc/freeswitch/scripts
sudo cp /tmp/route.lua /etc/freeswitch/scripts/
Step 5 — Dialplan
Add pulse_route extension in /etc/freeswitch/dialplan/default.xml before other extensions:
<extension name="pulse_route">
<condition field="destination_number" expression="^(.*)$">
<action application="set" data="balancer_url=http://127.0.0.1:8080"/>
<action application="lua" data="route.lua"/>
</condition>
</extension>
sudo fs_cli -x "reloadxml"
Step 6 — Create Balance Trunks
Trunks are created automatically when an agent sends its first metric with sip_gateway. Manual creation:
curl -X POST .../api/trunks \
-d '{"name":"uc06","type":"balance","node_id":"uc06","gateway":"sip:10.101.60.115:5060","enabled":true}'
Step 7 — Start pulse-lets-go
# config.json auto-creates on first run in /opt/pulse-lets-go/data/
# Add esl block to config.json:
# "esl": {"host": "127.0.0.1", "port": 8021, "password": "ClueCon"}
/opt/pulse-lets-go/bin/pulse-lets-go
Step 8 — Verify
curl http://127.0.0.1:8080/api/health | jq '.connections'
# → {"nats":"connected","esl":"connected"}
curl 'http://127.0.0.1:8080/api/route?caller_id=123&dest=456'
# → {"node_id":"pbx-03","score":88,"sip_gateway":...}
Rollback
# 1. Remove pulse_route from dialplan
sudo sed -i '/pulse_route/,/<\/extension>/d' /etc/freeswitch/dialplan/default.xml
sudo fs_cli -x "reloadxml"
# 2. Stop pulse-lets-go
sudo systemctl stop pulse-lets-go
# Calls continue through original dialplan without balancer.
Access Permissions (production)
| Operation | Required Permissions |
|---|---|
| Read FS configs | root or freeswitch |
fs_cli -x commands |
root or freeswitch |
| ESL (port 8021) | ACL in event_socket.conf.xml |
| Install software | root |
Write to /etc/freeswitch/scripts/ |
root |
reloadxml |
root or freeswitch |
Tested Versions
| Component | Version |
|---|---|
| FreeSWITCH | 1.10.12+ |
| NATS Server | 2.10+ |
| Go | 1.26 |
| OS | Linux (CentOS 7+, AlmaLinux, Arch) |