Skip to main content
The m87 server can be self-hosted for on-premise deployments, giving you complete control over your device management infrastructure.

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

git clone https://github.com/make87/m87
cd m87/m87-server
2

Configure Environment

Create a .env file with your configuration:
cp .env.example .env
Edit the .env file with your settings (see Configuration below).
3

Start the Server

docker compose up -d
This will start:
  • m87-server (API and tunnel relay)
  • MongoDB (database)
  • Watchtower (optional auto-updates)
4

Verify Deployment

Check that services are running:
docker compose ps
docker compose logs -f m87-server

Configuration

The m87 server is configured via environment variables. Below are the key settings:

Core Database

MONGO_URI
string
required
MongoDB connection string used by m87-serverDefault: mongodb://mongo:27017
MONGO_URI=mongodb://mongo:27017
MONGO_DB
string
default:"m87-server"
Logical database name used by m87-server
MONGO_DB=m87-server
MONGO_INITDB_ROOT_USERNAME
string
MongoDB root username (required for secured MongoDB setups)
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD
string
MongoDB root password (required for secured MongoDB setups)
MONGO_INITDB_ROOT_PASSWORD=secure_password_here

Authentication & OAuth

OAUTH_ISSUER
string
required
OAuth/OIDC issuer URL used to validate access tokensDefault: https://auth.make87.com/
OAUTH_ISSUER=https://auth.make87.com/
For custom auth, use your Auth0 tenant or OIDC provider.
OAUTH_AUDIENCE
string
required
Expected OAuth audience for access tokens (must match the aud claim)Default: https://auth.make87.com
OAUTH_AUDIENCE=https://auth.make87.com

Server Networking

PUBLIC_ADDRESS
string
required
Public base address where this server is reachableDefault: localhost
PUBLIC_ADDRESS=m87.example.com
Used to check SNI of incoming requests for device ID prefixes.
UNIFIED_PORT
string
default:"8084"
Port for the unified public interface (runtime connections and tunnel traffic)
UNIFIED_PORT=8084
This should be mapped to port 443 for TLS.
REST_PORT
string
default:"8085"
Port for the REST API
REST_PORT=8085
Used for WebTransport endpoint for the web app (typically mapped to 8080).

Admin & Security

ADMIN_KEY
string
required
Static admin API key for privileged actions
ADMIN_KEY=your-secure-admin-key-here
Used for approving users, creating organizations, and bootstrapping admin access.
Change this from the default value in production!
ADMIN_EMAILS
string
Comma-separated list of email addresses that receive admin privileges
ADMIN_EMAILS=admin@example.com,ops@example.com

User Management

USERS_NEED_APPROVAL
boolean
default:"false"
Whether newly registered users require manual approval
USERS_NEED_APPROVAL=false
  • true: User accounts start inactive until approved
  • false: Users are active immediately
USER_AUTO_ACCEPT_DOMAINS
string
Domains that are auto-approved on signup
USER_AUTO_ACCEPT_DOMAINS=make87.com,example.org
Comma-separated list (no spaces). If a user’s email domain matches, approval is skipped.

Device Sharing

ALLOW_CROSS_ORG_DEVICE_SHARING
boolean
default:"false"
Whether devices can be shared across different organizations
ALLOW_CROSS_ORG_DEVICE_SHARING=false
  • true: Cross-org device sharing allowed
  • false: Devices are restricted to their organization

Data Retention

AUDIT_RETENTION_DAYS
number
default:"30"
Number of days audit log entries are retained
AUDIT_RETENTION_DAYS=30
Older entries are automatically deleted.
REPORT_RETENTION_DAYS
number
default:"7"
Number of days deployment/report data is retained
REPORT_RETENTION_DAYS=7
Older reports are automatically deleted.

Other Settings

STAGING
number
default:"1"
Whether the server runs in staging mode
STAGING=0
  • 0: Production behavior
  • 1: Staging mode with relaxed checks and verbose logging
RUST_LOG
string
default:"info"
Logging level
RUST_LOG=info
Options: error, warn, info, debug, trace
CERTIFICATE_PATH
string
default:"/data/m87/certs/"
Path for TLS certificates
CERTIFICATE_PATH=/data/m87/certs/

