# Deployment ## Quick Deploy ```bash 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 ```ini # 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 blocked - `ProtectSystem=strict` — system directories read-only - `ProtectHome=yes` — home directory isolated - `PrivateTmp=true` — isolated /tmp - JWT secret and API-key auto-generated on first run ## Production Deployment (8 Steps) ### Step 1 — Deploy to Server ```bash make deploy scp -r /opt/pulse-lets-go admin@balancer.lan:/opt/ scp contrib/route.lua admin@balancer.lan:/tmp/ ``` ### Step 2 — NATS Server (if not installed) ```bash ssh admin@balancer.lan 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: ```bash # Copy binary and config to each PBX: scp bin/pulse-lets-go-agent admin@PBX_IP:/usr/local/bin/ scp contrib/agent-uc.json admin@PBX_IP:/etc/pulse-lets-go-agent/agent.json # Start: ssh admin@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 ```bash 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: ```xml ``` ```bash 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: ```bash curl -X POST .../api/trunks \ -d '{"name":"uc06","type":"balance","node_id":"uc06","gateway":"sip:uc-pbx.lan:5060","enabled":true}' ``` ### Step 7 — Start pulse-lets-go ```bash # 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 ```bash 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 ```bash # 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) |