Setting Up an MQTT Server for Meshtastic

Setting Up an MQTT Server for Meshtastic
Photo by Simona Sergi / Unsplash

MQTT (Message Queuing Telemetry Transport) extends your Meshtastic mesh network beyond radio range. By connecting a node to an MQTT broker, messages can travel over the internet, bridging geographically separated meshes or enabling remote monitoring and integration with other systems.

This guide walks through deploying your own MQTT broker using Mosquitto, configuring it for Meshtastic, and connecting your nodes.

Why Run Your Own MQTT Server

Meshtastic provides public MQTT infrastructure at mqtt.meshtastic.org, which works well for getting started. However, running your own server offers advantages:

  • Control: Your data stays on infrastructure you manage
  • Reliability: No dependency on third-party service availability
  • Privacy: Messages traverse only servers you trust
  • Customization: Configure retention, access controls, and integrations as needed
  • Integration: Direct access for building automation, alerts, and logging

Prerequisites

You'll need:

  • A Linux server with a public IP address (VPS from DigitalOcean, Linode, or similar works well)
  • A domain name pointing to your server (optional but recommended for TLS)
  • Root/sudo access
  • Basic familiarity with Linux command line

Installing Mosquitto

Mosquitto is the most widely-used open-source MQTT broker. On Ubuntu/Debian:

sudo apt update
sudo apt install mosquitto mosquitto-clients

Verify the installation:

mosquitto -v

The service starts automatically but isn't yet configured for external access.

Basic Configuration

Mosquitto's main configuration file is /etc/mosquitto/mosquitto.conf. The default configuration only listens on localhost, which is secure but not useful for Meshtastic nodes connecting over the internet.

Edit the configuration:

sudo nano /etc/mosquitto/mosquitto.conf

Add these lines:

# Allow connections from any network interface
listener 1883 0.0.0.0

# Allow anonymous connections (we'll secure this later)
allow_anonymous true

# Persistence for retained messages
persistence true
persistence_location /var/lib/mosquitto/

# Logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type all

What this does:

  • listener 1883 0.0.0.0 - Listen on port 1883 on all network interfaces
  • allow_anonymous true - Accept connections without authentication (temporary for testing)
  • persistence true - Retain messages survive broker restarts

Restart Mosquitto to apply changes:

sudo systemctl restart mosquitto

Firewall Configuration

Open port 1883 in your firewall:

UFW (Ubuntu):

sudo ufw allow 1883/tcp

Testing the Broker

From your server, test with the Mosquitto clients:

Terminal 1 - Subscribe:

mosquitto_sub -h localhost -t "test/#" -v

Terminal 2 - Publish:

mosquitto_pub -h localhost -t "test/hello" -m "Hello, MQTT!"

You should see the message appear in Terminal 1. If this works locally, test from a remote machine using your server's IP or hostname.

Adding Authentication

Running without authentication is fine for testing but inappropriate for production. Add password authentication:

Create a password file:

sudo mosquitto_passwd -c /etc/mosquitto/passwd meshtastic

Enter a password when prompted. To add additional users later:

sudo mosquitto_passwd /etc/mosquitto/passwd anotheruser

Update the configuration:

sudo nano /etc/mosquitto/mosquitto.conf

Change the authentication settings:

# Require authentication
allow_anonymous false
password_file /etc/mosquitto/passwd

Restart Mosquitto:

sudo systemctl restart mosquitto

Test with credentials:

mosquitto_pub -h localhost -t "test/hello" -m "Hello!" -u meshtastic -P yourpassword

Adding TLS Encryption

For production use, encrypt connections with TLS. This requires a domain name and certificates.

Using Let's Encrypt:

Install Certbot:

sudo apt install certbot

Obtain certificates:

sudo certbot certonly --standalone -d mqtt.yourdomain.com

Update Mosquitto configuration:

# TLS listener on port 8883
listener 8883 0.0.0.0
cafile /etc/letsencrypt/live/mqtt.yourdomain.com/chain.pem
certfile /etc/letsencrypt/live/mqtt.yourdomain.com/cert.pem
keyfile /etc/letsencrypt/live/mqtt.yourdomain.com/privkey.pem

# Keep the unencrypted listener for testing (remove in production)
listener 1883 0.0.0.0

allow_anonymous false
password_file /etc/mosquitto/passwd

Important: Mosquitto needs read access to the certificate files. Either run Mosquitto as root (not recommended) or adjust permissions:

