npm · signalbird-cli ↗
Installsudo npm i -g signalbird-cli && sudo signalbird agent install --token=sba_live_…

Server Agent - install and usage guide

This document covers the Signalbird agent you install on your server. The agent is the agent role of the signalbird-cli npm package: it reads your server's state and sends it to Signalbird. It changes nothing on your server.

You can follow this even if you have never managed a server. Every step says what to type, what you should see, and what to do when something goes wrong. Five minutes, start to finish.

Source code: https://github.com/Pariette-Inc/signalbird.cli (MIT)

Running the old bash agent? The bash and PowerShell agent scripts are retired. Just run the install below on the same server: the new agent takes over and keeps your config file (token, allowed paths, database lines).


1. What is this for? (30 seconds)

You can tell whether your site is up by looking at it from the outside. What you cannot see from the outside:

  • The disk is 97% full and will fill up tomorrow.
  • Database connections have hit the ceiling; the next traffic spike stops the site.
  • MySQL is down and the app is coasting on cache.
  • Your nightly backup has not run for three days and nobody knows.

The agent sees these from inside the server and brings them to the panel. There is also the "expected signal": your backup script says "done" every hour, and if it does not, the alarm fires.


2. Glossary

Term Meaning
Agent The program you install (signalbird agent). Runs in the background, always.
signalbird-cli The npm package that carries the agent. Installing it gives you the signalbird command.
Node.js The runtime the agent runs on. Version 20 or newer.
Terminal / SSH The text window where you type commands on the server.
root / sudo Administrator rights on the server. Needed to install.
Token The long secret starting with sba_live_…. The agent's identity.
Metric Numeric state: CPU, memory, disk and so on.
Radio Signalbird's log module. Log lines the agent ships land there.
Expected signal A "this job finished" ping. If it does not arrive, Signalbird raises an alarm.
Service (systemd) A program that starts automatically with the server. The agent runs this way.

3. Before you start

  1. A Linux server running systemd: Ubuntu, Debian, Rocky, AlmaLinux… (Windows Server is not supported yet, see §5.)
  2. A way in. SSH.
  3. Administrator rights. sudo (or root itself).
  4. Node.js 20 or newer. How to check is below.
  5. The Server Monitoring module on your Signalbird account. Without it the Servers screen shows a lock and offers to add the module.
  6. Outbound internet. Port 443 outbound is enough. You never open an inbound port.

Check Node.js:

bash
node --version

If it prints v20.… or higher you are ready. If it says "command not found" or the version is below 20, install the NodeSource package on Ubuntu/Debian. Download the setup script first, read it, then run it:

bash
curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
less nodesource_setup.sh
sudo bash nodesource_setup.sh && sudo apt-get install -y nodejs

(Press q to leave less.) On Rocky / AlmaLinux and similar, use the distribution's own Node.js 20 package or the instructions at https://nodejs.org.


4. Install - Ubuntu / Debian / Linux

Step 1 · Create the server record

  1. Open Servers in the panel menu.
  2. Click Add server.
  3. Give it a name you will recognise: web-01, database, orders-api.
  4. Enter the allowed log roots: the folders the agent may read. If unsure, keep the default /var/log (see "Optional" below).
  5. Click Create.

You get the token (starting with sba_live_…), and the panel then opens the server's install page (/servers/<id>/install) with the commands to copy and a live "waiting for first message" panel that turns green the moment the agent first checks in.

The token is shown once. Copy it before closing the dialog. If you lose it, open the server record and click Rotate key (the old one dies instantly).

Step 2 · Connect to the server

bash
ssh user@your-server

Step 3 · Install the package and the agent

Paste the commands from the install page as they are:

bash
sudo npm install -g signalbird-cli
signalbird --version
sudo signalbird agent install --token=sba_live_YOUR_TOKEN_HERE

The first line installs the package permanently, the second proves the signalbird command is there (it prints a version number), the third installs the agent.

Do not use npx. Something like npx signalbird-cli agent install runs the package from a temporary cache folder; when that folder is cleaned up, the service breaks. The agent detects this and refuses to install. Run sudo npm install -g signalbird-cli first.

install does the following, in order:

  1. Checks the token with Signalbird first. If it is rejected, nothing is written and the install stops.
  2. Writes the config file /etc/signalbird/agent.conf, readable by root only (0600).
  3. Installs and starts the systemd service signalbird-agent.
  4. If the old bash agent is installed, replaces it; the existing agent.conf is kept and only the token and API address are updated.

You are done when you see:

text
✓ Signalbird anahtarı kabul etti.

