Running Meshtastic via Docker Compose

There are a few ways to run the Meshtastic Firmware. There is no real right or wrong answer as to how you run it, more just the best way to run it for a given use-case. Whenever I have a node that has internet access, a good location, and power, I like to run the firmware using Docker. The main reason for this is that it allows me to quickly move configurations and node data from one piece of hardware to another really quickly. It also allows me to quickly test out new versions of the firmware without absolutely destroying a "production-ready" node. It also gives you some specific benefits such as bridging 2 modem presets using a single hardware host.

I have some other posts on this website that cover Docker, such as the Meshtastic Bridging post. For this post I'll more be discussing a more simplistic setup with just one radio interface that we're passing through into docker. Please note that this write-up assumes that your node utilizes some form of Raspberry Pi hardware as a host. If you use some other hardware (such as more traditional desktop PC or other SBC), your mileage may vary.

If you want to skip the explanation below, here's the template Docker Compose file that you can also download here:

services:
  meshtasticd:
    image: meshtastic/meshtasticd:alpha-debian
    container_name: meshtasticd
    devices:
      # SPI DEVICES
      - "/dev/spidev0.0"
      - "/dev/gpiochip0"
      # I2C DEVICES (OPTIONAL)
      - "/dev/i2c-1:/dev/i2c-1"
      # USB DEVICES
      - "/dev/bus/usb/001:/dev/bus/usb/001" # replace 001 using the output of lsusb
    ports:
      - 4403:4403
    # Required for SPI
    cap_add:
      - SYS_RAWIO
    # Required for USB
    group_add:
      - "plugdev"
    volumes:
      - ./meshtasticd:/var/lib/meshtasticd
      - ./config.yml:/etc/meshtasticd/config.yaml:ro
    restart: unless-stopped

Figuring Out Your Hardware

There are a few different examples of radio hardware that you can pass into your Docker containers. They work on 1 of 2 hardware interfaces: USB or SPI. SPI Devices (such as WeHooper4's designs) plug into the Raspberry Pi using GPIO headers while USB devices plut into the USB ports. Whatever hardware you choose will require a different set of instructions.

Finding Your USB Device

To find the path of your USB radio, you'll need to run a few commands in your terminal. All of the following commands work on a Raspberry Pi 3B+ and Raspbery Pi 4. I can't promise they'll work on a Mac or PC though, so your mileage may vary.

  1. Plug in your USB radio to your Raspberry Pi

  2. run lsusb and look for a device matching your manufacturer. I've used a MeshToad in the past and typically look for a manufacturer that looks like this:

Bus 001 Device 007: ID 1a86:5512 QinHeng Electronics CH341 in EPP/MEM/I2C mode, EPP/I2C adapter
  1. Write down the bus number and device number from the lsusb command. From the example above, it would be 001 for the bus and 007 for the device.

  2. Run ls /dev/bus/usb/{USB Bus Number} to make sure that your device number shows up here.

  3. Modify your docker-compose.yml and pass in the full path of your USB device into the container. You can pass in the entire USB bus directory, but I do recommend passing in the direct path if you can help it. ESPECIALLY if you're using 2 USB radios at the same time.

  4. Start your docker containers and test for connectivity.

Finding your SPI Device

SPI is a bit easier than USB devices. Here's what you have to do:

  1. Make sure SPI is enabled by running sudo raspi-config and going to Interface Options and enabling SPI.

  2. Power down your Pi and install the radio hat.

  3. Boot the Raspberry Pi back up and check that you have a directory for the SPI device by running ls /dev/spidev* It should be spidev0.0 or spidev0.1. You can also run modprobe spidev to see if it's showing up properly. For what it's worth, 99.999% of the time for me it's spidev0.0.

  4. Pass this device path into the docker container. You will need to enable additional permissions as well. See the example above.

  5. Start your container and test.

Setting Up The Node Config.yml

This part is the trickiest. Each radio interface is different and has a different pinout. I typically use wehooper4's hardware and he has all of this YAML configurations listed on his GitHub. I won't even post the full lora config example here as it varies too much from hardware to hardware and if you don't utilize the config specific to your radio, you may let out the machine spirit magic smoke.

I'll just say that whenever you get that configuration saved to your local machine, you'll want to save it to the local machine and pass it in as a volume to /etc/meshtasticd/config.yaml:ro as read-only (hence the :ro at the end there).

Apart from the lora config, I typically include some additional parameters:

Logging:
  LogLevel: info # debug, info, warn, error

I2C:
  I2CDevice: /dev/i2c-1 # optional, only if you have an i2c device such as GPS or env sensors

General:
  MaxNodes: 200
  MaxMessageQueue: 100
  MACAddress: AA:BB:CC:DD:EE:FF