-
Notifications
You must be signed in to change notification settings - Fork 0
OpenWrt Deployment
OpenWrt R2 is the current packaged deployment path for running AISMixer and
nmea_sproxy as native OpenWrt services. This page covers the published
operator interface: repository trust, installation, package layout,
configuration, service lifecycle, endpoint identities, and UDPSEC trust
provisioning.
| Item | Current published support |
|---|---|
| OpenWrt release | OpenWrt 25.12 |
| Published target | x86_64 only |
| Repository format | Signed APK v3 repository |
| Published package version |
0.2.0-r2 for all three packages |
| Runtime implementation | Python |
| Service manager | procd through /etc/init.d scripts |
| Distribution | Signed public repository at aismixer.net
|
x86_64 is the first published and validated OpenWrt target, and all three published APK manifests identify their architecture as x86_64. The current Python-and-shell payload is not inherently x86-specific, but no ARM, AArch64, or MIPS repository is published or supported yet. Do not use the x86_64 feed on another architecture.
R2 does not provide a native C runtime, UCI integration, or OpenWrt multi-instance services. The published packages were validated through signed repository, clean-install, reboot, plain-UDP, serial, and UDPSEC runtime acceptance; this page documents the resulting operator interface rather than the release-validation history.
The repository contains three packages:
| Package | Purpose | Direct shared dependency |
|---|---|---|
aismixer-common |
Shared Python runtime modules, key tooling, and common utilities | Python 3 |
aismixer |
Mixer/router service, UDPSEC server support, and aismixerctl
|
aismixer-common |
nmea_sproxy |
One station-side UDP or serial input to one UDPSEC or explicit plain-UDP output | aismixer-common |
aismixer and nmea_sproxy may be installed independently. APK resolves
aismixer-common and the other required Python dependencies automatically;
operators normally do not install aismixer-common directly.
The package recipe installs these important paths.
/usr/bin/aismixer
/usr/bin/aismixerctl
/usr/lib/aismixer/...
/etc/init.d/aismixer
/etc/aismixer/config.yaml
/etc/aismixer/udp_alias_map.yaml
/etc/aismixer/authorized_keys.yaml
/etc/aismixer/keys/
/usr/bin/nmea_sproxy
/usr/lib/aismixer/nmea_sproxy/...
/etc/init.d/nmea_sproxy
/etc/nmea_sproxy/config.yaml
/etc/nmea_sproxy/keys/
Shared modules are installed below /usr/lib/aismixer/core/; the shared key
tool is /usr/lib/aismixer/tools/aismixer_keys.py.
The public repository endpoints are:
- public key:
https://aismixer.net/openwrt/keys/aismixer-openwrt.pem; - public-key SHA-256:
170d30219e0e05d59898cd8ccd5ec9804e915df7882ab56b8e869ef6e99c8f9c; - OpenWrt 25.12 x86_64 repository:
https://aismixer.net/openwrt/25.12/x86_64/packages.adb.
Run the following as root. It adds the AISMixer feed without replacing any
operator-defined custom repositories:
wget -O /etc/apk/keys/aismixer-openwrt.pem \
https://aismixer.net/openwrt/keys/aismixer-openwrt.pem
chmod 0644 /etc/apk/keys/aismixer-openwrt.pem
REPO_FILE=/etc/apk/repositories.d/customfeeds.list
REPO_URL='https://aismixer.net/openwrt/25.12/x86_64/packages.adb'
grep -qxF "$REPO_URL" "$REPO_FILE" 2>/dev/null || {
printf '\n# AISMixer OpenWrt 25.12 x86_64 repository\n%s\n' \
"$REPO_URL" >> "$REPO_FILE"
}
apk updateTo compare the downloaded key with the published value, run:
sha256sum /etc/apk/keys/aismixer-openwrt.pem/etc/apk/keys/ is the package-manager trust store used here. Once this
public key is trusted, APK signatures authenticate the repository and package
artifacts. Downloading the key and checking its fingerprint from the same
HTTPS origin is a useful identity and integrity check, but it is not an
independent second trust channel or stronger authentication than the HTTPS
bootstrap itself.
Install the mixer/router package with:
apk add aismixerInstall the station-side proxy package with:
apk add nmea_sproxyDo not use --allow-untrusted, and do not perform a blanket apk upgrade as
part of AISMixer installation.
The OpenWrt configuration and identity layout is:
| Service | Path | Package treatment |
|---|---|---|
| AISMixer | /etc/aismixer/config.yaml |
Declared conffile |
| AISMixer | /etc/aismixer/udp_alias_map.yaml |
Declared conffile |
| AISMixer | /etc/aismixer/authorized_keys.yaml |
Declared conffile |
| AISMixer | /etc/aismixer/keys/ |
Empty directory installed; identity generated locally; no private key packaged |
nmea_sproxy |
/etc/nmea_sproxy/config.yaml |
Declared conffile |
nmea_sproxy |
/etc/nmea_sproxy/keys/ |
Empty directory installed; identity and trust material generated or provisioned locally |
The declared conffiles are operator-managed configuration and are intended to survive package upgrades. Endpoint private keys and trusted peer material are created or provisioned locally and must not be replaced merely because a package is upgraded.
Use the packaged files as starting points rather than copying large examples from this Wiki:
OpenWrt does not use the systemd installation path documented for conventional Linux. R2 installs these procd services:
/etc/init.d/aismixer
/etc/init.d/nmea_sproxy
OpenWrt's package post-install handling enables and attempts to start each
installed service. Consequently, apk add aismixer normally prepares the
mixer identity and launches AISMixer. With the packaged UDPSEC proxy
configuration, apk add nmea_sproxy prepares the station identity but safely
leaves the runtime stopped when its required peer key has not been provisioned;
the package installation itself still succeeds.
Enable and manage AISMixer with:
/etc/init.d/aismixer enable
/etc/init.d/aismixer start
/etc/init.d/aismixer status
/etc/init.d/aismixer restartEnable and manage the station proxy with:
/etc/init.d/nmea_sproxy enable
/etc/init.d/nmea_sproxy start
/etc/init.d/nmea_sproxy status
/etc/init.d/nmea_sproxy restartBoth init scripts send runtime standard output and error to OpenWrt logging and register a procd respawn policy after successful startup preparation.
Before registering the runtime with procd, the AISMixer init script:
- creates
/etc/aismixer/keys/and/run/aismixer; - creates the local server identity when both identity files are absent, or repairs the derived public key from an existing private key; and
- refuses an incomplete public-only identity instead of replacing it with a new private identity.
The packaged default configuration enables the local control socket at
/run/aismixer/control.sock, and the operator command is
/usr/bin/aismixerctl. See Runtime Routing Control
for control semantics and authorization boundaries.
OpenWrt R2 provides one singleton nmea_sproxy service using
/etc/nmea_sproxy/config.yaml. It does not provide the conventional-Linux
nmea_sproxy@name systemd template model.
Before registering the runtime with procd, its init script:
- verifies that the configuration file exists;
- creates or repairs the local station identity without replacing an existing private key;
- loads and validates the runtime configuration; and
- for UDPSEC output, verifies that the configured peer public key exists, is readable, and is a valid public key.
Only a runtime that passes this preparation is registered with procd. Genuine runtime failures after launch may therefore use procd respawn; a missing UDPSEC trust anchor is handled before launch.
Two unrelated trust domains are involved:
- APK repository signing identity authenticates repository and package artifacts to APK after the repository public key is trusted. Its private key is not shipped to routers.
- AISMixer/UDPSEC endpoint identities authenticate the mixer and station to each other. Their private keys are generated locally on the OpenWrt host.
The exact endpoint identity files are:
| Endpoint | Private identity | Derived public identity |
|---|---|---|
| AISMixer | /etc/aismixer/keys/aismixer_private.pem |
/etc/aismixer/keys/aismixer_public.pem |
nmea_sproxy station |
/etc/nmea_sproxy/keys/station_private.pem |
/etc/nmea_sproxy/keys/station_public.pem |
Private key files remain local. When a valid private key exists, the init scripts preserve it and use the key tool to repair a missing, invalid, or mismatched derived public key. If only the public identity exists, startup refuses to generate a replacement private identity. This prevents an incomplete state from silently changing endpoint identity.
The current init scripts do not select an alternate procd user, so they run in
OpenWrt's default root service context. They set each endpoint key directory
to mode 0700; the key tool sets private keys to 0600 and derived public
keys to 0644.
Local identity generation does not establish peer trust. For one
nmea_sproxy to AISMixer UDPSEC relation, provision both directions through a
trusted operator-controlled channel.
Copy only the mixer public identity from:
/etc/aismixer/keys/aismixer_public.pem
to the path configured as remote_public_key on the station. The packaged
default is:
/etc/nmea_sproxy/keys/aismixer_public.pem
Never copy the AISMixer private identity to the station.
The first nmea_sproxy start prepares the station identity before checking for
the UDPSEC peer key. If that peer key is not provisioned yet, the new station
identity remains in place while the runtime safely stays stopped. After the
station private identity exists, the OpenWrt-installed key tool can repair its
public key if needed and print the compressed base64 value required by
AISMixer:
/usr/bin/python3 /usr/lib/aismixer/tools/aismixer_keys.py station \
--keys-dir /etc/nmea_sproxy/keys \
--station-id boat_001 \
--repair-publicReplace boat_001 with the station_id in
/etc/nmea_sproxy/config.yaml. Add the printed value to
/etc/aismixer/authorized_keys.yaml:
authorized_clients:
- name: boat_001
pubkey: <compressed-public-key-base64>name must exactly match the proxy's configured station_id. Restart
AISMixer after changing its authorization file, then start or restart
nmea_sproxy:
/etc/init.d/aismixer restart
/etc/init.d/nmea_sproxy restartTrust material is never fetched, enrolled, or exchanged automatically. See the
canonical nmea_sproxy key and trust guide
for the full operator workflow.
When UDPSEC output is configured and remote_public_key is missing or cannot
be read, the init script logs:
UDPSEC peer public key not provisioned; service not started: <path>
When the file is invalid or cannot be loaded as a public key, it logs:
UDPSEC peer public key invalid or unreadable; service not started: <path>
The runtime is intentionally not launched in either case. This prevents procd from repeatedly respawning a process that cannot establish trust. Package installation may therefore be successful while the proxy runtime is correctly stopped and waiting for peer trust. Provision the AISMixer public key, then start or restart the service.
An explicit plain-UDP output does not require the UDPSEC peer public key. The OpenWrt init script still prepares the local station identity before its general runtime-readiness check, but the plain-UDP runtime does not load or use UDPSEC peer trust.
nmea_sproxy accepts two first-class input types:
- UDP input, either through an explicit
input.type: udpmapping or the backward-compatible top-level form whereinput:is omitted; and - serial or USB virtual serial input through
input.type: serial.
UDP input is not deprecated and is not a legacy input type. Only its omitted
input: top-level configuration form is described as backward-compatible.
The output types are:
- UDPSEC, through explicit
output.type: udpsecor the legacy, backward-compatible top-levelremote_host/remote_portform; and - explicit plain UDP through
output.type: udp, for a trusted LAN, VPN, or equivalent external security boundary.
Each R2 proxy process still represents one local input to one network output. See Secure UDP and nmea_sproxy for configuration and transport details.
AISMixer's original no-routing behavior remains legacy broadcast mode. It is supported and backward-compatible, not deprecated. Routing mode instead uses named targets and target-scoped deduplication. See Routing Engine; OpenWrt packaging does not change those semantics.
Serial input uses a normal device path. /dev/ttyACM0 is one example, not a
universal path:
input:
type: serial
port: /dev/ttyACM0
baudrate: 38400
bytesize: 8
parity: N
stopbits: 1
read_timeout: 1.0
reconnect_delay: 5
max_line_bytes: 4096A USB virtual serial receiver may need an OpenWrt kernel driver before a
/dev/tty* device appears. For a USB CDC ACM device, install:
apk add kmod-usb-acmAfter the driver loads and binds, a CDC ACM device typically appears as
/dev/ttyACM0, /dev/ttyACM1, and so on. Check recent kernel messages and
device nodes with:
dmesg | tail -n 30
ls -l /dev/ttyACM* 2>/dev/nullA successful binding can look like:
cdc_acm 1-1:1.0: ttyACM0: USB ACM device
kmod-usb-acm is hardware-specific, not a universal nmea_sproxy runtime
requirement or package dependency. UDP input does not need it, a native UART
does not need it, and USB-to-serial devices using other chipsets may require
their own OpenWrt kernel driver instead.
OpenWrt images may omit stty. For optional serial diagnostics, install:
apk add coreutils-sttyThen inspect the endpoint, for example:
stty -F /dev/ttyACM0 -acoreutils-stty is diagnostic tooling only. nmea_sproxy does not require it
because pySerial configures the serial endpoint itself. A common AIS NMEA 0183
high-speed serial configuration is 38400 baud, 8 data bits, no parity, and one
stop bit, but the operator must use the receiver manufacturer's specified
settings.
Because python3-pyserial is already an nmea_sproxy package dependency, an
operator can test the exact device path with a bounded read before starting the
service:
python3 - <<'PY'
import time
import serial
with serial.Serial(
"/dev/ttyACM0",
baudrate=38400,
bytesize=8,
parity="N",
stopbits=1,
timeout=1,
) as s:
print("opened:", s.name, flush=True)
total = 0
deadline = time.monotonic() + 15
while time.monotonic() < deadline:
data = s.read(512)
if data:
total += len(data)
print(repr(data), flush=True)
print("total bytes:", total)
PYSeeing !AIVDM or !AIVDO data verifies the receiver to kernel driver to
/dev/tty* to pySerial path independently of nmea_sproxy.
One real-hardware acceptance unit identified as USB VID:PID 27c5:0602,
manufacturer SRT Marine Technology Ltd., and product AIS Virtual COM Port.
It exposed CDC ACM interfaces and OpenWrt bound it through cdc_acm as
/dev/ttyACM0.
During this EM-Trak/SRT AIS Virtual COM Port test, the device enumerated successfully on one USB 3 host port but produced no serial data. Reading the COM port directly under Windows reproduced the symptom. Moving the receiver to a USB 2 port restored AIS data immediately. This is one observed hardware/host-controller compatibility case, not a general requirement for EM-Trak, SRT, CDC ACM, USB 3, or OpenWrt systems.
For this specific acceptance unit, the completed R2 real-hardware test directly
observed the full path: physical EM-Trak AIS receiver -> USB CDC ACM -> OpenWrt
/dev/ttyACM0 -> pySerial / nmea_sproxy -> authenticated UDPSEC -> AISMixer ->
processing -> UDP egress.
The following commands answer the usual post-install questions without reproducing the R2 release-acceptance sequence:
apk list -I | grep -E '^(aismixer|nmea_sproxy)-'
/etc/init.d/aismixer status
/etc/init.d/nmea_sproxy status
logread -e aismixer
logread -e nmea_sproxy
ls -l /run/aismixer/control.sock
aismixerctl statusInterpret them as follows:
-
apk list -Ishows which AISMixer packages are installed; - the init scripts report current procd service state;
-
logreadshows startup, identity, preflight, and runtime messages; - the socket listing confirms whether the configured local control socket exists; and
-
aismixerctl statusconfirms that the enabled control socket responds.
If the station log contains one of the safe-preflight messages above, complete
peer-trust provisioning and start the service again. A disabled control socket
is a valid operator configuration; in that case, the socket and
aismixerctl status checks are not expected to succeed.
Leave the repository URL in customfeeds.list, refresh package metadata, and
target only the installed AISMixer package or packages:
apk update
apk add --upgrade aismixer
apk add --upgrade nmea_sproxyRun only the package commands relevant to the router. APK resolves updates to
aismixer-common as a dependency. For a UDPSEC relation, keep both endpoints
on compatible runtime versions and restart the affected services after the
targeted package update.
Declared conffiles are intended to retain operator configuration. Endpoint
identity files are locally generated rather than package payload and must not
be replaced during an upgrade. Review package-manager messages and the
effective configuration before restarting. Do not use a global apk upgrade
as an AISMixer update procedure.
R2 provides:
- native OpenWrt packages in a signed repository;
- procd lifecycle integration;
- the local configuration and key layout documented above;
- independent installation of AISMixer and
nmea_sproxy; - one singleton OpenWrt
nmea_sproxyservice; and - safe UDPSEC startup preflight before the runtime is launched.
R3 is future work. It may introduce UCI integration, named multiple
nmea_sproxy procd instances, and router-oriented configuration integration.
No R3 behavior, syntax, or service model is implemented or promised here. The
conventional-Linux nmea_sproxy@name systemd model will not simply be copied
to OpenWrt; any multi-instance design will use an OpenWrt-native model defined
by that future work.
- Quick Start
- Installation and Operations
- OpenWrt Deployment
- Configuration and Examples
- Inputs and Outputs
- Architecture Overview
- Data Representation, Processor, and Runtime Boundary
- Processing and Routing Model
- State, Lifecycle, and Limits
- Multipart NMEA Assembly
- TAG Handling
- Deduplication
- Routing Engine
- Behavioural Contract
- Native-Ready Reference Foundation