-
Notifications
You must be signed in to change notification settings - Fork 0
OpenWrt Deployment
OpenWrt 25.12 is a production-oriented edge deployment environment for
aismixer and nmea_sproxy. The signed packages run the current Python
implementation as OpenWrt services managed by procd. This page covers
repository trust, architecture selection, storage planning, installation,
service lifecycle, endpoint identities, UDPSEC trust, and physical serial AIS
ingress.
The currently published package repositories are:
| OpenWrt version | Package architecture | Repository index |
|---|---|---|
| OpenWrt 25.12 | x86_64 |
https://aismixer.net/openwrt/25.12/x86_64/packages.adb |
| OpenWrt 25.12 | mips_24kc |
https://aismixer.net/openwrt/25.12/mips_24kc/packages.adb |
Both architectures use the same AISMixer repository signing key. Select only the repository whose package architecture matches the official OpenWrt feeds configured on the device.
| Item | Current published support |
|---|---|
| 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
|
The current packages do not provide a native C runtime, UCI integration, or OpenWrt multi-instance services. See Current package boundaries and planned work for that implemented/planned boundary.
Some tools report a broad machine architecture rather than the architecture used in package-feed paths. For example:
apk --print-archmay report mips, while the official OpenWrt package feeds configured for the
device use mips_24kc. Do not guess the AISMixer repository architecture from
apk --print-arch alone. Match the architecture segment used by the official
OpenWrt package feeds.
On OpenWrt 25.12, inspect the configured distribution feeds, for example:
grep '/packages/' /etc/apk/repositories.d/distfeeds.listIf that filter does not show enough context, inspect the file directly:
cat /etc/apk/repositories.d/distfeeds.list/etc/apk/repositories.d/distfeeds.list is the current OpenWrt 25.12 layout;
future OpenWrt releases may organize repository configuration differently.
The current OpenWrt packages use the Python implementation and dependencies that include cryptographic and serial libraries. Their installed footprint therefore requires materially more writable space than a minimal OpenWrt installation. Check the active root filesystem before installation:
df -h /Package installation writes into the active OpenWrt overlay. If internal writable storage is insufficient, extroot is a standard OpenWrt deployment option for placing that overlay on external storage. Extroot is not mandatory when the device already has sufficient writable space. When services depend on external storage, choose storage that is stable and available during boot.
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 repository trust material is:
- public key:
https://aismixer.net/openwrt/keys/aismixer-openwrt.pem; - public-key SHA-256:
170d30219e0e05d59898cd8ccd5ec9804e915df7882ab56b8e869ef6e99c8f9c.
The x86_64 and mips_24kc indexes listed above are both signed with this
key.
Run the following as root. It adds the AISMixer feed without replacing any
operator-defined custom repositories. Set AISMIXER_ARCH only after matching
it to the architecture used by the configured official feeds:
AISMIXER_ARCH='x86_64'
# or:
# AISMIXER_ARCH='mips_24kc'
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/${AISMIXER_ARCH}/packages.adb"
grep -qxF "$REPO_URL" "$REPO_FILE" 2>/dev/null || {
printf '\n# AISMixer OpenWrt 25.12 %s repository\n%s\n' \
"$AISMIXER_ARCH" "$REPO_URL" >> "$REPO_FILE"
}
apk update
apk add aismixerTo 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 station-side proxy package with:
apk add nmea_sproxyDo not use --allow-untrusted, and do not perform a blanket apk upgrade as
part of an AISMixer ecosystem 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. The current packages install 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 the aismixer service. 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 the aismixer service 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.
The current OpenWrt package 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 OpenWrt hosts.
-
UDPSEC endpoint identities for
aismixerandnmea_sproxyauthenticate 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 the
aismixer service 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 proxy process represents one local input to one network output. See Secure UDP and nmea_sproxy for configuration and transport details.
The original no-routing behavior of aismixer 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.
nmea_sproxy supports physical serial input, including USB virtual serial
devices exposed by the operating system. It consumes a serial device path
through pySerial; it does not implement USB device drivers.
Common device classes are:
| Connection | Typical serial device | Driver boundary |
|---|---|---|
| Native UART |
/dev/ttyS* or another platform-specific TTY path |
Platform UART support |
| USB CDC ACM | /dev/ttyACM* |
CDC ACM kernel support |
| USB-UART adapter such as FTDI, CP210x, or CH34x | /dev/ttyUSB* |
Chipset-appropriate USB-serial kernel support |
Use the actual device path discovered on the system. /dev/ttyACM0 in this
example is not a universal or persistent 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: 4096The driver required for a serial endpoint may be built into the OpenWrt
kernel, already installed as a kernel module, or available through the matching
OpenWrt kmod package. A device with USB ports does not necessarily include
CDC ACM support in its installed image.
For a CDC ACM receiver, check whether the package is installed:
apk info -e kmod-usb-acmIf CDC ACM support is needed, is not already built in or installed, and the matching OpenWrt feed provides it, install:
apk add kmod-usb-acmWhen the matching driver is available, OpenWrt hotplug and kmodloader normally
handle module loading and device binding automatically. Manual boot-time
modprobe commands are not part of the normal setup.
kmod-usb-acm is conditional hardware support, not a mandatory
nmea_sproxy dependency. UDP input and native UART input do not require it.
USB-UART devices using FTDI, CP210x, CH34x, or another chipset require their
matching OpenWrt driver when that support is not already present.
/dev/ttyACM0 or /dev/ttyUSB0 is the serial character device presented
through the Linux TTY layer. /dev/serial/by-id/... is a persistent
userspace-created alias commonly available on full Linux distributions, but
OpenWrt does not guarantee that this alias exists. Inspect what the kernel and
hotplug system actually created:
dmesg | tail -n 30
logread | tail -n 30
ls -l /dev/ttyACM* /dev/ttyUSB* 2>/dev/nullNumbering such as ttyACM0 versus ttyACM1, or ttyUSB0 versus ttyUSB1, is
not inherently persistent when several similar devices are attached. Confirm
the mapping after hardware or boot-order changes.
Because pySerial is already part of the nmea_sproxy serial deployment, it is
the preferred bounded raw-input check. Substitute the actual device path:
python3 - <<'PY'
import serial
ser = serial.Serial(
port="/dev/ttyACM0",
baudrate=38400,
bytesize=8,
parity="N",
stopbits=1,
timeout=2.0,
)
for _ in range(20):
line = ser.readline()
if line:
print(line.decode("ascii", errors="replace").rstrip())
ser.close()
PY/dev/ttyACM0 is only an example. Use the device path discovered on the
system. 38400 8N1 (38400 baud, 8 data bits, no parity, and one stop bit) is a
common AIS/NMEA serial configuration, but the receiver's own configuration is
authoritative. Seeing !AIVDM or !AIVDO data verifies the receiver, TTY, and
pySerial path independently of nmea_sproxy.
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 optional diagnostic tooling, not a runtime dependency.
pySerial configures the endpoint used by nmea_sproxy.
If a physical receiver uses a vendor-specific USB protocol and the operating
system does not expose it as a serial TTY device, the current
nmea_sproxy pySerial input cannot consume that device directly. Such hardware
requires either an appropriate operating-system or kernel driver that exposes
a serial endpoint, or a future separate input backend.
On resource-constrained OpenWrt systems, cold-starting Python, loading modules
from flash or extroot, and importing cryptographic and parser dependencies may
make aismixer, nmea_sproxy, or aismixerctl take a few seconds to begin
execution. This is startup and import latency. Long-running daemon services do
not pay that startup cost for each AIS packet, and page cache may make later
launches faster. This observation is not a throughput or capacity benchmark.
The published OpenWrt 25.12 mips_24kc package path has been functionally and
operationally validated end to end with:
physical AIS serial source
-> nmea_sproxy
-> authenticated mutual-ECDHE UDPSEC
-> aismixer UDPSEC ingress
-> processing
-> egress
-> aismixerctl runtime control and statistics
-> procd service operation
The validation also demonstrated bounded ingress, processing, and egress
operation without observed processing failures or queue backpressure during
the validation run. This was functional and operational validation, not a
controlled throughput or capacity benchmark, and it does not guarantee
performance for every mips_24kc system.
The following commands answer the usual post-install questions:
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 ecosystem 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 applicable installed AISMixer ecosystem packages:
apk update
apk add --upgrade aismixer
apk add --upgrade nmea_sproxyRun only the package commands relevant to the OpenWrt host. 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 ecosystem update procedure.
The current packages provide:
- signed OpenWrt APK packages;
- procd lifecycle integration;
- the local configuration and key layout documented above;
- independent installation of
aismixerandnmea_sproxy; - one singleton OpenWrt
nmea_sproxyservice; and - safe UDPSEC startup preflight before the runtime is launched.
Future work may introduce UCI integration, named multiple nmea_sproxy procd
instances, and OpenWrt-oriented configuration integration. No such behavior,
syntax, or service model is implemented or promised. The conventional-Linux
nmea_sproxy@name systemd model will not simply be copied to OpenWrt; any
multi-instance design will require a separately defined OpenWrt-specific model.
- 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