Quickstart: Binary
This chapter takes you from the vexyl-gateway bundle to a running gateway that answers a test call. It assumes you run the gateway yourself on a Linux server. For Docker, see the next chapter instead.
Before you start
You need:
- A Linux server (Ubuntu 20.04+ or Debian 11+), x86-64, on a small VM (more memory for higher call counts).
- The Vexyl bundle, which contains three items:
| Item | What it is |
|---|---|
vexyl-gateway |
The gateway binary |
node_modules/ |
Native speech modules. It must sit beside the binary |
sounds/ |
Prompt and filler audio |
- API keys for the providers you will use (speech recognition, speech synthesis, language model).
- Optionally, a licence key from Vexyl. Without one the gateway runs on the Free tier (see Licence).
- Node.js and pm2 if you use pm2 to run it. The binary itself does not need Node.js installed.
Ports the gateway uses:
| Port | Used for | Variable |
|---|---|---|
| 8080 | Asterisk connection (AudioSocket) | AUDIOSOCKET_PORT |
| 8081 | HTTP API and health check | HTTP_PORT |
| 8082 | Browser widget (WebSocket audio), only when enabled | WEBSOCKET_AUDIO_PORT |
| 5080 (UDP) | SIP bridge, only when enabled (unset default 5060; this manual sets SIP_PORT=5080, see chapter 05) |
SIP_PORT |
Set HTTP_PORT yourself. HTTP_PORT and AUDIOSOCKET_PORT both fall back to 8080 when unset, and the two servers cannot share a port. This manual uses HTTP_PORT=8081 everywhere.
Install
Pick a directory and copy the bundle into it. The binary must run with that directory as its working directory, because it finds node_modules/, sounds/ and .env relative to it.
sudo mkdir -p /opt/vexyl-gateway
cd /opt/vexyl-gateway
# copy vexyl-gateway, node_modules/ and sounds/ into this directory
sudo chmod +x vexyl-gateway
sudo mkdir -p config cache cdr logs
The layout should now look like this:
/opt/vexyl-gateway/
vexyl-gateway binary
node_modules/ native speech modules
sounds/
.env you create this below
config/ cache/ cdr/ logs/
Create a service user, hand it the directory, and keep .env readable by that user only, because it holds your API keys:
sudo useradd -r -s /usr/sbin/nologin vexyl
sudo touch .env
sudo chmod 600 .env
sudo chown -R vexyl:vexyl /opt/vexyl-gateway
Licence
With no LICENSE_KEY, the gateway runs on the Free tier: 4 concurrent calls, and it never expires. This is enough to test everything in this chapter.
A paid licence raises the call cap. A key is bound to one machine, so you first ask the binary for this machine's id:
cd /opt/vexyl-gateway
sudo ./vexyl-gateway --get-machine-id
This works before any .env exists. Send the printed id to Vexyl. You get a key back; put it in .env as LICENSE_KEY= (see the next section). If you later change the server's hardware or host identity, the key stops matching and you need a new one.
Minimal .env
Create .env in the install directory. This example uses Sarvam for listening and speaking and a LiteBot bot as the AI brain. Replace the placeholder values.
HTTP_PORT=8081
AUDIOSOCKET_PORT=8080
TELEPHONY_MODE=audiosocket
LLM_PROVIDER=litebot
LITEBOT_API_URL=http://<litebot-host>:3345
LITEBOT_BOT_ID=default
STT_PROVIDER=sarvam
TTS_PROVIDER=sarvam
SARVAM_API_KEY=your-sarvam-key
LICENSE_KEY=
Leave LICENSE_KEY= empty to stay on the Free tier. TELEPHONY_MODE takes audiosocket (the default), sip_bridge or both; the last two turn on the built-in SIP bridge.
See Configuration recipes for full provider recipes: other speech and language providers, languages, voices and the matching API keys.
When you add lines later, append them with a leading and trailing newline so the new line does not merge into the last one:
printf '\nHTTP_ALLOWED_IPS=127.0.0.1,::1\n' | sudo tee -a .env
Restart the gateway after every .env edit.
Run
Option 1: pm2
cd /opt/vexyl-gateway
sudo pm2 start ./vexyl-gateway --name vexyl-gateway --cwd /opt/vexyl-gateway
sudo pm2 save
sudo pm2 startup
The pm2 example runs the gateway as the user who starts pm2 (root, with sudo). pm2 startup prints one command. Run it to make pm2 (and the gateway) start at boot. If pm2 tries to run the binary through Node.js, start it again with --interpreter none.
Option 2: systemd
Create /etc/systemd/system/vexyl-gateway.service:
[Unit]
Description=Vexyl AI Voice Gateway
After=network-online.target
[Service]
User=vexyl
WorkingDirectory=/opt/vexyl-gateway
ExecStart=/opt/vexyl-gateway/vexyl-gateway
Restart=always
RestartSec=3
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Then enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now vexyl-gateway
Check it is up
curl -s 127.0.0.1:8081/health
The reply is JSON. Look at these fields:
| Field | What to expect |
|---|---|
status |
ok. degraded means a component is unhealthy; read the logs |
concurrentCalls |
active is the calls in progress now. max is your licence cap: 4 on the Free tier |
storage |
Where sessions are kept (memory, or Redis if you configured it) |
telephonyMode |
Matches your TELEPHONY_MODE |
concurrentCalls.max is how you confirm which licence the gateway is using. A sipBridge block also appears when the SIP bridge is on.
A punycode deprecation warning in the logs at boot is normal. Ignore it.
If the check fails, read the logs: sudo pm2 logs vexyl-gateway, or sudo journalctl -u vexyl-gateway -e under systemd.
First call
Choose one path.
Asterisk (AudioSocket). Add this to your dialplan. It answers the call and streams the audio to the gateway on the AudioSocket port:
exten => _X.,1,Answer()
exten => _X.,n,Set(SESSION_UUID=${TRIM(${SHELL(uuidgen)})})
exten => _X.,n,AudioSocket(${SESSION_UUID},127.0.0.1:8080)
exten => _X.,n,Hangup()
AudioSocket() needs a real UUID as its first argument, so the dialplan generates one with uuidgen (package uuid-runtime on Debian/Ubuntu; needs Asterisk's func_shell module). Asterisk's own ${UNIQUEID} is not a UUID and is rejected.
Reload the dialplan, call the number and talk to the bot. Before the AudioSocket line you can optionally POST to /session/${SESSION_UUID}/metadata on the HTTP port with values such as caller_id or botId (see HTTP API). For the full Asterisk setup, see Asterisk over AudioSocket.
SIP trunk, no PBX. Set TELEPHONY_MODE=sip_bridge (or both) and point your carrier at port 5080. Follow SIP trunk.
While the call runs, curl -s 127.0.0.1:8081/health shows concurrentCalls.active as 1.
Upgrading
Copy the new binary beside the old one under a different name and note its checksum:
cd /opt/vexyl-gateway md5sum vexyl-gateway.new md5sum vexyl-gatewayWait until
concurrentCalls.activein/healthis 0, so no caller is cut off.Keep the old binary as a backup, named after its checksum, then swap and restart:
sudo mv vexyl-gateway vexyl-gateway.bak-<old-md5> sudo mv vexyl-gateway.new vexyl-gateway sudo chmod 755 vexyl-gateway sudo pm2 restart vexyl-gatewayUnder systemd, use
sudo systemctl restart vexyl-gatewayinstead of the pm2 command. If the bundle also ships a newnode_modules/orsounds/, replace those at the same time.Check
/healthagain:statusisokandconcurrentCalls.maxstill shows your licence cap.
To roll back, move the backup over the binary and restart:
sudo mv vexyl-gateway.bak-<old-md5> vexyl-gateway
sudo pm2 restart vexyl-gateway
Next: Configuration recipes.