MQTT Explorer now supports running as a web application served by a Node.js server, in addition to the existing Electron desktop app.
-
Build the application for browser mode:
yarn build:server
-
Start the server:
yarn start:server
-
Open your browser and navigate to
http://localhost:3000 -
You'll be prompted to log in with credentials that were generated on server startup.
To run in development mode with hot reload:
yarn dev:serverThis starts both the webpack dev server and the backend server.
You can set custom authentication credentials using environment variables:
export MQTT_EXPLORER_USERNAME=admin
export MQTT_EXPLORER_PASSWORD=secretpassword
yarn start:serverIf no environment variables are set, the server will generate credentials on first startup and save them to data/credentials.json. The generated credentials will be printed to the console:
============================================================
Generated new credentials:
Username: user-abc123
Password: 123e4567-e89b-12d3-a456-426614174000
============================================================
Please save these credentials. They will be persisted to:
/path/to/data/credentials.json
============================================================
In browser mode, certificate files are uploaded directly through the browser using the HTML5 File API. The certificates are:
- Read client-side as base64
- Stored in the connection configuration
- Used when establishing MQTT connections
In browser mode, all data is stored on the server:
- Credentials:
data/credentials.json - Uploaded certificates:
data/certificates/ - File uploads:
data/uploads/
The default port is 3000. You can change it using the PORT environment variable:
PORT=8080 yarn start:server- Electron Mode: Uses Electron IPC for communication between renderer and main process
- Browser Mode: Uses Socket.io WebSockets for real-time communication between browser and server
The application automatically detects the environment and uses the appropriate transport layer.
Both Electron IPC and Socket.io implement the same EventBusInterface, allowing the application code to work seamlessly in both modes without modification.
- File System Access: Limited to server-side operations
- Native Dialogs: File selection uses browser file input instead of native dialogs
- Auto-Updates: Not available in browser mode
- Tray Icon: Not available in browser mode
- No Installation: Access from any browser
- Cross-Platform: Works on any device with a modern browser
- Remote Access: Can be deployed on a server for remote access
- Multi-User: Can support authentication for multiple users
CRITICAL: The following security measures must be implemented for production deployments:
Always use HTTPS in production to protect credentials and MQTT data in transit:
# Use a reverse proxy like nginx or Apache with TLS
# Example nginx configuration:
server {
listen 443 ssl http2;
server_name mqtt-explorer.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}NEVER use generated credentials in production. Always set secure credentials via environment variables:
export MQTT_EXPLORER_USERNAME=your_secure_username
export MQTT_EXPLORER_PASSWORD=your_strong_password_min_12_chars
export NODE_ENV=production
yarn start:serverConfigure allowed origins instead of using the wildcard (*):
# Single origin
export ALLOWED_ORIGINS=https://mqtt-explorer.example.com
# Multiple origins (comma-separated)
export ALLOWED_ORIGINS=https://app1.example.com,https://app2.example.com
yarn start:serverIn production with NODE_ENV=production, wildcard CORS is automatically disabled for security.
- Deploy behind a firewall or VPN
- Use IP whitelisting if possible
- Implement network-level rate limiting
- Monitor for suspicious connection patterns
The server implements several protections against malicious file uploads:
- Maximum file size: 16MB (configurable via
MAX_FILE_SIZEconstant) - Path traversal protection via filename sanitization
- Files stored in isolated directories
- Real path validation to prevent directory escapes
The server implements multiple layers of authentication security:
- Password Hashing: bcrypt with 10 rounds
- Timing Attack Protection: Constant-time string comparison for usernames
- Rate Limiting: Maximum 5 failed attempts per IP per 15 minutes
- Session Tracking: Failed attempts are tracked per client IP
- No Credential Logging: In production mode, credentials are not logged
The server uses helmet.js to set security headers:
- Content Security Policy (CSP)
- HTTP Strict Transport Security (HSTS) in production
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection
- Rotate Credentials Regularly: Change authentication credentials periodically
- Monitor Logs: Watch for authentication failures and unusual patterns
- Keep Dependencies Updated: Run
yarn auditregularly - Limit Network Exposure: Don't expose the server directly to the internet
- Use Strong Passwords: Minimum 12 characters with mixed case, numbers, and symbols
- Enable Logging: Monitor access logs and error logs
- Regular Backups: Back up configuration and certificate data
- Principle of Least Privilege: Run the server with minimal required permissions
If you discover a security vulnerability, please report it via:
- GitHub Security Advisories
- Email to the maintainer
- Do NOT create public issues for security vulnerabilities
- 2024-12: Initial security review and hardening
- Added helmet.js for HTTP security headers
- Implemented rate limiting for authentication
- Added path traversal protection
- Implemented constant-time comparison for credentials
- Added input validation and size limits
- Removed credential logging in production
- Added configurable CORS origins
- Created comprehensive security test suite
- HTTPS: For production, always use HTTPS to encrypt credentials and MQTT data
- Authentication: Keep credentials secure and rotate them regularly
- Network: Ensure the server is on a trusted network or behind a firewall
- Environment Variables: Use environment variables for production credentials, not the generated ones
For production deployment:
-
Build the application:
yarn build:server
-
Set environment variables:
export MQTT_EXPLORER_USERNAME=your_username export MQTT_EXPLORER_PASSWORD=your_secure_password export PORT=3000
-
Start the server:
yarn start:server
-
Use a reverse proxy (nginx, Apache) to add HTTPS and additional security features
Enable detailed Socket.IO connection and lifecycle debugging:
DEBUG=mqtt-explorer:socketio* yarn start:serverAvailable debug namespaces:
mqtt-explorer:socketio- General Socket.IO events and metricsmqtt-explorer:socketio:connect- Client connection eventsmqtt-explorer:socketio:disconnect- Client disconnection and cleanupmqtt-explorer:socketio:subscriptions- Subscription lifecycle trackingmqtt-explorer:socketio:connections- MQTT connection ownership
This will log:
- Client connect/disconnect events
- Subscription counts per socket
- MQTT connection ownership tracking
- Memory leak detection metrics (subscriptions, handlers, connections)
Example output:
mqtt-explorer:socketio:connect Client connected: abc123de
mqtt-explorer:socketio [connect] clients=1 subscriptions=8 mqttConns=0 | socket[abc123de]: subs=8 conns=0
mqtt-explorer:socketio:connections Connection my-mqtt owned by socket abc123de (total: 1)
mqtt-explorer:socketio:disconnect Client disconnected: abc123de
mqtt-explorer:socketio:subscriptions Removed 8 subscriptions for socket abc123de
mqtt-explorer:socketio [disconnect] clients=0 subscriptions=0 mqttConns=0 | socket[abc123de]: subs=0 conns=0
- Check the console output for the generated credentials
- Clear browser session storage:
sessionStorage.clear()in browser console - Restart the server to regenerate credentials
- Check that the server is running:
http://localhost:3000 - Check browser console for Socket.io connection errors
- Verify firewall rules allow the port
In browser mode, certificates are handled differently:
- Use the file upload button to select certificate files
- Files are read and encoded client-side
- Large certificate files (>16KB) will be rejected