#Install it, and check that it runs
The Linux Server Edition installs from an apt repository. You register the repository's signing key, then install roamswitch-server. Both amd64 and arm64 are available.
These commands install a package and start a service (they change the machine). Try them in a practice environment.
curl -fsSL https://lafine.net/apt/roamswitch-archive-keyring.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/roamswitch-archive-keyring.gpg
echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/roamswitch-archive-keyring.gpg] https://lafine.net/apt stable main" \
| sudo tee /etc/apt/sources.list.d/roamswitch.list
sudo apt update && sudo apt install roamswitch-server
systemctl is-active roamswitch-serverRoamSwitch Server Edition is installed and running with its defaults.
Next: sudo roamswitch server setup
Check the result: roamswitch status --server ; roamswitch doctor ; roamswitch detection-coverage
Full-coverage terminal UI: sudo roamswitch-server-tui
activeOn a first install, apt install finished in about 15 seconds. The end of the apt output says the service runs with its defaults, and names the next step, sudo roamswitch server setup. When apt is done, systemctl is-active already says active.
Also look at how systemd watches the daemon.
systemctl show roamswitch-server -p Type -p WatchdogUSecType=notify
WatchdogUSec=30sType=notify means the daemon itself tells systemd when it is ready. WatchdogUSec=30s means systemd restarts the daemon when it stops responding for 30 seconds.
active means the daemon is running. The settings file is /etc/roamswitch/server.conf.
#Read doctor: can this machine run it
Start with RoamSwitch self-check (doctor). It checks that the commands RoamSwitch needs are present, that the daemon is running, and that there is somewhere to send alerts. It changes nothing.
sudo roamswitch doctor[ok] The RoamSwitch daemon is running
[warn] fail2ban is also running and changes firewall rules. Its rules can overlap with RoamSwitch's
[ok] Signed data updates are working. Last success: 2026-11-12 01:27 UTC
[warn] The egress block list is empty. Nothing is blocked.
[warn] Web rules: no document root was found, so web shells are not watched at all. Name the roots in scan_dirs of /etc/roamswitch/web_rules.conf.
[warn] No alert channel is set up. Alerts are only written to the notification history and reach no one. Run sudo roamswitch server setup.
Nothing failed (4 warnings)Read the output like this.
- ok: the condition is met
- warn: it runs, but something may need action. The four warnings above are four separate things
- fail: there is a reason it cannot run. The exit code is 1
Go through the warnings one by one.
- fail2ban: it rewrites firewall rules, so its rules can overlap with RoamSwitch's. If you already use it, decide which one leads. An installed but inactive ufw does not raise a warning.
- Egress block list: the bundled block list is empty, so right after installing no destination is blocked. To block addresses, write them into
/var/lib/roamswitch/threatfeed/malicious_ips.txt, or put the URL of a public list inegress_ip_feed_urls(empty by default, so nothing is fetched). - Web rules: web shell detection watches nothing until you name the folders to watch. If you run a web server, name them. If you do not, leave it.
- Alert channel: with no destination, a detection reaches no one. You set this up in the next section.
Signed data updates run once right after a first install. After that, the timer runs them once a day. The time is in UTC.
#Set up an alert channel
Emergency notifications (Telegram, LINE, Webhook) can reach Telegram, LINE and webhooks. For practice, you run a receiver on the same machine and point the webhook at it. You see how an alert arrives before you send anything to a real Slack or Discord.
This edits the settings file (it changes the machine). Try it in a practice environment.
Start a receiver. It writes each request body to a file.
cat > /tmp/recv.py <<'PY'
import http.server
class H(http.server.BaseHTTPRequestHandler):
def do_POST(self):
n = int(self.headers.get('content-length', 0))
open('/tmp/recv.log', 'a').write(self.path + ' ' + self.rfile.read(n).decode() + '\n')
self.send_response(200); self.end_headers()
def log_message(self, *a): pass
http.server.HTTPServer(('127.0.0.1', 8099), H).serve_forever()
PY
nohup python3 /tmp/recv.py >/dev/null 2>&1 &Set the destination, and send a test alert. The alert language follows language in the settings, so set it to en first.
sudo roamswitch server config set language en
sudo roamswitch server config set webhook_url http://127.0.0.1:8099/hook
sudo roamswitch server config set webhook_enabled true
sudo roamswitch server test-notify webhook
cat /tmp/recv.log ✓ Server configuration updated and saved. (language = en)
To apply: sudo systemctl restart roamswitch-server or sudo roamswitch server restart
✓ Server configuration updated and saved. (webhook_url = http://127.0.0.1:8099/hook)
This channel is still off. To send alerts through it, also run sudo roamswitch server config set webhook_enabled true.
To apply: sudo systemctl restart roamswitch-server or sudo roamswitch server restart
✓ Server configuration updated and saved. (webhook_enabled = true)
To apply: sudo systemctl restart roamswitch-server or sudo roamswitch server restart
🔔 Dispatching test notification to endpoint (webhook) ...
[✓ Success] Webhook: Sent successfully
/hook {"content":"🔔 [RoamSwitch Server Test] Incident notification delivery test succeeded.\nHost: ubuntu (IP: 192.168.64.6)\nTimestamp: 2026-11-12 01:28:21","source":"RoamSwitch Server Edition","text":"..."}Setting only webhook_url prints a hint that the channel is still off. Alerts do not go out through it until webhook_enabled is true.
The receiver got the body, with the host name, the IP address and the time. The time is the machine's own clock. On a machine set to UTC, add the offset for your own time zone when you read it.
Run doctor again and one warning is gone.
sudo roamswitch doctor | tail -4[warn] Web rules: no document root was found, so web shells are not watched at all. Name the roots in scan_dirs of /etc/roamswitch/web_rules.conf.
[ok] Alert channels ready: webhook
Nothing failed (3 warnings)#How to change settings, and how it fails
You read and change settings with roamswitch server config.
sudo roamswitch server config get ssh_ports
sudo roamswitch server config set ssh_ports 2222
sudo roamswitch server config get ssh_ports
sudo roamswitch doctor | grep -E 'sshd|warnings\)'
sudo roamswitch server config set ssh_ports 22
sudo roamswitch server config set nonexistent_key 1
sudo roamswitch server config set webhook_enabled maybe22
✓ Server configuration updated and saved. (ssh_ports = 2222)
To apply: sudo systemctl restart roamswitch-server or sudo roamswitch server restart
2222
[warn] sshd also listens on port 22. The firewall running now does not block port 22, but ssh_ports in the saved server.conf is 2222. When roamswitch-server restarts (server restart or a reboot), the firewall lets in only ssh_ports and allowed_ports, and port 22 can no longer be reached from outside. Anyone who logs in only through it will be locked out. Before restarting: sudo roamswitch server config set ssh_ports 22,2222 then sudo roamswitch server restart
Nothing failed (4 warnings)
✓ Server configuration updated and saved. (ssh_ports = 22)
To apply: sudo systemctl restart roamswitch-server or sudo roamswitch server restart
Error: Unknown configuration key: 'nonexistent_key'
Error: Specify true or false: 'maybe'Four things to take from this.
- Saving a setting does not apply it to the daemon: you need a restart (
sudo roamswitch server restart).test-notifyis the exception, because it uses the saved setting at once - When
ssh_portsdoes not match the port sshd listens on, doctor shows a warning. Saving alone does not change the running firewall. The warning says that a restart would lock you out, and gives the command to run before that - A key that does not exist, or a value of the wrong kind, is not saved and gives an error (exit code 1)
/etc/roamswitch/server.confis-rw-------(only root can read or write it). It can hold secrets such as notification keys
ssh_ports is the port that stays open after an emergency isolation (a note in the settings file). If sshd listens on another port, set the same number here. If they differ, you may not be able to get in after the protection has acted. Before you change it on a real machine, run sudo roamswitch doctor and check that no warning about the sshd port appears.
sudo roamswitch server config set webhook_url http://127.0.0.1:1/none
sudo roamswitch server test-notify webhook; echo "rc=$?" 🔔 Dispatching test notification to endpoint (webhook) ...
[✗ Failed] Webhook: curl failed (exit code 7), log:
rc=1exit code 7 means curl could not connect. test-notify itself exits with 1 when delivery fails, and also when no alert channel is enabled. A script can rely on that exit code. Check the URL spelling, the port, and whether the other side is running. After you pick a destination, always confirm with test-notify that it arrives. The doctor line "Alert channels ready: webhook" only says the setting is on. It does not promise delivery: with this broken URL, doctor still prints it as ok.
#What it cannot see
In the range checked on a real machine (a disposable Ubuntu 24.04 VM):
- doctor does not check delivery. "Alert channels ready: webhook" does not mean the URL is right or that the other side accepts it. Check with
test-notify - A test alert that arrives does not prove that a real detection alert will. It confirms that the destination setting is correct
- Alerts are in Japanese or English. A note in the example settings file says that when
languageis noten, alerts come out in Japanese. Withlanguageset toen, the test alert was in English. Messages the commands print on screen, errors included, followLANG - Telegram and LINE need credentials such as a token in the settings file, and you check them with the same
test-notify(test-notify telegram,test-notify line). This lesson practiced the steps with a webhook, which needs no credentials
doctor printed "Nothing failed (4 warnings)". How should you read that
Show the explanation
"Fail" and "warn" are different. With no failures but no alert channel, a detection still reaches no one. Read each warning and decide whether your environment needs action.
#What to learn next
- Switching and choosing protection levels is covered in "Protection levels: settings and when to use each" (coming soon)
- Forwarding detections to a SIEM or syslog, and reading the notification history, are covered in Notifications and event forwarding
- Every setting is listed in the Linux Server operations manual
Verified on 2026-11-12. Target: Linux 1.17.39. In a disposable Ubuntu 24.04 (arm64) VM, purged roamswitch-server, reinstalled it with the official apt steps, and ran every listed command in Japanese and English. The webhook was checked against a receiver inside the VM, reading the delivered body.
Command output varies with the product version and the environment. If yours differs, check the version first.