Kurulum tamam.

  Ayar dosyası : /etc/signalbird/agent.conf
  Servis       : systemctl status signalbird-agent
  Günlük       : /var/log/signalbird-agent.log  ·  journalctl -u signalbird-agent
  Sinyal örneği: signalbird agent signal db-backup ok "yedek bitti"

(The agent's messages are in Turkish: "key accepted", "install complete", config file, service, log, signal example.)

Step 4 · Verify

bash
sudo signalbird agent status

The agent prints its config and service state, then tries to connect:

text
Signalbird ajanı 1.1.0 (signalbird-cli …, protokol 1)
  API        : https://live.signalbird.io/api
  Anahtar    : sba_live_xxxxxxx…
  İzinli yol : /var/log
  Veritabanı : yerel ayarda yok
  Ayar sürümü: …
  Servis     : active

Bağlantı deneniyor...
Bağlantı tamam.

The last line should read "Bağlantı tamam." (connection OK). Then check the service:

bash
systemctl status signalbird-agent

It should be active (running). The "waiting for first message" panel on the install page turns green; on Servers the machine shows as online and fills with CPU, memory and disk within a minute.

Optional · widen the readable log roots

By default the agent may only read files under /var/log. If your application logs elsewhere, say so at install time:

bash
sudo signalbird agent install \
  --token=sba_live_xxx \
  --allow=/var/log,/srv/myapp/storage/logs

This list lives on the server. A path chosen in the panel that is not under it is never read - even a stolen Signalbird account cannot open a new file on your machine.

Only pass --api=https://…/api if you connect to your own Signalbird installation or a test address; otherwise leave it out.


5. Windows Server

There is no agent for Windows Server yet. The old PowerShell script is retired and its replacement has not shipped. When Windows support arrives it will show up as an option on the Add server screen and this guide will be updated.

Until then you can still use expected signals for jobs on a Windows machine with a single HTTP call, no agent needed (see §11, "Without the agent").


6. What you see in the panel

Each server is a card: online state, CPU, memory, disk, last seen. Open it for the detail view:

Section Contents
Top tiles CPU, memory, uptime, database health
Disks Usage bar and inode ratio per disk
Services The services you asked about, green or red
Socket.io Connected clients, rooms, events per second
Processes Top N processes by CPU
Metric settings What gets measured
Watched logs Which file flows into Radio
Expected signals Schedule and state of jobs like backups

There is no "run command" box, and there never will be. What travels from the panel is configuration, not commands. This is a design decision: if the panel could run commands, your Signalbird password would effectively be your server password.


7. Metric settings

Setting What it does Suggested
Interval Seconds between metric reports 60. Lower values load the server; the floor is 30.
Process count How many top-CPU processes to list 5. Use 0 to disable.
Disks Disk and inode usage Keep it on. A full disk is a classic silent outage.
Listening ports Which ports are listening Optional; answers "since when has this port been closed".
Services Service names, comma separated nginx, mysql, redis. Find names with systemctl list-units --type=service.
Database Connections, response time, size Requires local credentials (see §9).
Socket.io Clients and rooms Point it at your own /metrics endpoint (see §10).

The agent picks up a saved change within 5 minutes. To apply it now: sudo systemctl restart signalbird-agent.


8. Watching logs

The agent reads log files where they are. It never moves or deletes them and ships only new lines, remembering where it left off.

In the server detail view: Watched logs → Add log.

Field What to write Example
Path Full path /var/log/nginx/error.log
Channel Radio channel it lands in server
Filter Regular expression; only matching lines ship \[error\]|\[crit\]

Common filters: nginx \[error\]\|\[crit\]\|\[alert\] · Laravel ERROR\|CRITICAL\|EMERGENCY · PHP-FPM child exited\|segfault · MySQL \[ERROR\]. Leave it empty to ship everything.

Three rules worth knowing:

  1. History is not shipped on first install. The agent jumps to the end of the file and listens from there - otherwise a year of nginx logs would burn your Radio quota in the first minute.
  2. The path must be allowed. Anything outside allow_paths is skipped and noted in the agent's own log. Escaping the list through a symlink is blocked too.
  3. Logs consume the Radio quota. The agent is only the courier; retention and notification rules live in Radio.

9. Database monitoring

Credentials live only in the local config file. They are not shown in the panel, cannot be set from it, and are never transmitted. Supported databases: MySQL, MariaDB and PostgreSQL.

Create a read-only user:

sql
-- MySQL / MariaDB
CREATE USER 'signalbird_ro'@'localhost' IDENTIFIED BY 'a-strong-password';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'signalbird_ro'@'localhost';
GRANT SELECT ON information_schema.* TO 'signalbird_ro'@'localhost';

-- PostgreSQL
CREATE USER signalbird_ro WITH PASSWORD 'a-strong-password';
GRANT pg_monitor TO signalbird_ro;

The agent queries through the server's mysql or psql client; install it if missing (mysql-client on Ubuntu, default-mysql-client on Debian, postgresql-client for PostgreSQL).

Then edit the config with sudo nano /etc/signalbird/agent.conf. It already contains commented-out db_* lines; remove the leading # and fill them in:

ini
db_driver=mysql          # mysql | mariadb | pgsql
db_host=127.0.0.1
db_port=3306
db_user=signalbird_ro
db_pass=a-strong-password
db_name=my_app

Restart the service (sudo systemctl restart signalbird-agent) and switch Database on in the panel.

The password never appears on a command line: the agent passes it only to that one call's environment as MYSQL_PWD / PGPASSWORD, otherwise anyone running ps on the box would see it.


10. Socket.io monitoring

The agent only calls localhost addresses (http://127.0.0.1:…, http://localhost:…, http://[::1]:…) and never follows redirects. That is deliberate: if the panel could name any address, the agent would become a tool for scanning the customer's internal network.

js
// Node.js + socket.io
const http = require('http')

http.createServer((req, res) => {
  if (req.url !== '/metrics') { res.writeHead(404); return res.end() }

  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.end(JSON.stringify({
    clients: io.engine.clientsCount,
    rooms: io.sockets.adapter.rooms.size,
    events_per_second: eventsPerSecond,
  }))
}).listen(3001, '127.0.0.1')     // localhost ONLY

Enable Socket.io in the panel and enter http://127.0.0.1:3001/metrics.


11. Expected signals - the "backup did not run" alarm

The logic is inverted: the absence of something raises the alarm.

The scenario

Your database backup runs hourly. One day cron breaks and it stops running. There is no error message - because a job that does not run produces no errors. You find out when the disk dies and your latest backup is three weeks old.

Setting it up

1. Create the check. Watchers → New → type Expected signal.

2. Say when. In "Expected signal timing":

Option When it is expected
Sliding window Counts from the last signal (legacy behaviour)
Every hour 00:00, 01:00, 02:00 …
Every 15 / 30 minutes :00, :15, :30, :45
Every 6 hours 00:00, 06:00, 12:00, 18:00
Daily at a given time e.g. every day at 03:30
Custom (cron) e.g. 0 4 * * 1 (Mondays at 04:00)

Tolerance is how long you wait: "every hour + 5 minutes" means the alarm fires if nothing arrives by 14:05. If the machine runs the agent, also pick the server and a signal key such as db-backup.

3. Add one line to your script.

bash
#!/bin/bash
if mysqldump --all-databases | gzip > /var/backups/db.sql.gz; then
    signalbird agent signal db-backup ok "$(du -h /var/backups/db.sql.gz | cut -f1)"
else
    signalbird agent signal db-backup fail "mysqldump failed"
fi

Run the script as root. signalbird agent signal reads the token from /etc/signalbird/agent.conf, which only root can read. Put the script in root's crontab (sudo crontab -e) and prefix manual tests with sudo. Run as another user, it fails with "izin yok, sudo ile çalıştırın" (permission denied, run with sudo).

Without the agent (or for a script that cannot run as root), the check gives you a URL that needs no login:

bash
curl -fsS "https://live.signalbird.io/api/heartbeat/YOUR_TOKEN"
curl -fsS "https://live.signalbird.io/api/heartbeat/YOUR_TOKEN?status=fail&message=mysqldump+failed"

Three rules

  1. The schedule is anchored to midnight, not to your install time. A check created at 14:26 with "every hour" expects XX:00, not XX:26.
  2. An early signal does not count. A signal at 13:58 does not satisfy the 14:00 slot. Without this rule, a job that ran 59 minutes early would mask a real miss forever.
  3. fail does not wait. If the job ran and failed, the alarm fires immediately. Silence only catches "the server is gone".

Without touching the script: file mode

If you cannot edit the backup script, give the check a file path (/var/backups/db.sql.gz). The agent looks at the file's modification time: if it is fresh it sends the signal itself; if it is stale it sends nothing and the alarm fires as usual. If the file does not exist at all, it sends fail.


12. Command reference

Every command is signalbird agent <command>. Most need sudo because the config file is readable by root only.

Command What it does
sudo signalbird agent install --token=… [--allow=…] [--api=…] Checks the token with Signalbird, then writes the config, installs and starts the service. Safe to re-run: your config is kept, only the token and API address (and allowed paths, if given) are refreshed. Replaces the old bash agent. Refuses to install from an npx cache.
sudo signalbird agent status Shows the config and service state, tries the connection, ends with "Bağlantı tamam." The first thing to check.
sudo signalbird agent once Runs one cycle: fetch config, ship logs and file signals, send metrics. Good for testing.
sudo signalbird agent signal <key> [ok|fail] [message] Sends an expected signal. Status defaults to ok.
signalbird agent run Runs forever. The service uses this; you never call it by hand.
sudo signalbird agent uninstall Removes the service. /etc/signalbird/agent.conf and /var/lib/signalbird stay, so a reinstall keeps your config and log positions.
signalbird agent version Agent version (e.g. 1.1.0). Separate from the package version, which signalbird --version prints.
bash
sudo signalbird agent signal db-backup ok "2.4 GB, 51 s"
sudo signalbird agent signal nightly-report fail "report failed"
sudo signalbird agent once

Service logs:

bash
systemctl status signalbird-agent
journalctl -u signalbird-agent -f
sudo tail -f /var/log/signalbird-agent.log

Removing it completely

bash
sudo signalbird agent uninstall && sudo npm uninstall -g signalbird-cli && sudo rm -rf /etc/signalbird /var/lib/signalbird

This removes the service, the package, the config file and the log positions. Delete the server record in the panel too (see §19).

Same package, another role: signalbird fix

On developer machines the signalbird-cli package is also used as the code fixer (signalbird fix). That role refuses to run as root and is not needed on servers: servers only use signalbird agent.


13. Config file reference

Path: /etc/signalbird/agent.conf

ini
token=sba_live_xxxxxxxxxxxxxxxxxxxx
api_base=https://live.signalbird.io/api
allow_paths=/var/log,/srv/app/storage/logs

db_driver=mysql
db_host=127.0.0.1
db_port=3306
db_user=signalbird_ro
db_pass=a-strong-password
db_name=my_app

Plain key=value lines; the file is never executed, only read line by line. Readable by root only (0600). Restart the service after changes (sudo systemctl restart signalbird-agent). State (log read positions) lives in /var/lib/signalbird/state, the last known panel config in /var/lib/signalbird/config.json; the agent's own log is /var/log/signalbird-agent.log (tokens are masked).


14. Using it with the SDK

The agent is a program, not a library: it is not, and should not be, an SDK package. Everything around it, however, is available:

Need How
Ship your application's own errors and events Radio SDK (signalbird package, 12 languages). Agent-shipped server logs land in the same place.
Read or report on those logs Management surface (radio:read scope): management.radioEvents({...})
Send an expected signal from code No agent needed, one HTTP call: /api/heartbeat/<token>
List or manage server records Panel endpoints (/v1/panel/agents) with a Sanctum session. No SDK method yet.
ts
import { Signalbird } from 'signalbird'

const log = new Signalbird({ domainKey: process.env.SB_RADIO_KEY })

await log.error('Backup script failed', {
  channel: 'server',
  meta: { host: 'web-01', exit_code: 2 },
})

Writing your own agent? The protocol is public: AGENT-PROTOCOL.md.


15. The endpoints the agent speaks

All one-way: the agent brings, Signalbird accepts.

text
Authorization: Bearer sba_live_…
Content-Type: application/json
Accept: application/json
Endpoint Purpose
POST /v1/agent/hello Identify; receive configuration and version status.
GET /v1/agent/config Configuration only.
POST /v1/agent/metrics Send metrics.
POST /v1/agent/logs Send log lines (max 100 per request).
POST /v1/agent/signal Send an expected signal (ok / fail).
bash
curl -X POST https://live.signalbird.io/api/v1/agent/signal \
  -H "Authorization: Bearer sba_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"key":"db-backup","status":"ok","message":"2.4 GB"}'

Field limits: message 4000, source 120 characters. Do not omit Accept - without it a validation error comes back as a redirect instead of JSON.


16. Security - what it can and cannot do

The agent cannot: start or stop services (other than its own, during install and uninstall); delete, modify or create files (beyond its own state folder and log); install packages or change system settings; receive commands from Signalbird (no such endpoint exists); update itself; read files outside the allowed roots; call any address other than the Signalbird API and localhost.

It only ever runs a fixed list of programs: df, systemctl, ss, ps, mysql, psql. The list is hard-coded; calling anything else is an error. Commands run without a shell, so nothing from the panel is ever interpreted by one. The full list with exact arguments: AGENT-COMMANDS.md. Reading config and logs and talking to Signalbird is done by Node.js itself; no curl, python3 or jq needed.

Sent to Signalbird: metric numbers, service names and states, matching lines from the log files you chose, signals. Never sent: your database password, your config file, the contents of files you did not choose.

If the token leaks, the worst anyone can do is send fake metrics and fake logs; it grants no access to any other team data. Rotate the key in the panel and re-run sudo signalbird agent install --token=… with the new one.

If the token is rejected (401) the agent stops and systemd does not restart it, so it never loops on 401s. If the module is disabled (403 MODULE_DISABLED) it waits and resumes on its own once the module is back.

What privileges does it run with? Install and the service need root (for the service unit, the 0600 config file and reading /var/log). The systemd unit runs with ProtectSystem=strict: the only writable places are its state folder (/var/lib/signalbird) and its own log under /var/log.


17. Versions and updates

The agent never updates itself. When a new agent version ships, the server row gets an "update available" badge and you get one notification per version (security releases also push to your phone). The agent also writes a "new agent version available" line to its own log.

To update:

bash
sudo npm install -g signalbird-cli@latest && sudo systemctl restart signalbird-agent

Your config and log positions are preserved.

The agent version is reported separately from the package version: the panel shows what signalbird agent version prints (currently 1.1.0), while signalbird --version prints the package version.


18. Troubleshooting

Symptom Cause and fix
Server shows offline systemctl status signalbird-agent; start it with sudo systemctl start signalbird-agent if stopped.
signalbird: command not found The package is not installed: sudo npm install -g signalbird-cli.
"Node 20+ gerekli" (Node 20+ required) Node.js is too old. Upgrade with the NodeSource steps in §3.
"Kurulum root gerektirir" (install needs root) Prefix the command with sudo.
"npx ile servis kurulmaz" (no service from npx) Run sudo npm install -g signalbird-cli first, then sudo signalbird agent install ….
"Ayar dosyası okunamadı … izin yok" (cannot read config) The config is root-only. Use sudo; for scripts, move them to root's crontab.
status / install says the key was rejected Token wrong or rotated. Take a new one and re-run sudo signalbird agent install --token=….
Install says "Bağlantı doğrulanamadı; kurulum yine de yapılıyor" The server could not reach Signalbird at that moment (outbound 443, DNS, proxy). The install completes and the service keeps retrying. Fix the network and check with sudo signalbird agent status.
MODULE_DISABLED The Server Monitoring module is missing or your subscription lapsed. Add it in the panel; the agent resumes on its own.
Metrics arrive, logs do not Is the path under allow_paths? Does the filter match? Check /var/log/signalbird-agent.log.
"log yolu izinli değil" warning Widen allow_paths and restart the service.
Database ok:false Check db_* lines, user privileges, and that the mysql/psql client exists.
Socket metrics missing Does the URL start with 127.0.0.1? Does the endpoint return JSON? Try curl http://127.0.0.1:3001/metrics.
I sent a signal but the alarm fired It probably arrived outside the window (see §11, rule 2). The check log shows "arrived outside the window".
"… anahtarıyla bir izleme yok" (no check with that key) The signal key in the panel and in your command differ.

When in doubt, send support these two outputs:

bash
sudo signalbird agent status
sudo tail -50 /var/log/signalbird-agent.log

19. FAQ

Does the agent slow my server down? No. It reads a few files and makes one HTTP request per minute. The only wait is one second for the CPU sample.

What happens if the network drops? It skips the metric, does not advance the log position and retries next cycle. Missed lines ship once connectivity returns.

Can I install two agents on one machine? You should not. One server, one record, one token.

I had the old bash agent. What do I do? Nothing to delete: run the install in §4. The service name and files are the same; the new agent takes over and inherits your config file and log positions. The old /usr/local/bin/signalbird-agent file is no longer used and can be removed.

I deleted my server. Now what? Delete the record in the panel. Expected signals bound to it are deactivated, so no alarm fires for a machine that is gone.

Can I see metric history as a chart? Today the panel shows the current state. History charts are on the roadmap; logs and alarm history are already stored.

Does it monitor Docker containers? Container processes and resource use are included in the server metrics. Per-container metrics are not there yet.

Can I install it on Windows Server? Not yet (see §5). Support will show up in the panel when it lands.

How is it billed? Per server, monthly. Metric volume is never billed. Logs consume the Radio module quota.