sudo chmod 755 /etc/letsencrypt/live/
sudo chmod 755 /etc/letsencrypt/archive/

Open port 8883:

sudo ufw allow 8883/tcp

Restart and test:

sudo systemctl restart mosquitto
mosquitto_pub -h mqtt.yourdomain.com -p 8883 -t "test" -m "TLS test" \
  -u meshtastic -P yourpassword --capath /etc/ssl/certs/

Configuring Meshtastic Nodes

With your MQTT broker running, configure Meshtastic nodes to connect.

In the Meshtastic app:

  1. Connect to your device via Bluetooth
  2. Go to Settings → Module Settings → MQTT
  3. Enable MQTT
  4. Configure:
    • Address: Your server hostname or IP
    • Port: 1883 (or 8883 for TLS)
    • Username: The username you created
    • Password: The corresponding password
    • Encryption Enabled: Match your server (on for TLS)
    • Root Topic: msh/ (default, or customize)

Enable uplink/downlink on channels:

In Channel Settings, enable "Uplink" on channels you want to send to MQTT, and "Downlink" for channels that should receive from MQTT.

Topic Structure

Meshtastic uses a hierarchical topic structure:

msh/<region>/<channel_name>/<gateway_id>

For example:

  • msh/US/LongFast/!abc12345 - Messages from a specific gateway
  • msh/US/LongFast/# - All messages on the LongFast channel in the US region

You can customize the root topic in your MQTT settings if you want to separate your mesh from the public topic namespace.

Docker Deployment (Alternative)

For easier management and isolation, run Mosquitto in Docker:

# docker-compose.yml
version: '3'
services:
  mosquitto:
    image: eclipse-mosquitto:latest
    container_name: mosquitto
    ports:
      - "1883:1883"
      - "8883:8883"
    volumes:
      - ./mosquitto/config:/mosquitto/config
      - ./mosquitto/data:/mosquitto/data
      - ./mosquitto/log:/mosquitto/log
    restart: unless-stopped

Create the configuration directory and file:

mkdir -p mosquitto/config mosquitto/data mosquitto/log

Create mosquitto/config/mosquitto.conf with your settings, then:

docker-compose up -d

Bridging to Other MQTT Servers

You can bridge your private MQTT server to the public Meshtastic infrastructure or other brokers, allowing your local mesh to interact with the global network while keeping your broker independent.

Add to mosquitto.conf:

# Bridge to public Meshtastic MQTT
connection meshtastic-public
address mqtt.meshtastic.org:1883
topic msh/# both 0
remote_username meshdev
remote_password large4cats

This mirrors traffic between your server and the public one on the msh/# topics.

Monitoring and Logging

Check broker status:

sudo systemctl status mosquitto

View logs:

sudo tail -f /var/log/mosquitto/mosquitto.log

Monitor connected clients and message flow:

mosquitto_sub -h localhost -t '$SYS/#' -v -u admin -P password

The $SYS topic provides broker statistics including connected clients, messages per second, and memory usage.

Security Considerations

Limit topic access:

Create an ACL (Access Control List) file for fine-grained permissions:

sudo nano /etc/mosquitto/acl
# Admin has full access
user admin
topic readwrite #

# Meshtastic user limited to msh topics
user meshtastic
topic readwrite msh/#

Add to mosquitto.conf:

acl_file /etc/mosquitto/acl

Rate limiting:

Mosquitto doesn't have built-in rate limiting, but you can use iptables or fail2ban to limit connection attempts.

Keep software updated:

sudo apt update && sudo apt upgrade

Troubleshooting

Connection refused:

  • Check firewall rules
  • Verify Mosquitto is running: sudo systemctl status mosquitto
  • Confirm the listener is on the expected port/interface

Authentication failed:

  • Verify username and password
  • Check the password file format
  • Ensure allow_anonymous false is set if using authentication

TLS handshake failed:

  • Verify certificate paths are correct and readable
  • Check certificate validity: openssl s_client -connect mqtt.yourdomain.com:8883
  • Ensure the client trusts the CA (use --capath or --cafile)

Meshtastic not connecting:

  • Enable MQTT debug logging in the Meshtastic app
  • Verify the address resolves correctly
  • Check that uplink/downlink is enabled on at least one channel

Footnotes:

[1] Meshtastic MQTT Documentation: https://meshtastic.org/docs/software/integrations/mqtt/
[2] Mosquitto Official Documentation: https://mosquitto.org/documentation/
[3] Meshtastic MQTT Configuration: https://meshtastic.org/docs/configuration/module/mqtt/