Exposed Ports

The docker-compose configuration exposes:
  • 4438084 (TCP/UDP): Runtime connections and tunnel traffic (TLS)
  • 80808085 (UDP): REST API and WebTransport endpoint

Example Configuration

Here’s a complete example .env file for production:
# Database
MONGO_URI=mongodb://admin:secure_password@mongo:27017/admin
MONGO_DB=m87-server
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=secure_password

# Auth (using make87 default auth)
OAUTH_ISSUER=https://auth.make87.com/
OAUTH_AUDIENCE=https://auth.make87.com

# Networking
PUBLIC_ADDRESS=m87.example.com
UNIFIED_PORT=8084
REST_PORT=8085

# Security
ADMIN_KEY=change-this-to-secure-random-string
ADMIN_EMAILS=admin@example.com

# User management
USERS_NEED_APPROVAL=true
USER_AUTO_ACCEPT_DOMAINS=example.com

# Device sharing
ALLOW_CROSS_ORG_DEVICE_SHARING=false

# Retention
AUDIT_RETENTION_DAYS=90
REPORT_RETENTION_DAYS=14

# Environment
STAGING=0
RUST_LOG=info

Building from Source

If you prefer to build the server binary yourself:
1

Install Rust

Requires Rust 1.85 or later:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
2

Clone and Build

git clone https://github.com/make87/m87
cd m87
cargo build --release -p m87-server
Binary will be at: target/release/m87-server
3

Run with MongoDB

Ensure MongoDB is running, then:
export MONGO_URI=mongodb://localhost:27017
export PUBLIC_ADDRESS=localhost
./target/release/m87-server

Using Prebuilt Docker Images

Pull the latest image from GitHub Container Registry:
docker pull ghcr.io/make87/m87-server:latest
Or specify a version:
docker pull ghcr.io/make87/m87-server:v1.2.3

Auto-Updates with Watchtower

The docker-compose file includes Watchtower for automatic updates:
# Enable auto-updates profile
docker compose --profile auto-update up -d
Watchtower will:
  • Check for new images every 5 minutes
  • Automatically pull and restart with latest version
  • Only update containers with the watchtower.enable label

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_KEY from default
  • Configure ADMIN_EMAILS
  • Set USERS_NEED_APPROVAL based on your requirements
4

Configure Authentication

If using custom OAuth:
  • Set up OAuth provider (Auth0, Keycloak, etc.)
  • Update OAUTH_ISSUER and OAUTH_AUDIENCE
  • Ensure tokens include required claims
5

Set Public Address

  • Update PUBLIC_ADDRESS to your domain
  • Ensure DNS points to your server
  • Verify firewall allows ports 443 and 8080
6

Configure Monitoring

  • Set appropriate RUST_LOG level
  • Set up log aggregation
  • Monitor container health
7

Backup Strategy

  • Configure MongoDB backups
  • Backup certificate files
  • Store .env configuration securely

Client Configuration

After deploying your server, configure clients to use it:
# Set the server URL (if using custom server)
export M87_SERVER_URL=https://m87.example.com

# Login
m87 login
Clients will need to authenticate against your OAuth provider.

Troubleshooting

Check logs:
docker compose logs -f m87-server
Common issues:
  • MongoDB connection failed (check MONGO_URI)
  • Invalid OAuth configuration
  • Port already in use
Verify:
  • PUBLIC_ADDRESS is correct and DNS resolves
  • Port 443 is accessible from internet
  • TLS certificate is valid
  • Firewall allows incoming connections
Check:
  • OAUTH_ISSUER and OAUTH_AUDIENCE match your provider
  • OAuth provider is reachable
  • Tokens include required claims
  • Admin key is correct
  • Verify MongoDB is running: docker compose ps mongo
  • Check MongoDB logs: docker compose logs mongo
  • Ensure credentials in .env match MongoDB config

Updating

Manual Update

# Pull latest image
docker compose pull

# Restart services
docker compose up -d

With Watchtower (Automatic)

If running with the auto-update profile, Watchtower handles updates automatically.

License

The m87 server is licensed under AGPL-3.0-or-later.

Support

For issues and questions: