Nvm is a development tool and is not supported for production.
The advantage of this setup is that the global node_modules and npm cache are private for matterbridge and sudo is not required.
The service runs with group and user matterbridge and the system has full protection.
The storage position is not compatible with the traditional setup (~/Matterbridge ~/.matterbridge ~/.mattercert).
Also various scripts don't work if you choose this configuration.
# ✅ Create the matterbridge group
sudo groupadd --system matterbridge 2>/dev/null || true
# ✅ Create the matterbridge user
sudo useradd --system \
--home-dir /opt/matterbridge \
--shell /usr/sbin/nologin \
--gid matterbridge \
matterbridge 2>/dev/null || true
This will create the required directories if they don't exist
cd ~
# ✅ Safe precaution if matterbridge was already running with the traditional setup
sudo systemctl stop matterbridge 2>/dev/null || true
# ✅ Safe precaution we need to uninstall from the global node_modules
sudo npm uninstall matterbridge -g 2>/dev/null || true
# ✅ Creates all required directories
sudo mkdir -p /opt/matterbridge /opt/matterbridge/Matterbridge /opt/matterbridge/.matterbridge /opt/matterbridge/.mattercert /opt/matterbridge/.npm-global /opt/matterbridge/.npm-cache
# ✅ Ensures ownership
sudo chown -R matterbridge:matterbridge /opt/matterbridge /opt/matterbridge/Matterbridge /opt/matterbridge/.matterbridge /opt/matterbridge/.mattercert /opt/matterbridge/.npm-global /opt/matterbridge/.npm-cache
# ✅ Secure permissions
sudo chmod -R 755 /opt/matterbridge /opt/matterbridge/Matterbridge /opt/matterbridge/.matterbridge /opt/matterbridge/.mattercert /opt/matterbridge/.npm-global /opt/matterbridge/.npm-cache
# ✅ make sure the “bin” dir exists for global executables
sudo -u matterbridge mkdir -p /opt/matterbridge/.npm-global/bin
# ✅ Install matterbridge in the private global node_modules using the private npm cache
sudo -u matterbridge npm install matterbridge --omit=dev --verbose --global --prefix=/opt/matterbridge/.npm-global --cache=/opt/matterbridge/.npm-cache
# ✅ Create a link to matterbridge bins
sudo ln -sf /opt/matterbridge/.npm-global/bin/matterbridge /usr/bin/matterbridge
sudo ln -sf /opt/matterbridge/.npm-global/bin/mb_mdns /usr/bin/mb_mdns
sudo ln -sf /opt/matterbridge/.npm-global/bin/mb_coap /usr/bin/mb_coap
# ✅ Clear bash command cache as a precaution
hash -r
# ✅ Check if matterbridge is /usr/bin/matterbridge
which matterbridge
# ✅ Will output the matterbridge version
matterbridge --version
The storage position is not compatible with the traditional setup (~/Matterbridge ~/.matterbridge ~/.mattercert).
If you are migrating from the traditional service setup, before removing the old directories, you may want to copy the contents of ~/Matterbridge ~/.matterbridge ~/.mattercert to the new directories /opt/matterbridge/Matterbridge /opt/matterbridge/.matterbridge /opt/matterbridge/.mattercert. This will save all the plugin configs and the fabrics, but you need to remove all plugins and add them again because the path will be different.
Copy the old directories content
sudo cp -a ~/Matterbridge/. /opt/matterbridge/Matterbridge/
sudo cp -a ~/.matterbridge/. /opt/matterbridge/.matterbridge/
sudo cp -a ~/.mattercert/. /opt/matterbridge/.mattercert/
Remove the old directories
sudo rm -rf ~/Matterbridge ~/.matterbridge ~/.mattercert ~/.npm-global
Create a systemctl configuration file for Matterbridge
sudo nano /etc/systemd/system/matterbridge.service
Add the following to this file:
[Unit]
Description=matterbridge
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=60
StartLimitBurst=5
[Service]
Type=simple
Environment="NODE_ENV=production"
Environment="NPM_CONFIG_PREFIX=/opt/matterbridge/.npm-global"
Environment="NPM_CONFIG_CACHE=/opt/matterbridge/.npm-cache"
ExecStart=matterbridge --service --nosudo
WorkingDirectory=/opt/matterbridge/Matterbridge
# Logs go to the journal (should be persistent). Read with: journalctl -u matterbridge -n 1000 -f --output cat
StandardOutput=journal
StandardError=journal
SyslogIdentifier=matterbridge
Restart=always
RestartSec=5
TimeoutStopSec=60
User=matterbridge
Group=matterbridge
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/opt/matterbridge
[Install]
WantedBy=multi-user.target
On some systems, npm install may fail with errors like ENETUNREACH:
This happens when:
The system has IPv6 enabled DNS returns IPv6 (AAAA) records But the host does not have a working IPv6 default route
In this situation:
Node.js may try IPv6 first. The connection fails with ENETUNREACH. Npm retries may randomly succeed or fail depending on resolution order.
This often indicates a misconfigured IPv6 route / DNS preference.
One possible fix, add this line to the existing [Service] section:
Environment="NODE_OPTIONS=--dns-result-order=ipv4first"
If you use the frontend with --ssl --frontend 443 and get an error message: "Port 443 requires elevated privileges", add this line to the existing [Service] section:
AmbientCapabilities=CAP_NET_BIND_SERVICE
If you use the matterbridge-bthome plugin add this line to the existing [Service] section:
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
Now and if you modify matterbridge.service after, run:
sudo systemctl daemon-reload
sudo systemctl restart matterbridge.service
sudo systemctl status matterbridge.service
sudo systemctl start matterbridge
sudo systemctl stop matterbridge
sudo systemctl status matterbridge
sudo systemctl enable matterbridge
sudo systemctl disable matterbridge
sudo journalctl -u matterbridge -n 1000 -f --output cat
Check the space used
sudo journalctl --disk-usage
remove all log older than 3 days
sudo journalctl --rotate
sudo journalctl --vacuum-time=3d
If you want to make the setting permanent to prevent the journal logs to grow too much, run
sudo nano /etc/systemd/journald.conf
add these to the [Journal] section:
# Store logs persistently in /var/log/journal so they survive reboots.
Storage=persistent
# Compress logs
Compress=yes
# Keep logs for a maximum of 3 days.
MaxRetentionSec=3days
# Rotate logs daily within the 3-day retention period.
MaxFileSec=1day
# Disable forwarding to syslog to prevent duplicate logging.
ForwardToSyslog=no
# Limit persistent (disk) logs in /var/log/journal to 100 MB.
SystemMaxUse=100M
# Limit runtime (memory) logs in /run/log/journal to 100 MB.
RuntimeMaxUse=100M
save it and check if other configs override yours:
sudo systemctl restart systemd-journald
sudo systemd-analyze cat-config systemd/journald.conf