Files
reflector-dashboard/help.html
T

720 lines
42 KiB
HTML

<!doctype html>
<!-- SvxPortal — Copyright (C) 2026 SA7AUX (Björn) — SPDX-License-Identifier: AGPL-3.0-or-later — see LICENSE -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Help &amp; Guides — SvxPortal | SvxLink nodes, reflector, build from source</title>
<meta name="description" content="SvxPortal help &amp; guides: register your SvxLink node, certificates, talkgroups and trunks — plus how to compile SvxLink from source on Debian, Ubuntu and Raspberry Pi, and how to find the right deb packages.">
<link rel="canonical" href="https://svxportal.sa7aux.se/help.html">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
:root{ color-scheme:dark; --bg:#000; --fg:#00ffff; --fg2:rgba(0,255,255,.75); --line:rgba(0,255,255,.35); }
html, body{ height:100%; background:var(--bg); color:var(--fg); }
body{ margin:0; }
*{ color:var(--fg); }
.navbar{ background: var(--bg) !important; }
a{ color:var(--fg) !important; }
.text-secondary{ color: var(--fg2) !important; }
.btn.btn-outline-secondary{ background: var(--bg) !important; color: var(--fg) !important; border-color: rgba(0,255,255,.7) !important; }
.btn.btn-outline-secondary:hover{ background: rgba(0,255,255,.1) !important; }
.panel{ border:1px solid var(--line); border-radius:10px; padding:16px; margin-bottom:16px; }
h5{ margin-bottom:12px; }
dt{ color:var(--fg2); font-weight:normal; margin-top:8px; }
dd{ margin-left:0; margin-bottom:4px; }
pre.code{ border:1px solid var(--line); border-radius:8px; padding:12px; overflow-x:auto;
font-size:.8rem; background:rgba(0,255,255,.05); margin:8px 0; }
.help-tabs{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:16px; }
.help-tabs button{ background:var(--bg); color:var(--fg); border:1px solid var(--line);
border-radius:8px; padding:6px 14px; cursor:pointer; }
.help-tabs button.active{ background:rgba(0,255,255,.15); border-color:var(--fg); }
/* Mobile responsive */
@media (max-width: 768px) {
.container, .container-fluid { padding-left: 10px; padding-right: 10px; }
table.data-table { font-size: .75rem; }
table.data-table th, table.data-table td { padding: 4px 6px; }
.node-grid { grid-template-columns: 1fr; gap: 1px 0; }
.node-grid dt { margin-top: 6px; }
.panel { padding: 12px; }
.d-flex.gap-2 { gap: 4px !important; }
.btn-sm { font-size: .75rem; padding: 3px 8px; }
.mono { font-size: .8rem; word-break: break-all; }
.navbar-text { font-size: .75rem; }
#paginationWrap .btn { padding: 2px 6px !important; font-size: .7rem; }
}
@media (max-width: 480px) {
table.data-table th:nth-child(3), table.data-table td:nth-child(3),
table.data-table th:nth-child(5), table.data-table td:nth-child(5),
table.data-table th:nth-child(6), table.data-table td:nth-child(6) { display: none; }
.profile-tabs { gap: 2px; }
.profile-tab { padding: 6px 8px; font-size: .8rem; }
}
</style>
</head>
<body>
<nav class="navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">SvxPortal</a>
<span class="navbar-text small me-auto ms-3">Help</span>
<a href="/" class="btn btn-sm btn-outline-secondary" onclick="if(history.length>1){history.back();return false;}">Back</a>
</div>
</nav>
<div class="container py-3" style="max-width:800px;">
<div class="help-tabs" id="helpTabs">
<button data-tab="portal" class="active">Portal</button>
<button data-tab="svxlink">SvxLink</button>
<button data-tab="svxref">SvxReflector</button>
<button data-tab="geu">GeuReflector</button>
<button data-tab="usrp">SvxLink-USRP</button>
<button data-tab="opusfec">Opus FEC</button>
<button data-tab="allstar">AllStar</button>
<button data-tab="pbxsvx">PBX &harr; SVX</button>
<button data-tab="admin">Admin</button>
</div>
<div class="tab-section" id="tab-portal">
<div class="panel">
<h5>Getting Started</h5>
<dl>
<dt>Register</dt>
<dd>Click <strong>Register</strong> in the top bar. Fill in your callsign, name, email and password. A verification email will be sent. After verifying your email, an administrator will activate your account.</dd>
<dt>Sign in</dt>
<dd>Click <strong>Sign in</strong> and enter your callsign (or email) and password.</dd>
<dt>Profile</dt>
<dd>After signing in, click your callsign in the top right and select <strong>Profile</strong>. Here you can edit your details and see your connected nodes.</dd>
</dl>
</div>
<div class="panel">
<h5>Your Nodes</h5>
<dl>
<dt>My Nodes tab</dt>
<dd>In your Profile, the <strong>My Nodes</strong> tab shows all nodes connected to the reflector that match your callsign. You can see node info, monitored talkgroups, CTCSS mappings, QTH, and RX/TX status.</dd>
<dt>Node Admins</dt>
<dd>Each node can have multiple administrators. The node owner (sysop) is always an admin. Additional admins can be added by a site administrator.</dd>
<dt>Certificates</dt>
<dd>Nodes need a signed certificate to connect. When your node first connects, it sends a Certificate Signing Request (CSR). An administrator will sign it, and the reflector sends the certificate to your node automatically.</dd>
</dl>
</div>
<div class="panel">
<h5>Account Status</h5>
<dl>
<dt>Banned</dt>
<dd>Your account has been suspended by an administrator. You cannot log in. The reason (if provided) will be shown at login. Contact an administrator to resolve this.</dd>
<dt>Locked</dt>
<dd>Your account has been temporarily locked. You cannot log in. The reason (if provided) will be shown at login. Contact an administrator.</dd>
<dt>Unverified</dt>
<dd>Your email has not been verified yet. Check your inbox for the verification link. If you did not receive it, contact an administrator.</dd>
</dl>
</div>
<div class="panel">
<h5>Notifications</h5>
<dl>
<dt>Bell icon</dt>
<dd>The bell icon in the top bar shows notifications. For regular users it shows account events (ban, lock, unlock). For administrators it also shows pending certificate requests and new registrations.</dd>
</dl>
</div>
<div class="panel">
<h5>Navigation</h5>
<dl>
<dt>Reflector clients</dt>
<dd>All connected nodes with real-time status, <strong>including remote nodes that arrive via a trunk</strong>. Shown as a table: Callsign (with sysop), Class, TG, Location, RX/TX, software/version and monitored talkgroups. The node currently transmitting is highlighted.</dd>
<dt>Monitor</dt>
<dd>Live activity monitor with <strong>Nodes</strong> and <strong>Trunks</strong> sub-views. Trunks shows each trunk link's status (Name, Status, heartbeat rx/tx, active talkgroups, Type, Qual).</dd>
<dt>Lastheard</dt>
<dd>Recent transmissions with callsign, talkgroup and duration &mdash; including traffic that arrives over a trunk (shown as <em>callsign via &lt;trunk&gt;</em>, with source local/trunk).</dd>
<dt>CTCSS Table</dt>
<dd>Reference table for CTCSS tone frequencies and talkgroup mappings.</dd>
<dt>Map</dt>
<dd>Geographic map showing node locations.</dd>
</dl>
</div>
<div class="panel">
<h5>Trunks &amp; Remote Nodes</h5>
<dl>
<dt>What is a trunk?</dt>
<dd>A trunk is a link between this reflector and another reflector network (for example reflector-network.se). Talkgroup audio is exchanged across the link.</dd>
<dt>Remote nodes</dt>
<dd>Nodes on the other side of a trunk are relayed in and appear in the client list, Monitor and Lastheard just like local nodes. They do <strong>not</strong> log in to this reflector &mdash; only the trunk link itself is authenticated (a shared key).</dd>
<dt>Identity</dt>
<dd>A remote node's identity is the name it advertises over the trunk (e.g. a node name like <span class="mono">SE-EASTCOAST</span>). There is no separate, locally verified operator callsign for trunk traffic &mdash; the advertised name is the identity.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-svxlink">
<div class="panel">
<h5>Build SvxLink from source (Debian / Ubuntu / Raspberry Pi)</h5>
<dl>
<dt>What this covers</dt>
<dd>Compiling stock <a href="https://github.com/sm0svx/svxlink">SvxLink</a> (svxlink node, svxreflector, RemoteTrx) on Debian 12/13 (bookworm/trixie) or Ubuntu 22.04/24.04 &mdash; PC or Raspberry&nbsp;Pi (64-bit). The same procedure works for forks: just clone a different repository.</dd>
</dl>
<pre class="code">#!/bin/bash
set -e
# --- Build dependencies ------------------------------------------------
# Package names drift between releases. If apt says
# "Unable to locate package X": apt search &lt;part-of-name&gt;
# (e.g. apt search libgpiod) and pick the closest -dev package.
sudo apt update
sudo apt install -y \
build-essential cmake git wget curl sox alsa-utils vorbis-tools \
libgpiod-dev `# pulls the right runtime: libgpiod2 (bookworm/ubuntu) or libgpiod3 (trixie)` \
libsigc++-2.0-dev libgsm1-dev libpopt-dev \
tcl8.6-dev `# NOT tcl9.0-dev - svxlink wants 8.6 (apt list -a 'tcl*-dev' shows yours)` \
libgcrypt20-dev libssl-dev libspeex-dev libasound2-dev libopus-dev \
librtlsdr-dev libjsoncpp-dev libcurl4-gnutls-dev libogg-dev
# Optional, only for the Qtel EchoLink GUI (skip on headless/RPi):
# sudo apt install -y qtbase5-dev qttools5-dev qttools5-dev-tools
# Optional, only for "make doc": doxygen groff
# --- svxlink system user -----------------------------------------------
id -u svxlink &gt;/dev/null 2&gt;&amp;1 || sudo useradd -r -G audio,plugdev,dialout svxlink
getent group gpio &gt;/dev/null &amp;&amp; sudo usermod -aG gpio svxlink # RPi: GPIO PTT
# --- Fetch and build ---------------------------------------------------
mkdir -p ~/projects &amp;&amp; cd ~/projects
[ -d svxlink ] || git clone https://github.com/sm0svx/svxlink.git
mkdir -p svxlink/src/build &amp;&amp; cd svxlink/src/build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \
-DLOCAL_STATE_DIR=/var -DWITH_SYSTEMD=yes ..
make -j"$(nproc)"
sudo make install
sudo ldconfig
# --- Sound files (English + Swedish) -----------------------------------
cd ~/projects
[ -d svxlink-sounds-en_US-heather ] || git clone https://github.com/sm0svx/svxlink-sounds-en_US-heather.git
[ -d svxlink-sounds-sv_SE-elin ] || git clone https://github.com/sm0svx/svxlink-sounds-sv_SE-elin.git
cp svxlink/src/svxlink/scripts/filter_sounds.sh .
sudo ./filter_sounds.sh svxlink-sounds-en_US-heather en_US
sudo ./filter_sounds.sh svxlink-sounds-sv_SE-elin sv_SE
sudo tar xjf svxlink-sounds-en_US.tar.bz2 -C /usr/share/svxlink/sounds
sudo tar xjf svxlink-sounds-sv_SE.tar.bz2 -C /usr/share/svxlink/sounds
# --- Enable what this machine should run -------------------------------
# Node: sudo systemctl enable --now svxlink
# Reflector: sudo systemctl enable --now svxreflector</pre>
<dl>
<dt>&quot;Unable to locate package &hellip;&quot;</dt>
<dd>Find the real name on your release: <span class="mono">apt search libgpiod</span>, <span class="mono">apt list -a 'tcl*-dev'</span> or <span class="mono">apt-cache policy &lt;package&gt;</span>. Rule of thumb: install the <span class="mono">-dev</span> package &mdash; its name is stable across releases, while runtime libraries carry version suffixes that differ (libgpiod2 vs libgpiod3).</dd>
<dt>&quot;fatal error: some/header.h: No such file&quot;</dt>
<dd>Find which package ships the header: <span class="mono">sudo apt install apt-file &amp;&amp; sudo apt-file update</span>, then <span class="mono">apt-file search header.h</span> &mdash; install the -dev package it points to and re-run cmake.</dd>
<dt>Raspberry Pi notes</dt>
<dd>64-bit Raspberry Pi OS builds fine with the same script. The <span class="mono">gpio</span> group above is what allows GPIO PTT. On a Pi&nbsp;3, use <span class="mono">make -j2</span> to avoid running out of RAM.</dd>
</dl>
</div>
<div class="panel">
<h5>Configure the node &mdash; radio side (svxlink.conf)</h5>
<dl>
<dt>Skeleton</dt>
<dd>A minimal simplex node: one logic, one receiver, one transmitter. Everything lives in <span class="mono">/etc/svxlink/svxlink.conf</span>:</dd>
</dl>
<pre class="code">[GLOBAL]
LOGICS=SimplexLogic,ReflectorLogic
CFG_DIR=svxlink.d
CARD_SAMPLE_RATE=48000
[SimplexLogic]
TYPE=Simplex
RX=Rx1
TX=Tx1
CALLSIGN=SM0ABC
MODULES=ModuleHelp,ModuleParrot
REPORT_CTCSS=136.5 ; subtone your node transmits
DEFAULT_LANG=en_US
[Rx1]
TYPE=Local
AUDIO_DEV=alsa:plughw:0
AUDIO_CHANNEL=0
SQL_DET=CTCSS ; VOX works too, CTCSS is cleaner
CTCSS_FQ=136.5
SQL_HANGTIME=2000
[Tx1]
TYPE=Local
AUDIO_DEV=alsa:plughw:0
AUDIO_CHANNEL=0
PTT_TYPE=SerialPin ; on a Raspberry Pi instead:
PTT_PORT=/dev/ttyUSB0 ; PTT_TYPE=GPIOD
PTT_PIN=DTRRTS ; PTT_GPIOD_CHIP=gpiochip0 PTT_GPIOD_LINE=17</pre>
<dl>
<dt>CTCSS &rarr; talkgroup</dt>
<dd>With <span class="mono">CTCSS_TO_TG=</span> in the logic section, different subtones select different talkgroups &mdash; that is what populates the tone table in this portal.</dd>
</dl>
</div>
<div class="panel">
<h5>Set up a SvxLink node (connect to this network)</h5>
<dl>
<dt>1. Register</dt>
<dd>Create an account on this portal first (see <em>Getting Started</em>) so the administrator knows who the node belongs to.</dd>
<dt>2. Configure ReflectorLogic</dt>
<dd>In <span class="mono">/etc/svxlink/svxlink.conf</span> on your node:</dd>
</dl>
<pre class="code">[ReflectorLogic]
TYPE=Reflector
HOSTS=svx.sa7aux.se
CALLSIGN="SM0ABC-1" ; your node callsign (with -suffix if you run several)
CERT_EMAIL=you@example.com ; used in your node certificate
CERT_DOWNLOAD_CA_BUNDLE=1
CERT_CAFILE=/var/lib/svxlink/pki/ca-bundle.pem
DEFAULT_TG=240
MONITOR_TGS=240,2400
EVENT_HANDLER=/usr/share/svxlink/events.tcl
NODE_INFO_FILE=/etc/svxlink/node_info.json</pre>
<dl>
<dt>3. First connect &mdash; certificate</dt>
<dd>Add the logic to <span class="mono">LOGICS=</span> in <span class="mono">[GLOBAL]</span> and start svxlink. On first connect the node automatically sends a Certificate Signing Request. When the administrator signs it, the certificate is delivered to your node automatically and it comes online &mdash; nothing more to do on your side.</dd>
<dt>Fill in node_info.json</dt>
<dd>QTH, locator, frequencies and CTCSS in <span class="mono">/etc/svxlink/node_info.json</span> is what makes your node show up properly in the portal (map, frequencies, tone table).</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-usrp">
<div class="panel">
<h5>Build the USRP fork (svxlink-usrp)</h5>
<dl>
<dt>What it is</dt>
<dd>DL1HRC's SvxLink fork with <span class="mono">UsrpLogic</span> &mdash; bridges USRP audio (AllStar <span class="mono">chan_usrp</span>, DVSwitch Analog_Bridge) into SvxLink. UsrpLogic lives in contrib and is built automatically.</dd>
</dl>
<pre class="code"># Same build dependencies as the stock guide above, then:
cd ~/projects
git clone https://github.com/dl1hrc/svxlink.git svxlink-usrp
cd svxlink-usrp
git checkout svxlink-usrp
mkdir -p src/build &amp;&amp; cd src/build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \
-DLOCAL_STATE_DIR=/var -DWITH_SYSTEMD=yes ..
make -j"$(nproc)"
sudo make install &amp;&amp; sudo ldconfig</pre>
<dl>
<dt>Configuration</dt>
<dd>Add a <span class="mono">[UsrpLogic]</span> section to svxlink.conf &mdash; see the <span class="mono">UsrpLogic.conf</span> man page shipped with the fork for the USRP host/port settings.</dd>
</dl>
</div>
<div class="panel">
<h5>Configure UsrpLogic (svxlink.conf)</h5>
<pre class="code">[UsrpLogic]
TYPE=Usrp
USRP_HOST=127.0.0.1
USRP_TX_PORT=4002 ; svxlink sends here (Asterisk listens)
USRP_RX_PORT=4001 ; svxlink listens here (Asterisk sends)
CALL=N0CALL
DV_USER_INFOFILE=/etc/svxlink/dv_users.json
JITTER_BUFFER_DELAY=100
SHARE_USERINFO=1</pre>
<dl>
<dt>Wiring it up</dt>
<dd>Add <span class="mono">UsrpLogic</span> to <span class="mono">LOGICS=</span> and connect it to your <span class="mono">ReflectorLogic</span> with a LinkManager section (see the svxlink.conf man page) &mdash; the reflector TG the bridge lands on is the logic's <span class="mono">DEFAULT_TG</span>. The other end of the UDP port pair is the AllStar side &mdash; see the <strong>AllStar</strong> tab.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-opusfec">
<div class="panel">
<h5>Opus in-band FEC patch (lossy long-haul links)</h5>
<dl>
<dt>What it fixes</dt>
<dd>Over a long-haul reflector hop with real packet loss (for example a transatlantic link) Opus audio breaks up more and more the longer a QSO runs. SvxLink's Opus encoder ships with <strong>in-band FEC off</strong> and <strong>expected packet loss 0%</strong> &mdash; and there was no config key to change it: the encoder had the setters but they were never wired to <span class="mono">setOption</span>. This patch exposes them so the config can turn on forward error correction. (Confirmed identical in stock <span class="mono">sm0svx</span> and the <span class="mono">dl1hrc</span> USRP fork.)</dd>
<dt>Where it belongs</dt>
<dd>On the <strong>SvxLink node that encodes</strong> audio into the lossy hop &mdash; <em>not</em> on SvxReflector, which only relays the already-encoded Opus stream. FEC must be added by the encoder at the sending end; the decoder at the far end uses it automatically.</dd>
</dl>
</div>
<div class="panel">
<h5>Get the patched fork and build it</h5>
<dl>
<dt>Clone the public fork</dt>
<dd>The patch sits on top of DL1HRC's <span class="mono">svxlink-usrp</span> in a public Gitea fork. Clone it and check out the tagged, patched version:</dd>
</dl>
<pre class="code"># Same build dependencies as the SvxLink tab, then:
cd ~/projects
git clone https://git.sa7aux.se/bjorne/svxlink-fork-usrp.git svxlink-usrp
cd svxlink-usrp
git checkout opus-fec-260723 # tagged patched version
# or: git checkout opus-inband-fec # the branch it lives on
mkdir -p src/build &amp;&amp; cd src/build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \
-DLOCAL_STATE_DIR=/var -DWITH_SYSTEMD=yes -DUSE_QT=OFF ..
make -j"$(nproc)"
sudo make install &amp;&amp; sudo ldconfig</pre>
<dl>
<dt><span class="mono">-DUSE_QT=OFF</span></dt>
<dd>Skips the Qtel EchoLink GUI &mdash; needed unless the full Qt6 stack (including Qt6Core5Compat) is installed. We only build the node, reflector and audio libraries.</dd>
</dl>
</div>
<div class="panel">
<h5>Enable FEC (svxlink.conf &mdash; ReflectorLogic)</h5>
<dl>
<dt>Config keys</dt>
<dd>Add these to the <span class="mono">[ReflectorLogic]</span> section. Any <span class="mono">OPUS_ENC_&lt;OPTION&gt;</span> key is passed straight through to the Opus encoder:</dd>
</dl>
<pre class="code">[ReflectorLogic]
; ... existing settings ...
OPUS_ENC_INBAND_FEC=1 ; enable Opus in-band forward error correction
OPUS_ENC_PACKET_LOSS=10 ; expected packet loss %, drives FEC redundancy</pre>
<dl>
<dt>OPUS_ENC_INBAND_FEC</dt>
<dd><span class="mono">1</span> = on, <span class="mono">0</span> = off (default). With FEC on, the encoder embeds a low-bitrate copy of the previous frame inside the next packet, so the decoder can rebuild a single lost packet instead of dropping audio.</dd>
<dt>OPUS_ENC_PACKET_LOSS</dt>
<dd>The loss percentage the encoder should plan for (for example <span class="mono">10</span>). It controls how much FEC redundancy is added: higher = more robust to loss but slightly less bitrate left for the main audio. Match it to the real loss on your path &mdash; 5&ndash;15 is sensible for a transatlantic hop.</dd>
<dt>Verify</dt>
<dd>On start SvxLink logs its Opus parameters. You should now see <span class="mono">Inband FEC = YES</span> and <span class="mono">Expected Packet Loss = 10%</span> instead of <span class="mono">NO</span> / <span class="mono">0%</span>.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-geu">
<div class="panel">
<h5>Build GeuReflector (trunked reflector)</h5>
<dl>
<dt>What it is</dt>
<dd>A fork of SvxReflector (trunk extension by IW1GEU) that links multiple reflectors into a federated mesh &mdash; talkgroups are routed to their owning server by numeric prefix. This network runs SA2BLV's fork of it.</dd>
</dl>
<pre class="code"># Same build dependencies as the stock guide above, plus:
sudo apt install -y libhiredis-dev `# or build with -DWITH_REDIS=OFF`
cd ~/projects
git clone https://github.com/sa2blv/GeuReflector.git
cd GeuReflector
git checkout SwedenReflectors
mkdir -p src/build &amp;&amp; cd src/build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \
-DLOCAL_STATE_DIR=/var -DWITH_SYSTEMD=yes ..
make -j"$(nproc)"
sudo make install &amp;&amp; sudo ldconfig
sudo systemctl enable --now svxreflector</pre>
</div>
<div class="panel">
<h5>Configure trunks (svxreflector.conf)</h5>
<dl>
<dt>How routing works</dt>
<dd>Each reflector owns all talkgroups whose number starts with its prefix (like telephone country codes). Trunk peers exchange audio over UDP and talkgroups are routed to the owning server automatically.</dd>
</dl>
<pre class="code">[GLOBAL]
LOCAL_PREFIX=240 ; this reflector owns TG 240*, 2400*, ...
[ReflectorTrunk]
GatewayId=SE-MYREFLECTOR ; this server's identity on the trunk network
Port=5500 ; UDP trunk port
Peers=SE-AUX ; comma-separated [TrunkPeer#...] names
[TrunkPeer#SE-AUX]
Host=reflector.example.com
Port=5500
TGRule=^.*$ ; regex: which TGs may cross this trunk
Retransmit=0
ActiveFilter=0
Key=CHANGEME ; shared secret, same on both sides</pre>
<dl>
<dt>Joining an existing network</dt>
<dd>Both sides must agree on peer name, port and key. To peer with this network, contact the administrator.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-svxref">
<div class="panel">
<h5>Run your own reflector: basics &amp; password login</h5>
<dl>
<dt>Basics</dt>
<dd>In <span class="mono">/etc/svxlink/svxreflector.conf</span>: <span class="mono">LISTEN_PORT=5300</span> is what nodes connect to, <span class="mono">HTTP_SRV_PORT=8090</span> serves the <span class="mono">/status</span> JSON that dashboards read.</dd>
<dt>Password login (legacy v1/v2 clients)</dt>
<dd><span class="mono">[USERS]</span> maps a callsign to a key group and <span class="mono">[PASSWORDS]</span> holds each group's secret &mdash; several nodes can share one group:</dd>
</dl>
<pre class="code">[USERS]
SM0ABC-1=MyNodes
SM0ABC-2=MyNodes
SM3XYZ=SM3XYZ
[PASSWORDS]
MyNodes="a strong shared key"
SM3XYZ="another strong password"</pre>
</div>
<div class="panel">
<h5>Certificates (PKI)</h5>
<dl>
<dt>The reflector is its own CA</dt>
<dd>On first start the reflector creates a complete PKI from the <span class="mono">[ROOT_CA]</span>, <span class="mono">[ISSUING_CA]</span> and <span class="mono">[SERVER_CERT]</span> sections &mdash; fill in your own organisation and set <span class="mono">COMMON_NAME</span>/<span class="mono">SUBJECT_ALT_NAME</span> in <span class="mono">[SERVER_CERT]</span> to your reflector's public hostname:</dd>
</dl>
<pre class="code">[GLOBAL]
CERT_PKI_DIR=/etc/svxlink/pki
CERT_CA_BUNDLE=/etc/svxlink/pki/ca-bundle.crt
CERT_CA_KEYS_DIR=/etc/svxlink/pki/private/
CERT_CA_PENDING_CSRS_DIR=/etc/svxlink/pki/pending_csrs/
CERT_CA_CSRS_DIR=/etc/svxlink/pki/csrs/
CERT_CA_CERTS_DIR=/etc/svxlink/pki/certs/
#ACCEPT_CALLSIGN="[A-Z0-9][A-Z]{0,2}\d[A-Z0-9]{0,3}[A-Z](?:-[A-Z0-9]{1,3})?"
[SERVER_CERT]
COMMON_NAME=reflector.example.com
SUBJECT_ALT_NAME=DNS:reflector.example.com
ORG=MYCLUB
COUNTRY=SE
EMAIL_ADDRESS=you@example.com</pre>
<dl>
<dt>Signing node certificates</dt>
<dd>Incoming node CSRs land in <span class="mono">CERT_CA_PENDING_CSRS_DIR</span> until an administrator signs them; the signed certificate is then pushed to the node automatically over the reflector connection. Use the <span class="mono">ACCEPT_CALLSIGN=</span> regex to restrict who may even submit one.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-allstar">
<div class="panel">
<h5>AllStar &rarr; SvxReflector &mdash; native (chan_svx)</h5>
<dl>
<dt>What it is</dt>
<dd><span class="mono">chan_svx</span> is an Asterisk channel driver for <strong>AllStarLink&nbsp;3</strong> that connects directly to a SvxLink <strong>SVXReflector</strong>. Unlike the USRP bridge (see the <strong>SvxLink-USRP</strong> tab), it speaks the reflector protocol natively &mdash; lower latency, simpler architecture, a single Opus transcoding step, and reduced CPU/memory. SVXReflector talkgroups can be used straight from AllStarLink with no intermediate USRP hop.</dd>
<dt>Features</dt>
<dd>Native SVXReflector connectivity &middot; direct <span class="mono">app_rpt</span> integration &middot; SVXReflector v2 protocol (HMAC-SHA1) &middot; configurable jitter buffer &middot; adjustable RX/TX gain &middot; optional RX/TX AGC &middot; x86-64 and ARM64 (Raspberry&nbsp;Pi). Source code is private.</dd>
<dt>Requirements</dt>
<dd>Debian&nbsp;12 (Bookworm) or Debian&nbsp;13 (Trixie) &middot; AllStarLink&nbsp;3 (<span class="mono">asl3-asterisk</span>) already installed &middot; access credentials for an SVXReflector.</dd>
</dl>
<dl>
<dt>1. Choose the correct package</dt>
<dd>Browse and download from the repository: <a href="https://git.sa7aux.se/bjorne/chan-svx-deb" target="_blank" rel="noopener">git.sa7aux.se/bjorne/chan-svx-deb</a></dd>
<dd>Check your Debian release and CPU architecture, then pick the matching <span class="mono">.deb</span> (64-bit only):</dd>
</dl>
<pre class="code">. /etc/os-release; echo $VERSION_CODENAME # trixie / bookworm
dpkg --print-architecture # amd64 / arm64</pre>
<dl>
<dd>
<span class="mono">asl3-chan-svx_0.2.4~trixie_amd64.deb</span> &mdash; Debian&nbsp;13, x86-64<br>
<span class="mono">asl3-chan-svx_0.2.4~trixie_arm64.deb</span> &mdash; Debian&nbsp;13, ARM64 (Raspberry Pi OS Trixie)<br>
<span class="mono">asl3-chan-svx_0.2.4~bookworm_amd64.deb</span> &mdash; Debian&nbsp;12, x86-64<br>
<span class="mono">asl3-chan-svx_0.2.4~bookworm_arm64.deb</span> &mdash; Debian&nbsp;12, ARM64 (Raspberry Pi OS Bookworm)
</dd>
</dl>
<dl>
<dt>2. Install</dt>
<dd>Dependencies (<span class="mono">asl3-asterisk</span>, <span class="mono">libopus0</span>, <span class="mono">libssl3</span>) are pulled in automatically:</dd>
</dl>
<pre class="code">sudo apt install ./asl3-chan-svx_0.2.4~&lt;os&gt;_&lt;arch&gt;.deb</pre>
<dl>
<dt>3. Create /etc/asterisk/svx.conf</dt>
<dd>One section per reflector login / talkgroup. Required: <span class="mono">host</span>, <span class="mono">port</span>, <span class="mono">callsign</span>, <span class="mono">password</span>, <span class="mono">tg</span>. Optional: <span class="mono">tx_hold</span>, <span class="mono">jitter</span>, <span class="mono">rx_gain</span>, <span class="mono">tx_gain</span>, <span class="mono">rx_agc</span>, <span class="mono">tx_agc</span>.</dd>
<dt>4. Enable the module</dt>
<dd>In <span class="mono">/etc/asterisk/modules.conf</span> (remove the leading semicolon if the line is commented out):</dd>
</dl>
<pre class="code">load = chan_svx.so</pre>
<dl>
<dt>5. Point app_rpt at it</dt>
<dd>In <span class="mono">/etc/asterisk/rpt.conf</span>, where <span class="mono">&lt;section&gt;</span> matches the <span class="mono">svx.conf</span> section name:</dd>
</dl>
<pre class="code">rxchannel = SVX/&lt;section&gt;</pre>
<dl>
<dt>6. Restart &amp; verify</dt>
<dd>A successful connection prints reflector and talkgroup information:</dd>
</dl>
<pre class="code">sudo asterisk -rx "core restart now"
sudo asterisk -rx "svx show"</pre>
<dl>
<dt>Compatibility</dt>
<dd>Implements the SVXReflector v2 protocol (HMAC-SHA1). Reflectors that provide v2 compatibility can be used even if their SvxLink nodes normally operate on v3/TLS.</dd>
<dt>Notes</dt>
<dd>Reflector logins must use an <strong>upper-case callsign</strong> &mdash; SVXReflector validates callsigns case-sensitively. Match the package version to your installed AllStarLink&nbsp;3 release. A full guide ships in <span class="mono">/usr/share/doc/asl3-chan-svx/INSTALL.md</span>, and the post-install script prints the required steps.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-pbxsvx">
<div class="panel">
<h5>PBX &rarr; SvxReflector &mdash; native (chan_pbx_sat)</h5>
<dl>
<dt>What it is</dt>
<dd><span class="mono">chan_pbx_sat</span> is an Asterisk channel driver that connects a <strong>PBX</strong> (FreePBX or standard Asterisk) directly to SvxLink <strong>SVXReflector</strong> talkgroups &mdash; no AllStar / <span class="mono">app_rpt</span> in the path. A phone dials a talkgroup (PBX&nbsp;&rarr;&nbsp;SVX); a talkgroup can ring a phone or ring group (SVX&nbsp;&rarr;&nbsp;PBX). A single Opus transcoding step. Source code is private.</dd>
<dt>Two packages</dt>
<dd><span class="mono">chan-pbx-sat</span> &mdash; the driver (required, any Asterisk box).<br>
<span class="mono">pbxsat-freepbx</span> &mdash; the FreePBX web GUI (<em>Connectivity &rarr; PBX &harr; SVX</em>): trunks, routing, callsigns, talkgroups, access lists, plus a live status panel and a dashboard widget. Install it too on a FreePBX box.</dd>
<dt>Requirements</dt>
<dd>Debian&nbsp;12/13 or CentOS/RHEL&nbsp;7/8/9 &middot; x86-64 &middot; Asterisk (driver) / FreePBX (GUI) &middot; access credentials for an SVXReflector.</dd>
</dl>
<dl>
<dt>1. Get the packages</dt>
<dd>All prebuilt <span class="mono">.deb</span> / <span class="mono">.rpm</span> packages live in the repository &mdash; browse and download them there:</dd>
<dd><a href="https://git.sa7aux.se/bjorne/pbx-sat-deb" target="_blank" rel="noopener">git.sa7aux.se/bjorne/pbx-sat-deb</a></dd>
</dl>
<dl>
<dt>2. Install &mdash; Debian 12 / 13</dt>
</dl>
<pre class="code">. /etc/os-release; echo $VERSION_CODENAME # bookworm (12) / trixie (13)
sudo apt install ./chan-pbx-sat_&lt;ver&gt;~&lt;suite&gt;_amd64.deb
# on a FreePBX box, add the GUI:
sudo apt install ./pbxsat-freepbx_&lt;ver&gt;~&lt;suite&gt;_all.deb</pre>
<dl>
<dt>2. Install &mdash; CentOS / RHEL 7 / 8 / 9</dt>
</dl>
<pre class="code">sudo dnf install ./chan-pbx-sat-&lt;ver&gt;.&lt;asttag&gt;.&lt;dist&gt;.x86_64.rpm
# on a FreePBX box, add the GUI:
sudo dnf install ./pbxsat-freepbx-&lt;ver&gt;.&lt;asttag&gt;.&lt;dist&gt;.noarch.rpm</pre>
<dl>
<dt>3. Configure</dt>
<dd>Copy <span class="mono">/etc/asterisk/pbx_sat.conf.sample</span> to <span class="mono">pbx_sat.conf</span> and edit it &mdash; or, with <span class="mono">pbxsat-freepbx</span> installed, use the GUI under <em>Connectivity &rarr; PBX &harr; SVX</em> (no database; it writes the same file).</dd>
<dt>4. Enable &amp; dial</dt>
<dd>Uncomment <span class="mono">load = chan_pbx_sat.so</span> in <span class="mono">/etc/asterisk/modules.conf</span>, then point a dial-plan route at <span class="mono">PBXSAT/&lt;trunk&gt;/&lt;tg&gt;</span>. Full guide: <span class="mono">/usr/share/doc/chan-pbx-sat/HOWTO.md</span>, or follow the complete walk-through below.</dd>
</dl>
</div>
<div class="panel">
<h5>Full FreePBX setup &mdash; everything, step by step</h5>
<p>The module only writes <span class="mono">pbx_sat.conf</span>. A working bridge also needs a few standard FreePBX pieces (an extension, the module loaded, a dial-plan entry). This is the whole chain, in order. Replace <span class="mono">mytrunk</span>, <span class="mono">91</span> and the talkgroup / extension numbers with your own.</p>
<dl>
<dt>0. Prerequisites</dt>
<dd>A running FreePBX&nbsp;17 (or standard Asterisk) on x86-64; at least one <strong>extension</strong> a phone can register to (<em>Applications &rarr; Extensions</em>); and credentials for an SVXReflector satellite trunk &mdash; its host, port, your <span class="mono">satellite_id</span> and the matching <span class="mono">SECRET_&lt;id&gt;</span> from the reflector's <span class="mono">svxreflector.conf</span>.</dd>
</dl>
<dl>
<dt>1. Install the packages</dt>
<dd>Install <span class="mono">chan-pbx-sat</span> (the driver) and, on FreePBX, <span class="mono">pbxsat-freepbx</span> (the GUI) &mdash; see the box above. The GUI appears under <em>Connectivity &rarr; PBX &harr; SVX</em>. The <span class="mono">.deb</span>/<span class="mono">.rpm</span> also drops the sample config and the group-dial voice prompt (English + Swedish).</dd>
</dl>
<dl>
<dt>2. Load the driver</dt>
<dd>Tell Asterisk to load the module, then confirm it is up:</dd>
</dl>
<pre class="code"># /etc/asterisk/modules.conf (under [modules])
load = chan_pbx_sat.so
sudo fwconsole restart # or: asterisk -rx "module load chan_pbx_sat.so"
asterisk -rx "pbxsat status" # should print JSON, not an error</pre>
<dl>
<dt>3. Create the trunk (GUI)</dt>
<dd><em>Connectivity &rarr; PBX &harr; SVX &rarr; Add trunk</em>. Every field shows its default, an example and the allowed range to the right. The essentials:
<ul>
<li><span class="mono">host</span> / <span class="mono">port</span> &mdash; the reflector (port defaults to 5300).</li>
<li><span class="mono">satellite_id</span> + <span class="mono">secret</span> &mdash; your trunk login and its shared HMAC secret.</li>
<li><span class="mono">callsign</span> + <span class="mono">node_location</span> &mdash; how you appear in lastheard (&ldquo;<em>&lt;callsign&gt; via &lt;label&gt;</em>&rdquo;).</li>
<li><span class="mono">tg</span> (default talkgroup) &mdash; joined at connect and used for a bare dial.</li>
<li><span class="mono">Group number</span> &mdash; the prefix a phone dials to reach <em>this</em> trunk with a dynamic TG (used in step&nbsp;5). One per trunk, so each reflector gets its own prefix.</li>
</ul>
Leave everything else on its default unless you have a reason. Save &mdash; the module writes the section to <span class="mono">pbx_sat.conf</span> and reloads the driver.</dd>
</dl>
<dl>
<dt>4. Global lists (once, shared by all trunks)</dt>
<dd>Still in the module, the other tabs are site-wide because one reflector is shared:
<ul>
<li><strong>Callsigns</strong> &mdash; <span class="mono">extension = callsign</span>, so a caller shows as their own callsign in lastheard.</li>
<li><strong>Talkgroups</strong> &mdash; a <span class="mono">number = label</span> catalogue for readability.</li>
<li><strong>Routing</strong> &mdash; <span class="mono">SIP&nbsp;&rarr;&nbsp;TG</span> (a bare dial from extension X joins TG&nbsp;Y) and <span class="mono">TG&nbsp;&rarr;&nbsp;SIP</span> (an active TG rings extension/ring-group Z; used in step&nbsp;6).</li>
<li><strong>Settings</strong> &mdash; one <span class="mono">max_dialout</span> cap on concurrent PBX&nbsp;&rarr;&nbsp;SVX calls (blank = unlimited).</li>
</ul>
</dd>
</dl>
<dl>
<dt>5. Dial-plan: let a phone dial a talkgroup (PBX &rarr; SVX)</dt>
<dd>The driver is dialled as <span class="mono">PBXSAT/&lt;trunk&gt;/&lt;tg&gt;</span>. Wire your <em>Group number</em> to it with a small custom context. Add this to <span class="mono">/etc/asterisk/extensions_custom.conf</span> (survives FreePBX reloads):</dd>
</dl>
<pre class="code">; dial 91&lt;tg&gt; to key up talkgroup &lt;tg&gt; on "mytrunk"
; (91 = this trunk's Group number; mytrunk = its name)
[pbxsat-mytrunk](+)
exten => _91.,1,Answer()
same => n,Dial(PBXSAT/mytrunk/${EXTEN:2}) ; :2 strips the "91" prefix
same => n,Hangup()</pre>
<dd>Include that context for your phones: add <span class="mono">include = pbxsat-mytrunk</span> to <span class="mono">[from-internal-custom]</span> in the same file, then <span class="mono">sudo fwconsole reload</span>. A softphone dialling <span class="mono">9124016</span> now keys TG&nbsp;24016. Mid-call, <span class="mono">*99</span>/<span class="mono">#99</span> key up/down and <span class="mono">91&lt;tg&gt;#</span> switches TG (the <span class="mono">ptt_up</span>/<span class="mono">ptt_dn</span>/<span class="mono">cmd_select_tg</span> fields).</dd>
<dl>
<dt>6. Optional: let a talkgroup ring a phone (SVX &rarr; PBX)</dt>
<dd>On the trunk, set <span class="mono">standing = yes</span> and list the talkgroups to watch in the <strong>TG list (monitor)</strong>. Then in <em>Routing</em> add a <span class="mono">TG&nbsp;&rarr;&nbsp;SIP</span> entry (e.g. <span class="mono">24016 = 200</span>, or a ring-group number). When that TG goes active the trunk originates a call into <span class="mono">pbx_context</span> (default <span class="mono">from-internal</span>) and rings the number. The target extension / ring group must exist in FreePBX.</dd>
</dl>
<dl>
<dt>7. Access control (optional, per trunk)</dt>
<dd>The trunk's <strong>Access list</strong> gates who may pass, in either direction: pick a direction (SIP&nbsp;&rarr;&nbsp;TG, TG&nbsp;&rarr;&nbsp;SIP, or both), a SIP extension (single, <span class="mono">100-199</span> range, or <span class="mono">any</span>), a TG (same forms), and allow/deny. Rules match top-down, first match wins; no rules = open.</dd>
</dl>
<dl>
<dt>8. Apply &amp; verify</dt>
<dd><span class="mono">sudo fwconsole reload</span> to apply dial-plan changes (the module already reloads the driver on save). Check the <strong>status panel</strong> at the top of the module page and the <strong>dashboard widget</strong>: each trunk shows Online/Offline and Idle/In&nbsp;use, plus any live talkers. From the CLI, <span class="mono">asterisk -rx "pbxsat status"</span> prints the same as JSON.</dd>
<dt>Secrets</dt>
<dd><span class="mono">pbx_sat.conf</span> holds the reflector secret &mdash; keep it <span class="mono">asterisk:asterisk</span> and mode <span class="mono">640</span>. The module writes it that way; if you edit by hand, re-check the permissions.</dd>
</dl>
</div>
<div class="panel">
<h5>Audio tuning (optional) &mdash; per-trunk EQ / AGC / limiter, live</h5>
<p>Each trunk carries a full audio chain <b>per direction</b> (rx = reflector&rarr;phone, tx = phone&rarr;reflector): preamp gain &rarr; 7-band EQ &rarr; AGC &rarr; limiter. It is <b>off by default</b> &mdash; a trunk that sets nothing passes audio through bit-for-bit, so this can never colour a link you didn't ask it to. The most useful piece on a phone path is the <b>limiter</b> (stops a hot caller clipping into the reflector) and <b>AGC</b> (evens out wildly different phone levels); the EQ is there for a low-cut / presence lift if you want it.</p>
<dl>
<dt>Where</dt>
<dd>Open a trunk in <em>Connectivity &rarr; PBX &harr; SVX</em>. The audio fields (<span class="mono">rx_gain</span>/<span class="mono">tx_gain</span>, <span class="mono">rx_agc</span>/<span class="mono">tx_agc</span> + target, <span class="mono">rx_lim_ceil</span>/<span class="mono">tx_lim_ceil</span>, <span class="mono">rx_eq_on</span>/<span class="mono">tx_eq_on</span>, <span class="mono">rx_eq</span>/<span class="mono">tx_eq</span>) each show their default, an example and the range. The EQ is 7 dB values low&rarr;high @ 250 500 900 1.4k 2k 2.8k 3.3k&nbsp;Hz; a good starting &ldquo;Voice&rdquo; preset is <span class="mono">0,0,2,3,2,0,-2</span>.</dd>
<dt>Tune it live</dt>
<dd>With a call up on the trunk, press <b>Start live preview</b> in the <em>Live audio preview</em> panel and adjust the fields &mdash; you hear each change <b>on the active call</b> as you type. <b>Stop</b> reverts the audio to the saved config; <b>Discard</b> also undoes your edits back to the saved values; <b>Save</b> writes them to the config for good (the next call reads them). An unattended preview auto-reverts after 30&nbsp;s, so you can never leave a link stuck on a half-tuned setting.</dd>
<dt>By hand</dt>
<dd>The same keys work directly in <span class="mono">pbx_sat.conf</span>, e.g. <span class="mono">tx_agc = yes</span>, <span class="mono">tx_lim_ceil = 30000</span>, <span class="mono">tx_eq_on = yes</span>, <span class="mono">tx_eq = 0,0,2,3,2,0,-2</span>. Changes take effect on the next call &mdash; no reload needed.</dd>
</dl>
</div>
</div>
<div class="tab-section d-none" id="tab-admin">
<div class="panel">
<h5>For Administrators</h5>
<dl>
<dt>Accounts</dt>
<dd>Manage user accounts — edit details, ban/lock/unlock, set admin levels, reset passwords, delete accounts. Click Edit on an account to manage that user's nodes and certificates.</dd>
<dt>Certificates</dt>
<dd>Manage node certificates. List pending CSRs (sign or reject), and list issued certificates with details, delete/revoke, or move a certificate back to pending for re-signing.</dd>
<dt>Control</dt>
<dd>Reload configuration, restart or shut down the reflector service.</dd>
<dt>Config</dt>
<dd>View and edit the reflector configuration file (svxreflector.conf). Save changes and reload the service to apply.</dd>
</dl>
</div>
</div>
<div class="panel">
<h5>Contact</h5>
<dd>For help or questions, contact the reflector administrator at <strong>bjorne@sa7aux.se</strong></dd>
</div>
</div>
<script src="help.js?v=20260720a" defer></script>
<footer style="text-align:center; padding:16px; color:rgba(0,255,255,.4); font-size:.75rem; border-top:1px solid rgba(0,255,255,.15);">
&copy; 2026 SA7AUX. All rights reserved.
</footer>
</body>
</html>