RMM+PSA MeshCentral Deployment
Production deployment configuration for MeshCentral integration with custom JWT authentication.
๐ Quick Links
๐ Overview
This repository contains the deployment configuration for running a forked version of MeshCentral with custom JWT authentication. The fork enables true Single Sign-On (SSO) with the RMM+PSA dashboard by validating JWT tokens against a PostgreSQL user database.
Why a Fork?
MeshCentral's native authentication uses its own user database. By forking and adding JWT support, we:
- Eliminate separate logins for remote desktop access
- Use the existing RMM+PSA user database
- Maintain tenant isolation and security
- Enable seamless iframe embedding
๐๏ธ Architecture
RMM Dashboard (React)
โ JWT Token
Backend API (Node.js)
โ /meshcentral/session/:agentId
MeshCentral Fork (This Deployment)
โ JWT Validation
PostgreSQL Database (Shared)
โ User Lookup
MeshCentral Session Created
๐ Repository Structure
.
โโโ Dockerfile # Docker build configuration
โโโ .do-app-spec.yaml # DigitalOcean App Platform spec
โโโ config.json.template # MeshCentral configuration template
โโโ entrypoint.sh # Container startup script
โโโ JWT_AUTH_IMPLEMENTATION.md # Complete implementation guide
โโโ meshcentral-fork/ # Fork submodule (optional)
โ โโโ jwt-auth.js # Custom JWT authentication module
โ โโโ webserver.js # Modified (4 places)
โ โโโ meshcentral.js # Modified (line ~1926)
โ โโโ package.json # Modified (added jwt, pg)
โ โโโ UPSTREAM_SYNC.md # Fork maintenance guide
โ โโโ sync-upstream.sh # Automated sync script
โโโ README.md # This file
๐ง Local Development
Prerequisites
- Docker
- Node.js 18+
- PostgreSQL access
Setup
- Clone repository:
git clone https://github.com/Independent-Business-Group/rmm-psa-meshcentral.git
cd rmm-psa-meshcentral
- Configure environment:
cp .env.example .env
# Edit .env with your credentials
- Build Docker image:
docker build -t meshcentral-local .
- Run locally:
docker run -it --rm \
--env-file .env \
-p 4430:443 \
meshcentral-local
- Access:
๐ Production Deployment
Automatic Deployment
Pushes to main branch automatically deploy to DigitalOcean App Platform.
Manual Deployment
# Trigger rebuild
doctl apps create-deployment 0ceb0932-3fa7-4a42-9a51-f0a124360a04 --force-rebuild
# Check deployment status
doctl apps get-deployment 0ceb0932-3fa7-4a42-9a51-f0a124360a04 <deployment-id>
# View logs
doctl apps logs 0ceb0932-3fa7-4a42-9a51-f0a124360a04 --follow
Deployment Checklist
Before deploying:
- Fork has latest changes pushed
- Environment variables are configured
- Database is accessible from MeshCentral
- JWT secrets match between backend and MeshCentral
- Dockerfile clones from fork repository
After deploying:
- Check logs for "โ
JWT Auth: PostgreSQL connected"
- Test login with dashboard
- Verify Terminal, Files, and RDS tabs work
- Check error rate in monitoring
๐ Configuration
Required Environment Variables
# JWT Authentication
JWT_SECRET=<base64-secret> # Must match backend
AGENT_SIGN_KEY=<hex-secret> # Must match backend
# PostgreSQL Database
POSTGRES_HOST=<db-host>
POSTGRES_PORT=25060
POSTGRES_USER=doadmin
POSTGRES_PASSWORD=<password>
POSTGRES_DB=defaultdb
# Fallback variables (compatibility)
DB_HOST=${POSTGRES_HOST}
DB_PORT=${POSTGRES_PORT}
DB_USER=${POSTGRES_USER}
DB_PASSWORD=${POSTGRES_PASSWORD}
DB_NAME=${POSTGRES_DB}
MeshCentral Settings
config.json.template (substituted at runtime):
{
"settings": {
"jwtAuth": true,
"postgres": {
"host": "${POSTGRES_HOST}",
"port": ${POSTGRES_PORT},
"user": "${POSTGRES_USER}",
"password": "${POSTGRES_PASSWORD}",
"database": "${POSTGRES_DB}"
},
"cert": "${MESHCENTRAL_URL}",
"port": 443,
"agentPort": 444,
"redirPort": 0,
"trustedProxy": true
},
"domains": {
"": {
"title": "RMM+PSA Remote Management",
"newAccounts": false,
"certUrl": "${MESHCENTRAL_URL}:443"
}
}
}
๐งช Testing
Health Check
# Check if MeshCentral is responding
curl -I https://rmm-psa-meshcentral-aq48h.ondigitalocean.app/
# Check JWT authentication
curl "https://rmm-psa-meshcentral-aq48h.ondigitalocean.app/?token=YOUR_JWT_TOKEN"
Integration Test
- Login to dashboard: https://dashboard.everydaytech.au
- Navigate: Devices โ Select Agent โ RDS tab
- Verify: MeshCentral loads without login prompt
- Test: Desktop view, Terminal tab, Files tab
Debug Logging
# Watch real-time logs
doctl apps logs 0ceb0932-3fa7-4a42-9a51-f0a124360a04 --follow
# Filter JWT-related logs
doctl apps logs 0ceb0932-3fa7-4a42-9a51-f0a124360a04 --tail 1000 | grep -i jwt
# Check PostgreSQL connection
doctl apps logs 0ceb0932-3fa7-4a42-9a51-f0a124360a04 | grep "PostgreSQL"
๐ Fork Maintenance
Check for Upstream Updates
cd meshcentral-fork
./sync-upstream.sh check
Merge Upstream Changes
cd meshcentral-fork
./sync-upstream.sh merge
# Resolve conflicts if any
./sync-upstream.sh push
See: meshcentral-fork/UPSTREAM_SYNC.md for detailed instructions.
๐ Monitoring
Key Metrics
- Uptime: DigitalOcean monitors health checks
- Response Time: <200ms for authenticated requests
- **Error Rate**: <1% JWT validation failures
- **Database Connections**: Max 10 (pooled)
Alerts
Configure alerts in DigitalOcean:
- App restart/crash
- High error rate (>5%)
- Resource limits exceeded
- Certificate expiration
๐ Troubleshooting
Common Issues
1. "401 Unauthorized" in iframe
Cause: JWT token invalid or expired
Fix:
# Check if JWT_SECRET matches backend
doctl apps spec get 0ceb0932-3fa7-4a42-9a51-f0a124360a04 | grep JWT_SECRET
# Compare with backend secret
grep JWT_SECRET /path/to/backend/.env
2. "PostgreSQL connection failed"
Cause: Database not accessible or credentials wrong
Fix:
# Test connection from your machine
psql "postgresql://user:pass@host:25060/defaultdb?sslmode=require"
# Check DigitalOcean database firewall rules
# Add MeshCentral app IP to trusted sources
3. "Agent not connected"
Cause: MeshAgent not installed or wrong nodeId
Fix:
SELECT agent_id, hostname, meshcentral_nodeid
FROM agents
WHERE agent_id = 115;
4. Deployment stuck in "BUILD" phase
Cause: Build timeout or dependency issues
Fix:
# Cancel stuck deployment
doctl apps list-deployments 0ceb0932-3fa7-4a42-9a51-f0a124360a04
doctl apps cancel-deployment 0ceb0932-3fa7-4a42-9a51-f0a124360a04 <deployment-id>
# Trigger fresh deployment
doctl apps create-deployment 0ceb0932-3fa7-4a42-9a51-f0a124360a04 --force-rebuild
๐ Documentation
๐ Security
Best Practices
- Secrets Rotation: Rotate JWT secrets quarterly
- Database Access: Use read-only credentials where possible
- HTTPS Only: Never access over HTTP
- Token Expiry: Keep JWT expiry short (24h max)
- Monitoring: Watch for authentication failures
Security Checklist
- JWT secrets stored as DigitalOcean secrets (not in code)
- Database firewall configured
- MeshCentral behind DigitalOcean CDN
- Regular security updates from upstream
๐ค Contributing
Making Changes
- Test locally first
- Update fork if modifying authentication
- Update docs if changing configuration
- Create PR for review before merging to main
Fork Development
If modifying the MeshCentral fork:
- Clone fork: git clone https://github.com/Independent-Business-Group/MeshCentral.git
- Make changes in jwt-auth.js, webserver.js, etc.
- Test with local PostgreSQL
- Commit and push to fork
- Update deployment Dockerfile if needed
- Trigger deployment rebuild
๐ Support
๐ License
- MeshCentral: Apache License 2.0 (upstream)
- Custom Code: Proprietary (IBG Development)
- This Deployment: Internal use only
Maintained By: IBG Development Team
Last Updated: February 16, 2026
Version: 1.0.0