Overview
m87-server handles device registration, authentication, and tunnel relay. It connects m87 runtimes on edge devices to m87 CLI users. Self-hosting allows you to:- Keep all device data within your infrastructure
- Customize authentication and access control
- Meet compliance requirements
- Control updates and maintenance windows
Requirements
- MongoDB: Version 8 or later (for device and user data storage)
- Docker (recommended): For containerized deployment
- TLS Certificate: For production deployments (Let’s Encrypt or custom)
- Public IP/Domain: For device and client connectivity
Quick Start with Docker Compose
1
Clone the Repository
2
Configure Environment
Create a Edit the
.env file with your configuration:.env file with your settings (see Configuration below).3
Start the Server
- m87-server (API and tunnel relay)
- MongoDB (database)
- Watchtower (optional auto-updates)
4
Verify Deployment
Check that services are running:
Configuration
The m87 server is configured via environment variables. Below are the key settings:Core Database
string
required
MongoDB connection string used by m87-serverDefault:
mongodb://mongo:27017string
default:"m87-server"
Logical database name used by m87-server
string
MongoDB root username (required for secured MongoDB setups)
string
MongoDB root password (required for secured MongoDB setups)
Authentication & OAuth
string
required
OAuth/OIDC issuer URL used to validate access tokensDefault: For custom auth, use your Auth0 tenant or OIDC provider.
https://auth.make87.com/string
required
Expected OAuth audience for access tokens (must match the
aud claim)Default: https://auth.make87.comServer Networking
string
required
Public base address where this server is reachableDefault: Used to check SNI of incoming requests for device ID prefixes.
localhoststring
default:"8084"
Port for the unified public interface (runtime connections and tunnel traffic)This should be mapped to port 443 for TLS.
string
default:"8085"
Port for the REST APIUsed for WebTransport endpoint for the web app (typically mapped to 8080).
Admin & Security
string
required
Static admin API key for privileged actionsUsed for approving users, creating organizations, and bootstrapping admin access.
string
Comma-separated list of email addresses that receive admin privileges
User Management
boolean
default:"false"
Whether newly registered users require manual approval
true: User accounts start inactive until approvedfalse: Users are active immediately
string
Domains that are auto-approved on signupComma-separated list (no spaces). If a user’s email domain matches, approval is skipped.
Device Sharing
boolean
default:"false"
Whether devices can be shared across different organizations
true: Cross-org device sharing allowedfalse: Devices are restricted to their organization
Data Retention
number
default:"30"
Number of days audit log entries are retainedOlder entries are automatically deleted.
number
default:"7"
Number of days deployment/report data is retainedOlder reports are automatically deleted.
Other Settings
number
default:"1"
Whether the server runs in staging mode
0: Production behavior1: Staging mode with relaxed checks and verbose logging
string
default:"info"
Logging levelOptions:
error, warn, info, debug, tracestring
default:"/data/m87/certs/"
Path for TLS certificates
Exposed Ports
The docker-compose configuration exposes:- 443 → 8084 (TCP/UDP): Runtime connections and tunnel traffic (TLS)
- 8080 → 8085 (UDP): REST API and WebTransport endpoint
Example Configuration
Here’s a complete example.env file for production:
Building from Source
If you prefer to build the server binary yourself:1
Install Rust
Requires Rust 1.85 or later:
2
Clone and Build
target/release/m87-server3
Run with MongoDB
Ensure MongoDB is running, then:
Using Prebuilt Docker Images
Pull the latest image from GitHub Container Registry:Auto-Updates with Watchtower
The docker-compose file includes Watchtower for automatic updates:- Check for new images every 5 minutes
- Automatically pull and restart with latest version
- Only update containers with the
watchtower.enablelabel
Production Deployment Checklist
1
Secure MongoDB
- Set strong
MONGO_INITDB_ROOT_PASSWORD - Restrict MongoDB port access (only to m87-server)
- Enable MongoDB authentication
2
Configure TLS
- Obtain TLS certificate (Let’s Encrypt recommended)
- Configure reverse proxy (nginx, Caddy) or mount certificates
- Ensure port 443 routes to
UNIFIED_PORT
3
Set Admin Credentials
- Change
ADMIN_KEYfrom default - Configure
ADMIN_EMAILS - Set
USERS_NEED_APPROVALbased on your requirements
4
Configure Authentication
If using custom OAuth:
- Set up OAuth provider (Auth0, Keycloak, etc.)
- Update
OAUTH_ISSUERandOAUTH_AUDIENCE - Ensure tokens include required claims
5
Set Public Address
- Update
PUBLIC_ADDRESSto your domain - Ensure DNS points to your server
- Verify firewall allows ports 443 and 8080
6
Configure Monitoring
- Set appropriate
RUST_LOGlevel - Set up log aggregation
- Monitor container health
7
Backup Strategy
- Configure MongoDB backups
- Backup certificate files
- Store
.envconfiguration securely
Client Configuration
After deploying your server, configure clients to use it:Troubleshooting
Server not starting
Server not starting
Check logs:Common issues:
- MongoDB connection failed (check
MONGO_URI) - Invalid OAuth configuration
- Port already in use
Devices can't connect
Devices can't connect
Verify:
PUBLIC_ADDRESSis correct and DNS resolves- Port 443 is accessible from internet
- TLS certificate is valid
- Firewall allows incoming connections
Authentication errors
Authentication errors
Check:
OAUTH_ISSUERandOAUTH_AUDIENCEmatch your provider- OAuth provider is reachable
- Tokens include required claims
- Admin key is correct
Database connection issues
Database connection issues
- Verify MongoDB is running:
docker compose ps mongo - Check MongoDB logs:
docker compose logs mongo - Ensure credentials in
.envmatch MongoDB config
Updating
Manual Update
With Watchtower (Automatic)
If running with theauto-update profile, Watchtower handles updates automatically.