-
Notifications
You must be signed in to change notification settings - Fork 6
Run the CONSOLE variant
Note
Some functionality will be made available from v26.3
dotnet .\JoinFS\bin\CONSOLE\net8.0\JoinFS-CONSOLE.dll --create --hub --hubname "CHOOSE A NAME" --nosim --nogui --background --whazzup-public --websocket --websocketport 8765 --comswebhookuri http://localhost/tsapi/usertochannel
The CONSOLE build is published automatically to Docker Hub as joinfs/joinfs-console on every push to main (:latest) and on every version tag (:1.2.3).
The image is based on Alpine Linux with the .NET 8 runtime — no simulator, no GUI, no UI translations. Roughly 100–120 MB.
docker run -d \
-p 6112:6112/udp \
-p 8765:8765 \
joinfs/joinfs-console:latest \
--hub \
--hubname "My Hub" \
--hubdomain "myhub.example.com" \
--nosim --nogui --background \
--whazzup \
--websocket --websocketport 8765 \
--localaddress 192.168.1.10All parameters described in the WebSocket Server and COM Frequency Webhook sections below apply. Additional hub/network parameters:
| Parameter | Description |
|---|---|
--hub |
Run as a hub (server) instead of a client |
--hubname <name> |
Public name for the hub |
--hubdomain <domain> |
Public hostname or IP clients use to connect |
--hubport <port> |
UDP port the hub listens on (default 6112) |
--nosim |
Run without a flight simulator connection |
--nogui |
Run without the desktop GUI |
--background |
Suppress console output |
--port <port> |
Local UDP port (default 6112) |
--localaddress <ip> |
Required in Docker. Set to the Docker host's LAN IP. Without this, clients on the same network as the host are routed via the container's internal bridge address and the handshake fails after 30 s. |
Inside a Docker bridge network the container's local address resolves to an internal IP (e.g. 172.17.0.2). JoinFS uses this address to route traffic to clients that share the same public IP as the hub. Passing --localaddress overrides it with the host's real LAN IP:
# Find your host's LAN IP on Linux:
JOINFS_LOCAL_ADDRESS=$(ip route get 1 | awk '{print $7; exit}')Drop JoinFS into an existing compose.yaml alongside TeamSpeak 3. All credentials go in a .env file (which should be in your .gitignore).
.env
JOINFS_HUB_DOMAIN=myhub.example.com
JOINFS_HUB_NAME=My Hub
JOINFS_LOCAL_ADDRESS=192.168.1.10
compose.yaml
services:
joinfs:
image: tuduce/joinfs-console:latest
env_file: .env
command:
- --hub
- --hubdomain
- "${JOINFS_HUB_DOMAIN}"
- --hubname
- "${JOINFS_HUB_NAME}"
- --nosim
- --nogui
- --background
- --whazzup
- --websocket
- --websocketport
- "8765"
- --localaddress
- "${JOINFS_LOCAL_ADDRESS}"
environment:
JOINFS_LOCAL_ADDRESS: ${JOINFS_LOCAL_ADDRESS}
ports:
- "6112:6112/udp"
- "8765:8765"
restart: unless-stoppedTo also push COM frequency changes to a TeamSpeak query API running in the same stack, add:
- --comswebhookuri
- "http://tsapi:8081/usertochannel"
- --comswebhookmethod
- PUTThe CONSOLE build includes an integrated WebSocket server that broadcasts live aircraft state to any connected client whenever something changes.
| Parameter | Default | Description |
|---|---|---|
--websocket |
(disabled) | Enable the WebSocket server |
--websocketport <port> |
8765 |
Port to listen on |
--websocketlog |
(disabled) | Log connection events, sent messages, and webhook calls to the monitor |
Connect to ws://<host>:<port>/ws/. The server tries to bind on all interfaces; if that requires elevated permissions on Windows, it falls back to localhost only. To allow remote access without running as admin:
netsh http add urlacl url=http://+:8765/ws/ user=Everyone
Sent whenever one or more aircraft change state (position, frequencies, lights, engines, etc.). Also sent once on first appearance. Sources are locally-connected sim aircraft and, when --whazzup-public is active, global hub users.
{
"type": "aircraft_update",
"aircraft": [
{
"callsign": "DAL123",
"nickname": "PlayerName",
"guid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"latitude": 51.476852,
"longitude": -0.461111,
"altitude": 35000,
"speed": 450.3,
"heading": 270,
"com1": "121.500",
"com2": "119.100",
"squawk": "2000",
"icaoType": "B738",
"from": "EGLL",
"to": "KJFK",
"rules": "IFR",
"route": "BCN UL9 ...",
"remarks": "",
"gear": 0,
"flaps": 0.000,
"lights": {
"nav": 1,
"beacon": 1,
"landing": 0,
"taxi": 0,
"strobe": 1
},
"engines": {
"eng1Running": true,
"eng2Running": true,
"eng3Running": false,
"eng4Running": false
},
"rotorRpm": 0.0
}
]
}| Field | Type | Unit / notes |
|---|---|---|
callsign |
string | ATC callsign from flight plan |
nickname |
string | JoinFS display name of the pilot |
guid |
string | Stable UUID identifying this pilot session |
latitude |
number | Degrees, 6 decimal places |
longitude |
number | Degrees, 6 decimal places |
altitude |
number | Feet MSL, rounded to the nearest foot |
speed |
number | Knots (ground speed), 1 decimal place |
heading |
integer | Degrees magnetic, 0–359 |
com1 / com2
|
string | Active COM frequency, e.g. "121.500"
|
squawk |
string | Transponder code, e.g. "2000"
|
icaoType |
string | ICAO aircraft type designator, e.g. "B738"
|
from / to
|
string | Departure / destination ICAO |
rules |
string |
"IFR" or "VFR"
|
route / remarks
|
string | Flight plan route and remarks |
gear |
integer |
1 = down/locked, 0 = up |
flaps |
number | Left trailing-edge flaps, 0.0–1.0 |
lights.nav |
integer |
1 = on, 0 = off |
lights.beacon |
integer |
1 = on, 0 = off |
lights.landing |
integer |
1 = on, 0 = off |
lights.taxi |
integer |
1 = on, 0 = off |
lights.strobe |
integer |
1 = on, 0 = off |
engines.eng1Running–eng4Running
|
boolean | Whether each engine is running |
rotorRpm |
number | Rotor RPM (helicopters), 1 decimal place |
The CONSOLE build can call an HTTP endpoint whenever a pilot changes their active COM1 or COM2 frequency. This is useful for integrating with TeamSpeak bots, Discord bots, or any other kind of radio-switching automation.
| Parameter | Default | Description |
|---|---|---|
--comswebhookuri <uri> |
(disabled) | URI to call on COM frequency changes (enables the webhook) |
--comswebhookmethod <method> |
PUT |
HTTP method: POST, PUT, PATCH, or GET
|
--websocketlog |
(disabled) | Log the outgoing request body and HTTP response code |
The body is sent as application/json. Multiple aircraft whose frequencies changed in the same polling cycle are batched into a single request.
{
"comsupdate": [
{
"callsign": "DAL123",
"nickname": "PlayerName",
"com1": "121.500",
"com2": "119.100"
}
]
}| Field | Type | Description |
|---|---|---|
callsign |
string | ATC callsign from flight plan |
nickname |
string | JoinFS display name of the pilot |
com1 |
string | New active COM1 frequency, e.g. "121.500"
|
com2 |
string | New active COM2 frequency, e.g. "119.100"
|
The webhook fires only on actual frequency changes — the first-seen state for each aircraft is recorded silently and no initial call is made.