Fleet Manager is a self-hosted service for managing fleets of Shelly Gen2+ (Plus, Pro, Mini) and Wall Display devices via outbound WebSocket from a single dashboard.
- Real-time device monitoring and control
- Fleet alerts with rules and notification channels
- Energy and environment dashboards and reports
- Device settings editor
- Device onboarding with enrollment tokens and a waiting room
- Device grouping, locations, tags, and bulk operations
- OTA firmware updates
- Role-based access control (OIDC)
- Plugin system for custom extensions
- MCP endpoint for permissioned AI tools
- WebSocket and HTTP API
- Linux (Ubuntu/Debian, Raspberry Pi arm64, Arch) or macOS
- 4 GB RAM minimum, 8 GB recommended
- Docker and Docker Compose (auto-installed if missing)
- Bash 4.0+ (macOS ships 3.2, run
brew install bash)
git clone https://github.com/ALLTERCO/fleet-management.git
cd fleet-management
./deploy/deploy-public.sh upOnce ready, the script prints the access URLs and the login for each account.
The passwords are random and made on the first run. They are also saved in
deploy/state/initial-credentials.txt. Copy them to your password manager.
The admin user name is fm-admin@<your-hostname-or-ip>.
-
Open the Shelly device's local web page
-
Navigate to Networks > Outbound WebSocket
-
Enable it and enter:
- without SSL:
ws://<your-ip>:7011/shelly - with SSL:
wss://<your-hostname-or-ip>/shelly
- without SSL:
-
For self-signed deployments (
--ssl selfsigned), configure device TLS:- Device Web UI > Settings > TLS Configuration > Custom CA PEM bundle > upload
deploy/state/tls/ca.crt - Outbound WebSocket > Connection type > select
User TLS - Server >
wss://<your-hostname-or-ip>/shelly
For Let's Encrypt or other publicly trusted certificates, leave SSL Connectivity on
ca.pem(the device's built-in CA bundle). - Device Web UI > Settings > TLS Configuration > Custom CA PEM bundle > upload
The device will appear in the Fleet Manager dashboard.
Shelly Wall Display devices connect the same way as other Gen2+ devices, but their firmware only trusts the Allterco CA for TLS, they cannot validate self-signed, Let's Encrypt, or custom certificates.
When SSL is enabled, set FM_PLAIN_WS=true in deploy/env/public.env (enabled by default) to allow plain ws:// connections on port 80 for the /shelly path. All other HTTP traffic is still redirected to HTTPS. Configure the Wall Display to connect to ws://<your-ip>/shelly (port 80, no TLS).
| Command | Description |
|---|---|
up |
Start Fleet Management (installs Docker if needed, bootstraps or restarts) |
upgrade |
Safe upgrade: backup, pull Fleet Manager, health check, smoke test, automatic rollback on failure |
upgrade --migrate-first --yes |
Run required migration work first, then upgrade |
upgrade --local |
Upgrade to an image built on this machine (set FM_VERSION to its tag); never pulls |
migrate --plan-only |
Show required database and Zitadel migration work |
migrate --yes |
Run required migration work before upgrading |
upgrade-audit |
Save and compare database and Zitadel snapshots (snapshot, snapshot-zitadel, compare, zitadel-plan) |
rollback |
Revert to the image from before the last upgrade and restore the pre-update database backup (--image-only skips the restore, --backup PATH picks a dump) |
backup-db |
Database backups: list, inspect, verify, create, restore |
backup-state |
Create an encrypted deploy-state backup (credentials, keys, certs). Needs --age-recipient FILE or --passphrase; --out DIR sets the folder |
rotate-secrets |
Rotate JWT secret, encryption key, and database password |
down |
Stop and keep data |
down --volumes |
Stop and delete all data (asks for confirmation; --yes to skip) |
status |
Show container and health status |
logs [service] |
Follow logs |
ip |
Show access URLs |
doctor |
Troubleshoot configuration |
help |
Show help |
All commands are run via ./deploy/deploy-public.sh <command>.
Image pull behavior: up never contacts the registry, it uses cached images
(Compose pulls automatically on first run when no images exist).
upgrade pulls the Fleet Manager image (and Node-RED when it is on), swaps it, and checks health. Use upgrade when a new version is available.
Add --debug for raw shell trace and full output.
Add --logging to enable the authenticated Dozzle container log viewer. Set
DOZZLE_USERS_FILE to an absolute path containing a Dozzle users.yml first.
The viewer binds only to 127.0.0.1:9999; use an SSH tunnel for remote access.
Before a major upgrade, make a backup and inspect the migration plan:
./deploy/deploy-public.sh backup-db create
./deploy/deploy-public.sh backup-state --passphrase
./deploy/deploy-public.sh migrate --plan-onlyIf migration work is required, run:
./deploy/deploy-public.sh migrate --yes
./deploy/deploy-public.sh upgradeor run both steps together:
./deploy/deploy-public.sh upgrade --migrate-first --yesThe upgrade command refuses to continue when database or Zitadel migration work
is pending. Keep deploy/state/ safe: it holds the secret salt that your stored
secrets depend on, and it must never change. See Deployment Guide for the full upgrade
flow.
# Self-signed (local networks, IPs, .local)
./deploy/deploy-public.sh up --ssl selfsigned
# Let's Encrypt (public FQDN)
./deploy/deploy-public.sh up --ssl --domain your.domain.com
# Your own certificate
./deploy/deploy-public.sh up --ssl custom \
--domain your.domain.com \
--cert /path/fullchain.pem \
--key /path/privkey.pemSee the Deployment Guide for SSL mode details, certificate requirements, and configuration options.
Pre-built multi-arch images (amd64 + arm64):
docker pull shellygroup/fleet-management:latestThe Fleet Manager image serves MCP on the normal application endpoint:
https://<your-host>/mcp
Create a scoped access key with mcp:read, mcp:write, or mcp:full, then
send it as a bearer token. No extra container or port is required.
curl -X POST https://<your-host>/mcp \
-H "Authorization: Bearer <scoped-key>" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'For local documentation lookup, use mcp.example.json. Install backend
dependencies first, then point your MCP client at the included stdio server.
- greetings - Hello-world plugin demonstrating the API
- metadata-demo - Device metadata storage and querying
See plugins/ for source code.
- Deployment Guide
- API Reference
- Runtime OpenAPI document:
https://<your-host>/api/docs/openapi.json - RPC and Components
- Events
- RPC Relay
- Entities
- Plugins
- Backups
- Rollback
- Observability
- AI and MCP
- MCP Operations
| Platform | Architecture | Status |
|---|---|---|
| Ubuntu 22.04+ | amd64/arm64 | Supported |
| Debian 12+ | amd64/arm64 | Supported |
| Raspberry Pi OS | arm64 | Supported |
| Arch Linux | amd64/arm64 | Supported |
| macOS | amd64/arm64 | Supported (Docker Desktop) |
- Bugs and feature requests: GitHub Issues
- Run
./deploy/deploy-public.sh doctorfirst for deployment problems; include its output in your report.
Apache License 2.0 - see LICENSE.
Contributions are welcome via pull requests on GitHub.
To work on the code, run Fleet Manager from source with hot reload:
./deploy/deploy-public.sh up --env devThis needs Node.js 24 and Docker. The database and Redis run in Docker; the
backend and the UI run from backend/ and frontend/. Open
http://localhost:7011 and log in with admin / admin. Press Ctrl+C to stop.
Dev mode is for development only: it has no SSO and no MFA, and it runs over
plain HTTP. Use a separate clone for development, because dev mode shares the
database of a normal deployment in the same folder.