MR-Bridge - A flexible, configurable tool for bridging topics between two MQTT brokers with dynamic configuration reloading.
- ✅ Bidirectional Bridging: Forward messages between two MQTT brokers in any direction
- ✅ Flexible Topic Rules: Support for MQTT wildcards (
+for single-level,#for multi-level) - ✅ Dynamic Configuration Reload: Update bridge rules on-the-fly by publishing to a reload topic
- ✅ Configurable QoS: Set Quality of Service per-rule (0, 1, or 2)
- ✅ Optional Logging: Log individual messages per-rule for debugging
- ✅ Auto-reconnection: Automatic reconnection on connection failures
- ✅ Multiple Formats: Support for TOML and JSON configuration files
git clone <repository-url>
cd mr-bridge
cargo build --releaseThe binary will be available at target/release/mr-bridge.
Pre-built Docker images are available from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/<username>/mr-bridge:latest
# Run with a config file mounted
docker run -v $(pwd)/config.toml:/app/config.toml \
ghcr.io/<username>/mr-bridge:latest \
--config /app/config.toml
# Run with environment variable
docker run -e MR_BRIDGE_CONFIG=/app/config.toml \
-v $(pwd)/config.toml:/app/config.toml \
ghcr.io/<username>/mr-bridge:latest# Build the image
docker build -t mr-bridge .
# Run the image
docker run -v $(pwd)/config.toml:/app/config.toml \
mr-bridge --config /app/config.tomlCreate a configuration file in TOML or JSON format. See config.example.toml or config.example.json for examples.
[near]
host = "localhost"
port = 1883
username = "user1" # optional
password = "pass1" # optional
client_id = "mr-bridge-near" # optional, auto-generated if not provided
[far]
host = "mqtt.example.com"
port = 1883
[[rules]]
topic = "sensors/#"
direction = "near_to_far"
logging = true
qos = 1
[[rules]]
topic = "commands/#"
direction = "far_to_near"
logging = false
qos = 1
[[rules]]
topic = "status/+"
direction = "wherever" # bidirectional
logging = false
qos = 0{
"near": {
"host": "localhost",
"port": 1883
},
"far": {
"host": "mqtt.example.com",
"port": 1883
},
"rules": [
{
"topic": "sensors/#",
"direction": "near_to_far",
"logging": true,
"qos": 1
}
]
}host(required): MQTT broker hostname or IP addressport(optional, default: 1883): MQTT broker portusername(optional): Username for authenticationpassword(optional): Password for authenticationclient_id(optional): MQTT client ID (auto-generated UUID if not specified)
topic(required): MQTT topic pattern with wildcard support+matches a single level (e.g.,home/+/tempmatcheshome/kitchen/temp)#matches multiple levels (e.g.,sensors/#matchessensors/temp,sensors/room/temp)
direction(required): Bridge directionnear_to_far: Forward messages from near broker to far brokerfar_to_near: Forward messages from far broker to near brokerwherever: Bidirectional bridging (forward in both directions)
logging(optional, default: false): Log each bridged messageqos(optional, default: 0): Quality of Service level (0, 1, or 2)
# Using a TOML configuration file
mr-bridge --config config.toml
# Using a JSON configuration file
mr-bridge --config config.json
# Using environment variable
export MR_BRIDGE_CONFIG=config.toml
mr-bridgeEnable dynamic reloading by specifying a reload topic:
# Reload when a message is published to 'admin/reload' on the near broker
mr-bridge --config config.toml --reload-topic admin/reload
# Listen for reload on the far broker instead
mr-bridge --config config.toml --reload-topic admin/reload --reload-broker farTo trigger a reload, publish any message to the reload topic:
mosquitto_pub -t admin/reload -m "reload"The bridge will:
- Load the updated configuration file
- Unsubscribe from old topics
- Subscribe to new topics
- Continue operating without disconnecting from brokers
All CLI arguments can be set via environment variables:
MR_BRIDGE_CONFIG: Path to configuration fileMR_BRIDGE_RELOAD_TOPIC: Reload topicMR_BRIDGE_RELOAD_BROKER: Broker to listen for reload messages (nearorfar)
Control log verbosity with the RUST_LOG environment variable:
# Info level (default)
export RUST_LOG=info
mr-bridge --config config.toml
# Debug level for troubleshooting
export RUST_LOG=debug
mr-bridge --config config.toml
# Only errors
export RUST_LOG=error
mr-bridge --config config.tomlForward all sensor data from local MQTT broker to cloud broker:
[near]
host = "localhost"
port = 1883
[far]
host = "cloud.mqtt.provider.com"
port = 8883
username = "cloud_user"
password = "cloud_password"
[[rules]]
topic = "sensors/#"
direction = "near_to_far"
logging = true
qos = 1Receive commands from cloud and forward to local devices:
[near]
host = "localhost"
port = 1883
[far]
host = "cloud.mqtt.provider.com"
port = 8883
username = "cloud_user"
password = "cloud_password"
[[rules]]
topic = "commands/#"
direction = "far_to_near"
logging = true
qos = 1Keep certain topics synchronized between brokers:
[near]
host = "broker1.local"
port = 1883
[far]
host = "broker2.local"
port = 1883
[[rules]]
topic = "shared/#"
direction = "wherever"
logging = false
qos = 1Different rules for different topic patterns:
[near]
host = "localhost"
port = 1883
[far]
host = "remote.example.com"
port = 1883
# Forward all temperature readings
[[rules]]
topic = "home/+/temperature"
direction = "near_to_far"
logging = true
qos = 0
# Forward all humidity readings
[[rules]]
topic = "home/+/humidity"
direction = "near_to_far"
logging = true
qos = 0
# Receive control commands
[[rules]]
topic = "home/+/control"
direction = "far_to_near"
logging = true
qos = 1
# Bidirectional status updates
[[rules]]
topic = "home/+/status"
direction = "wherever"
logging = false
qos = 0- Startup: mr-bridge connects to both MQTT brokers (near and far)
- Subscription: Subscribes to all topics defined in rules based on direction
- Message Handling: When a message arrives:
- Checks if it matches any configured topic patterns
- Verifies the direction matches
- Forwards the message to the target broker
- Optionally logs the message
- Dynamic Reload: When a message is received on the reload topic:
- Reloads configuration file
- Unsubscribes from old topics
- Subscribes to new topics
- Continues operation seamlessly
Run the test suite:
cargo test- Start two MQTT brokers:
# Terminal 1 - Near broker
mosquitto -p 1883
# Terminal 2 - Far broker
mosquitto -p 1884- Create a test config:
[near]
host = "localhost"
port = 1883
[far]
host = "localhost"
port = 1884
[[rules]]
topic = "test/#"
direction = "near_to_far"
logging = true
qos = 1- Run the bridge:
mr-bridge --config test.toml- Test message forwarding:
# Subscribe to far broker
mosquitto_sub -p 1884 -t "test/#"
# Publish to near broker (in another terminal)
mosquitto_pub -p 1883 -t "test/message" -m "Hello from near!"You should see the message appear on the far broker.
- Async Runtime: Built on Tokio for efficient concurrent operation
- MQTT Client: Uses
rumqttcfor robust MQTT 3.1.1 support - Configuration: Supports both TOML and JSON via serde
- Error Handling: Comprehensive error handling with automatic reconnection
- Topic Matching: Custom wildcard matching implementation for MQTT topics
This project uses GitHub Actions for continuous integration and deployment:
On every push and pull request:
- Formatting:
cargo fmtverifies code formatting - Linting:
cargo clippychecks for common mistakes and improvements - Tests:
cargo testruns the test suite
On pushes to main branch:
- Multi-architecture Docker images (amd64, arm64) are built and pushed to GitHub Container Registry
- Images are tagged with:
latest- Latest stable version from main branch<branch>-<sha>- Commit-specific tagsv*- Semantic version tags (for git tags)
# Pull the latest stable image
docker pull ghcr.io/<username>/mr-bridge:latest
# Pull a specific commit
docker pull ghcr.io/<username>/mr-bridge:main-abc1234
# Pull a tagged release
docker pull ghcr.io/<username>/mr-bridge:v1.0.0version: '3.8'
services:
mr-bridge:
image: ghcr.io/<username>/mr-bridge:latest
container_name: mr-bridge
restart: unless-stopped
volumes:
- ./config.toml:/app/config.toml:ro
environment:
- MR_BRIDGE_CONFIG=/app/config.toml
- RUST_LOG=info
# Optional: If you need to access local MQTT brokers
network_mode: hostIf you can't connect to a broker:
- Verify the host and port are correct
- Check if authentication is required
- Ensure firewall rules allow the connection
- Check broker logs for connection attempts
If messages aren't being bridged:
- Verify the topic pattern matches (wildcards are case-sensitive)
- Check the direction is correct
- Enable logging on the rule to see if messages are being received
- Use
RUST_LOG=debugto see detailed internal operations
If reload isn't working:
- Verify the reload topic is correct
- Check which broker you're publishing to (matches
--reload-broker) - Ensure the configuration file is readable and valid
- Check logs for reload errors