Server Docker Image
MOAS-Server is published as a container image on GitHub Container Registry (GHCR):
ghcr.io/m1dst/moas-server
This image packages the native moas-server-cli binary and a Docker entrypoint that maps environment variables to CLI arguments.
What the image includes
Section titled “What the image includes”- Linux runtime image based on Ubuntu 24.04.
moas-server-clibinary at/app/moas-server-cli.- Built-in example configs:
/app/config/sample-config.moas/app/config/sample-network-config.moas
- Default exposed ports:
12059/tcpfor client command and control12059/udpfor client discovery
Supported image tags
Section titled “Supported image tags”The publish workflow pushes multiple tags to GHCR:
latest- Version tags from Git tags, for example
v2.1.0 - Commit SHA tags (
sha-*)
Use version tags in production for reproducible deployments.
Architecture support
Section titled “Architecture support”Published GHCR images are multi-architecture:
linux/amd64linux/arm64
So on ARM64 hosts (for example Raspberry Pi 64-bit or Apple Silicon Macs), docker pull ghcr.io/m1dst/moas-server:<tag> will automatically fetch the ARM64 variant.
Notes:
- Multi-arch images are created by the GitHub publish workflow using Buildx.
- On macOS, run with Docker Desktop. Network-based setups work normally; direct USB serial passthrough is typically not supported in Docker Desktop.
- There are no macOS-native container images; Mac runs the Linux image variant via Docker Desktop.
Pull the prebuilt image
Section titled “Pull the prebuilt image”docker pull ghcr.io/m1dst/moas-server:latestOr pin to a release:
docker pull ghcr.io/m1dst/moas-server:v2.0.0Quick start: simulation mode
Section titled “Quick start: simulation mode”Simulation mode is the safest first run because no physical switching occurs.
docker run --rm -it \ -e MOAS_SIM=true \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestRun with your own .moas file
Section titled “Run with your own .moas file”Mount your config directory and point MOAS_CONFIG at a file in the mount.
docker run --rm -it \ -v "$PWD/moas:/config:ro" \ -e MOAS_CONFIG=/config/2x6.moas \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestRun with USB serial hardware (Linux host)
Section titled “Run with USB serial hardware (Linux host)”Pass through the serial device to the container.
docker run --rm -it \ --device=/dev/ttyUSB0:/dev/ttyUSB0 \ -e MOAS_CONFIG=/app/config/sample-config.moas \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestIf your config references a different serial device, update the .moas file accordingly.
Run with network-connected switch
Section titled “Run with network-connected switch”No device passthrough is needed when using TCP transport.
docker run --rm -it \ -v "$PWD/moas:/config:ro" \ -e MOAS_CONFIG=/config/2x6-network.moas \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestOr use the bundled template:
docker run --rm -it \ -e MOAS_CONFIG=/app/config/sample-network-config.moas \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestExample Switches block for TCP transport:
"Switches" : [ { "ID" : 1, "Transport" : "TCP", "Address" : "192.168.1.50", "TCPPort" : 12058 }]Address and TCPPort are the hardware switch endpoint (commonly 12058), not the MOAS server listen port.
Environment variables
Section titled “Environment variables”The Docker entrypoint maps these variables to CLI arguments:
MOAS_MODEdefaultrunMOAS_CONFIGdefault/app/config/sample-config.moasMOAS_LOG_LEVELdefaultinfoMOAS_SIMdefaultfalse(trueor1enables--sim)MOAS_DURATIONunset by default (if set, adds--duration <value>)
12059/udp: MOAS client discovery12059/tcp: MOAS client command and control
Expose only the ports your setup needs.
Passing CLI arguments directly
Section titled “Passing CLI arguments directly”If you pass arguments after the image name, the entrypoint executes moas-server-cli directly and ignores env-var defaults.
docker run --rm -it \ ghcr.io/m1dst/moas-server:latest \ validate /app/config/sample-config.moas info --simChecking logs
Section titled “Checking logs”Run in detached mode:
docker run -d \ --name moas-server \ -v "$PWD/moas:/config:ro" \ -e MOAS_CONFIG=/config/m1dst_tcp.moas \ -e MOAS_LOG_LEVEL=info \ -p 12059:12059/tcp \ -p 12059:12059/udp \ ghcr.io/m1dst/moas-server:latestThen inspect logs:
docker logs moas-serverOr follow logs live:
docker logs -f moas-serverA typical startup log looks like:
__ __ ___ _ ____ ___ ___| \/ | / _ \ / \ / ___| |_ _| |_ _|| |\/| | | | | | / _ \ \___ \ | | | || | | | | |_| | / ___ \ ___) | | | | ||_| |_| \___/ /_/ \_\ |____/ |___| |___|
Master Of Antenna Switching (MOAS)Developed by James Patterson, M1DST and Paul Young, K1XM.Version: v2.0.0
Loading configuration: /config/m1dst_tcp.moasConfiguration loaded.MOAS core running. Press Ctrl+C to stop.Stopped.
Read 3905 lines from configuration fileLinux TCP listener started on port 12059Switch 1 port 192.168.10.94:12058 is not connectedSwitch 1 port 192.168.10.94:12058 is connectedSwitch 1 port 192.168.10.94:12058 is operationalPortainer deployment
Section titled “Portainer deployment”If you are using Portainer and want to use a Stack, you can find an example below.
version: "3.8"
services:
moas-server:
# Override IMAGE in Portainer if needed.
image: ${IMAGE:-ghcr.io/m1dst/moas-server:latest}
container_name: moas-server
restart: unless-stopped
environment:
MOAS_MODE: "run"
# Network-switch default template.
MOAS_CONFIG: "/config/2x6-network.moas"
MOAS_LOG_LEVEL: "info"
MOAS_SIM: "false"
# Optional finite run for testing, for example "10".
MOAS_DURATION: ""
ports:
# MOAS client command/control
- "12059:12059/tcp"
# MOAS client discovery
- "12059:12059/udp"
volumes:
# Host path containing your .moas files.
- /opt/moas/config:/config:ro
# Optional serial passthrough (uncomment if using USB serial hardware).
# devices:
# - "/dev/ttyUSB0:/dev/ttyUSB0"
Default behaviour of the stack:
- Uses
ghcr.io/m1dst/moas-server:latest(override withIMAGEif needed) - Mounts
/opt/moas/config:/config:ro - Exposes
12059/tcpand12059/udp - Includes optional serial passthrough lines you can uncomment
Troubleshooting
Section titled “Troubleshooting”- Container exits immediately:
- Check
MOAS_MODEandMOAS_CONFIGvalues. - Run
docker logs <container>for startup errors.
- Check
- Clients cannot discover server:
- Ensure
12059/udpis published and allowed through firewall.
- Ensure
- Clients cannot connect:
- Ensure
12059/tcpis published and reachable.
- Ensure
- USB serial hardware not detected:
- Confirm
--devicemapping and permissions on/dev/ttyUSB*.
- Confirm
- Config path errors:
- Verify host volume mount path and container path in
MOAS_CONFIG.
- Verify host volume mount path and container path in
Security and operations notes
Section titled “Security and operations notes”- Prefer pinned tags (
vX.Y.Z) overlatestin production. - Keep
.moasfiles mounted read-only when possible. - Use simulation mode before switching live hardware.
- Limit network exposure to trusted station networks.