Be more sane with by-id aliases

This commit is contained in:
Jack Kingsman
2026-03-31 20:47:10 -07:00
parent 8446d99df1
commit b52431616e
3 changed files with 60 additions and 23 deletions

View File

@@ -107,6 +107,8 @@ Source checkouts expect a normal frontend build in `frontend/dist`.
Local Docker builds are architecture-native by default. On Apple Silicon Macs and ARM64 Linux hosts such as Raspberry Pi, `docker compose build` / `docker compose up --build` will produce an ARM64 image unless you override the platform.
For serial-device passthrough, use rootful Docker. In practice that usually means starting the stack with `sudo docker compose ...` unless your Docker daemon is already configured for rootful access via your user/group. Rootless Docker has been observed to fail on serial-device mappings even when the compose file itself is correct.
Create a local `docker-compose.yml` in one of two ways:
1. Copy the example file and edit it by hand:
@@ -128,7 +130,7 @@ The guided Docker flow can collect BLE settings, but BLE access from Docker stil
Then customize the local compose file for your transport and launch:
```bash
docker compose up # -d for background once you validate it's working
sudo docker compose up # add -d for background once you validate it's working
```
The database is stored in `./data/` (bind-mounted), so the container shares the same database as the native app.
@@ -136,8 +138,8 @@ The database is stored in `./data/` (bind-mounted), so the container shares the
To rebuild after pulling updates:
```bash
docker compose pull
docker compose up -d
sudo docker compose pull
sudo docker compose up -d
```
The example file and setup script default to the published Docker Hub image. To build locally from your checkout instead, replace:
@@ -155,7 +157,7 @@ build: .
Then run:
```bash
docker compose up -d --build
sudo docker compose up -d --build
```
The container runs as root by default for maximum serial passthrough compatibility across host setups. On Linux, if you switch between native and Docker runs, `./data` can end up root-owned. If you do not need that serial compatibility behavior, you can enable the optional `user: "${UID:-1000}:${GID:-1000}"` line in `docker-compose.yml` to keep ownership aligned with your host user.
@@ -163,7 +165,7 @@ The container runs as root by default for maximum serial passthrough compatibili
To stop:
```bash
docker compose down
sudo docker compose down
```
## Standard Environment Variables

View File

@@ -12,12 +12,14 @@ services:
volumes:
- ./data:/app/data
################################################
# Map your radio by stable device ID if available. #
################################################
#####################################################################
# Map your radio by stable device ID if available. #
# If your by-id path contains ':' characters, Docker Compose cannot #
# represent it here directly; use a colon-free host alias instead. #
# (e.g. /dev/ttyUSB0) #
#####################################################################
devices:
- source: /dev/serial/by-id/your-meshcore-radio
target: /dev/meshcore-radio
- /dev/serial/by-id/your-meshcore-radio:/dev/meshcore-radio
environment:
MESHCORE_DATABASE_PATH: data/meshcore.db

View File

@@ -32,6 +32,7 @@ SNAKEOIL_KEY_CONTAINER_PATH="/app/certs/$SNAKEOIL_KEY_BASENAME"
IMAGE_MODE="image"
TRANSPORT_MODE="serial"
SERIAL_HOST_PATH="/dev/ttyACM0"
SERIAL_COMPOSE_HOST_PATH="/dev/ttyACM0"
SERIAL_CONTAINER_PATH="/dev/meshcore-radio"
TCP_HOST=""
TCP_PORT="4000"
@@ -98,6 +99,35 @@ yaml_quote() {
printf "'%s'" "$value"
}
normalize_serial_host_path_for_compose() {
local selected_path="$1"
local resolved_path=""
if [[ "$selected_path" != *:* ]]; then
SERIAL_COMPOSE_HOST_PATH="$selected_path"
return 0
fi
resolved_path="$(readlink -f "$selected_path" 2>/dev/null || true)"
if [ -z "$resolved_path" ]; then
echo -e "${RED}Error:${NC} the selected serial path contains ':' and could not be resolved to a raw /dev/tty-style device path."
echo "Selected path: $selected_path"
echo "Please enter the raw serial device path instead (for example /dev/ttyACM0)."
exit 1
fi
if [[ "$resolved_path" == *:* ]]; then
echo -e "${RED}Error:${NC} the selected serial path still resolves to a path containing ':', which Docker Compose cannot use here."
echo "Selected path: $selected_path"
echo "Resolved path: $resolved_path"
echo "Please enter the raw serial device path instead (for example /dev/ttyACM0)."
exit 1
fi
echo -e "${YELLOW}Note:${NC} the selected serial path contains ':', so Docker Compose will use the resolved raw device path instead: ${resolved_path}"
SERIAL_COMPOSE_HOST_PATH="$resolved_path"
}
detect_primary_local_ip() {
local ip=""
local iface=""
@@ -275,7 +305,8 @@ case "$TRANSPORT_CHOICE" in
fi
fi
echo -e "${GREEN}Serial passthrough: ${SERIAL_HOST_PATH} -> ${SERIAL_CONTAINER_PATH}${NC}"
normalize_serial_host_path_for_compose "$SERIAL_HOST_PATH"
echo -e "${GREEN}Serial passthrough: ${SERIAL_COMPOSE_HOST_PATH} -> ${SERIAL_CONTAINER_PATH}${NC}"
;;
2)
TRANSPORT_MODE="tcp"
@@ -419,8 +450,7 @@ mkdir -p "$REPO_DIR/data"
fi
if [ "$TRANSPORT_MODE" = "serial" ]; then
echo " devices:"
echo " - source: $(yaml_quote "$SERIAL_HOST_PATH")"
echo " target: $(yaml_quote "$SERIAL_CONTAINER_PATH")"
echo " - ${SERIAL_COMPOSE_HOST_PATH}:${SERIAL_CONTAINER_PATH}"
fi
if [[ "$ENABLE_SNAKEOIL_TLS" =~ ^[Yy]$ ]]; then
echo " command:"
@@ -462,15 +492,18 @@ echo -e "${GREEN}Generated ${COMPOSE_FILE}.${NC}"
echo
echo -e "${BOLD}Docker commands${NC}"
if [ "$IMAGE_MODE" = "build" ]; then
echo " docker compose up -d --build # build the local image and start RemoteTerm in the background"
echo " sudo docker compose up -d --build # build the local image and start RemoteTerm in the background"
else
echo " docker compose up -d # start RemoteTerm in the background"
echo " sudo docker compose up -d # start RemoteTerm in the background"
fi
echo " docker compose logs -f # follow the container logs live"
echo " sudo docker compose logs -f # follow the container logs live"
echo
echo " docker compose down # stop and remove the running container"
echo " docker compose restart # restart the container without changing the image"
echo " docker compose pull && docker compose up -d # upgrade to the latest published image and restart"
echo " sudo docker compose down # stop and remove the running container"
echo " sudo docker compose restart # restart the container without changing the image"
echo " sudo docker compose pull && sudo docker compose up -d # upgrade to the latest published image and restart"
echo
echo -e "${YELLOW}Note:${NC} serial passthrough generally needs ${BOLD}rootful Docker${NC}."
echo "If Docker is running rootless on this host, serial-device mappings may fail even with a valid compose file."
if [ "$TRANSPORT_MODE" = "ble" ] || [ "$BLE_MANUAL_WARNING" = true ]; then
echo
echo -e "${RED}BLE requires more than the generated env vars.${NC}"
@@ -480,9 +513,9 @@ echo
echo -e "${GREEN}Your new docker file is ready at ${COMPOSE_FILE}.${NC}"
echo -e "${GREEN}Feel free to edit it by hand as desired, or:${NC}"
echo
echo -e "${PURPLE}┌──────────────────────────────────────────────┐${NC}"
echo -e "${PURPLE} Run ${GREEN}${BOLD}docker compose up -d${NC}${PURPLE} to get started. ${NC}"
echo -e "${PURPLE}└──────────────────────────────────────────────┘${NC}"
echo -e "${PURPLE}┌──────────────────────────────────────────────${NC}"
echo -e "${PURPLE}│ Run ${GREEN}${BOLD}sudo docker compose up -d${NC}${PURPLE} to get started. │${NC}"
echo -e "${PURPLE}└──────────────────────────────────────────────${NC}"
if [[ "$ENABLE_SNAKEOIL_TLS" =~ ^[Yy]$ ]]; then
echo
echo -e "After the container starts, open ${CYAN}https://${LOCAL_ACCESS_IP}:8000${NC}."
@@ -492,4 +525,4 @@ else
echo -e "After the container starts, open ${CYAN}http://${LOCAL_ACCESS_IP}:8000${NC}."
fi
echo "If the interface does not appear, follow the logs with:"
echo " docker compose logs -f"
echo " sudo docker compose logs -f"