This tool synchronizes monitors and groups between two Uptime Kuma instances while preserving instance-specific settings.
- ✅ Syncs monitors (HTTP, TCP, Ping, etc.)
- ✅ Syncs groups/tags with color coding
- ✅ Syncs status pages - Groups, monitor membership, and page config replicated across instances
- ✅ Shallow & Deep Sync Modes - Choose to preserve or copy instance-specific settings
- ✅ Preserves instance-specific settings (intervals, timeouts, TTLs) in shallow mode
- ✅ Updates existing monitors or creates new ones
- ✅ Maps tags/groups correctly between instances
- ✅ Parent/Group relationships - Correctly maintains monitor hierarchies
- ✅ Tag associations - Uses dedicated
addMonitorTagAPI for reliable tag syncing, prevents duplicates - ✅ Named instance configuration - Reference instances by name
- ✅ Makefile - Convenient
maketargets for all common operations - ✅ Automatic backup before sync - Creates a timestamped backup of the target instance
- ✅ Standalone backup tool - Backup any instance on demand
- ✅ Restore tool - Restore from any backup file
- ✅ Diff tool - Compare monitors between two instances
- ✅ Incremental sync - Hash-based change detection skips unchanged monitors
- ✅ Prune - Optionally delete target monitors absent from source (
--prune) - ✅ Bidirectional sync - Copy target-only monitors back to source (
--bidirectional) - ✅ Sync daemon - Scheduled sync service with a web status UI
Use when: You want to sync monitor definitions but keep each instance's own check intervals and notification settings.
What syncs:
- Monitor names, types, URLs, hostnames
- Basic configuration (auth, headers, accepted status codes, etc.)
- Tags/groups (cleans duplicates, exact match from source)
- Parent/group hierarchies
- Status pages (groups, monitor membership, page config)
What stays on target:
- Check intervals (
interval,retryInterval,resendInterval) - Timeouts and retry limits (
timeout,maxretries,maxredirects) - DNS resolution settings (
dns_resolve_type,dns_resolve_server) - Notification settings (
notificationIDList)
Example use case: Production→Staging sync where staging checks less frequently
Use when: You want an exact replica of the source instance.
What syncs:
- Everything from shallow mode, plus:
- Check intervals and timing settings
- Timeout and retry configuration
- DNS resolution settings
- Notification associations
- All instance-specific settings
Example use case: DR (disaster recovery) setup, migrating to new instance
Regardless of mode, sync now:
- Deletes all existing tags from target monitor
- Updates monitor configuration
- Adds fresh tags from source (prevents duplicates)
- Remaps parent/group relationships to maintain hierarchies
This prevents tag duplication and ensures hierarchies stay intact across instances with different IDs.
- Install required dependencies:
npm install axios socket.io-client dotenv- Configure your instances:
Option A: Named Instances (Recommended)
Copy the example config and edit with your instance details:
cp uptime-kuma-config.json.example uptime-kuma-config.jsonEdit uptime-kuma-config.json:
{
"instances": {
"primary": {
"url": "https://uptime1.example.com",
"username": "admin",
"password": "your-password",
"description": "Primary production instance"
},
"secondary": {
"url": "https://uptime2.example.com",
"username": "admin",
"password": "your-password",
"description": "Secondary backup instance"
}
},
"backup": {
"directory": "./uptime-kuma-backups"
}
}Option B: Environment Variables
Copy .env.uptime-kuma to .env.uptime-kuma.local and configure:
cp .env.uptime-kuma .env.uptime-kuma.localNo Node.js or git clone needed. Copy three files to any Docker host and run.
mkdir uptime-kuma-sync && cd uptime-kuma-synccurl -O https://raw.githubusercontent.com/slmingol/uptime-kuma-sync-n-bak/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/slmingol/uptime-kuma-sync-n-bak/main/Makefile
curl -O https://raw.githubusercontent.com/slmingol/uptime-kuma-sync-n-bak/main/uptime-kuma-config.json.examplecp uptime-kuma-config.json.example uptime-kuma-config.json
# Edit uptime-kuma-config.json with your instance URLs and credentialsmake daemonThe daemon starts immediately, syncs primary → secondary, then repeats every 6 hours.
Web UI available at http://<host>:8089.
./scripts/uptime-kuma-docker.sh list # List configured instances
./scripts/uptime-kuma-docker.sh monitors <instance> # List monitors grouped by parent
./scripts/uptime-kuma-docker.sh monitors <instance> --tldr # Monitor count by group and type
./scripts/uptime-kuma-docker.sh backup <instance> # Backup an instance
./scripts/uptime-kuma-docker.sh sync <source> <target> # Incremental shallow sync
./scripts/uptime-kuma-docker.sh sync <source> <target> --deep # Sync with all settings
./scripts/uptime-kuma-docker.sh sync <source> <target> --force # Full sync, ignore state
./scripts/uptime-kuma-docker.sh sync <source> <target> --prune # Sync + delete target-only monitors
./scripts/uptime-kuma-docker.sh sync <source> <target> --prune --dry-run # Preview prune without deleting
./scripts/uptime-kuma-docker.sh sync <source> <target> --bidirectional # Sync both directions (source wins)
./scripts/uptime-kuma-docker.sh diff <source> <target> # Compare instances
./scripts/uptime-kuma-docker.sh diff <source> <target> --tldr # Compare instances (summary)
./scripts/uptime-kuma-docker.sh restore <backup-file> [instance] # Restore from backup
./scripts/uptime-kuma-docker.sh build # Build the image
./scripts/uptime-kuma-docker.sh shell # Interactive shell
./scripts/uptime-kuma-docker.sh help # Show helpA Makefile wraps the Docker script for the most common operations. Run make help to see all targets.
make list # List configured instances
make monitors # List monitors in SOURCE grouped by parent
make monitors-tldr # Monitor count by group and type for SOURCE
make sync # Incremental shallow sync SOURCE → TARGET
make sync-deep # Sync SOURCE → TARGET (deep, all settings)
make sync-force # Full sync SOURCE → TARGET (bypass state)
make sync-prune # Sync + delete target monitors absent from SOURCE
make sync-prune-dry # Preview what sync-prune would delete
make sync-bidir # Bidirectional sync (source wins conflicts)
make diff # Diff SOURCE vs TARGET (full detail)
make diff-tldr # Diff SOURCE vs TARGET (summary)
make backup # Backup SOURCE instance
make restore FILE=<path> # Restore backup to TARGET
make daemon # Start sync daemon + UI (port 8089)
make daemon-stop # Stop sync daemon
make daemon-logs # Follow daemon logs
make build # Build the Docker image locally
make shell # Drop into an interactive container shellOverride source/target instances:
make sync SOURCE=secondary TARGET=primaryThe daemon runs a sync on a configurable schedule and serves a status UI at port 8089.
# Start the daemon (pre-creates state files, then starts the Docker Compose service)
make daemon
# Stop the daemon
make daemon-stop
# Follow logs
make daemon-logsThe make daemon target is the correct way to start it — it runs touch on the host-side
state files before Docker mounts them (Docker creates missing mount targets as directories,
which breaks JSON parsing).
Configure via environment variables in your shell or a .env file:
| Variable | Default | Description |
|---|---|---|
SYNC_SOURCE |
primary |
Source instance name |
SYNC_TARGET |
secondary |
Target instance name |
SYNC_INTERVAL |
21600 |
Seconds between syncs |
SYNC_MODE |
shallow |
Sync mode (shallow or deep) |
DAEMON_PORT |
8089 |
Web UI port |
The web UI at http://localhost:8089 shows sync status, countdown to next sync, a "Sync Now"
button, and a history table of recent runs.
The docker-compose.yml also includes a service for scheduled backups (separate from the daemon):
docker compose -f docker/docker-compose.yml up -d uptime-kuma-backup-cronTo run one-off commands:
docker compose -f docker/docker-compose.yml run --rm uptime-kuma-sync node src/uptime-kuma-backup.js primary
docker compose -f docker/docker-compose.yml run --rm uptime-kuma-sync node src/uptime-kuma-sync.js primary secondary
docker compose -f docker/docker-compose.yml run --rm uptime-kuma-sync node src/uptime-kuma-diff.js primary secondaryIf you prefer direct docker run commands:
# Build image
docker build -t uptime-kuma-sync:latest .
# Run backup
docker run --rm \
-v "$(pwd)/uptime-kuma-config.json:/app/uptime-kuma-config.json:ro" \
-v "$(pwd)/uptime-kuma-backups:/app/uptime-kuma-backups" \
uptime-kuma-sync:latest node src/uptime-kuma-backup.js primary
# Run sync
docker run --rm \
-v "$(pwd)/uptime-kuma-config.json:/app/uptime-kuma-config.json:ro" \
-v "$(pwd)/uptime-kuma-backups:/app/uptime-kuma-backups" \
uptime-kuma-sync:latest node src/uptime-kuma-sync.js primary secondaryThe easiest way to sync - just reference your instances by name:
# Sync from primary to secondary
./scripts/sync-uptime.sh primary secondary
# Or run directly:
node src/uptime-kuma-sync.js primary secondaryOutput example:
=== Creating Backup ===
Creating backup: uptime-kuma-backups/secondary-2026-03-01T15-30-00.json
Backup saved: 25 monitors, 5 tags
✓ Backup complete
=== Starting Sync ===
From: primary (https://uptime1.example.com)
To: secondary (https://uptime2.example.com)
...
Backups are automatically named based on the instance name!
Using .env file:
./scripts/sync-uptime.shOr use environment variables directly:
SOURCE_UPTIME_URL=http://localhost:3001 \
SOURCE_UPTIME_USER=admin \
SOURCE_UPTIME_PASS=password1 \
SOURCE_NAME=primary \
TARGET_UPTIME_URL=http://localhost:3002 \
TARGET_UPTIME_USER=admin \
TARGET_UPTIME_PASS=password2 \
TARGET_NAME=secondary \
node src/uptime-kuma-sync.jsThe sync tool supports two modes to fit different use cases:
Best for: Maintaining independent instances with different monitoring configurations
Shallow sync copies monitor definitions while preserving instance-specific settings on the target:
# Shallow sync - preserves target's check intervals and timeouts
./scripts/sync-uptime.sh primary secondary
node src/uptime-kuma-sync.js primary secondaryWhat gets synced:
- Monitor names and types
- URLs, hostnames, and ports
- Descriptions and keywords
- Accepted status codes
- Tags/groups (with colors)
- Headers, body, method
- Authentication settings
- Certificate settings
- Status pages (groups, monitor membership, page config)
What is preserved on the target:
- Check intervals
- Retry intervals
- Timeout values
- Max retries
- Notification settings
- DNS settings
Use cases:
- Syncing monitors to a backup instance with different check frequencies
- Maintaining a test environment with slower polling
- Keeping notification settings separate per instance
Best for: Creating exact replicas or clones
Deep sync copies everything from source to target, including all instance-specific settings:
# Deep sync - copies ALL settings including intervals
./scripts/sync-uptime.sh primary secondary --deep
node src/uptime-kuma-sync.js primary secondary --deepWhat gets synced:
- Everything from shallow mode PLUS:
- Check intervals
- Retry intervals
- Timeout values
- Max retries
- Notification settings
- DNS settings
- Accepted status codes
- All other configuration fields
Use cases:
- Creating an exact replica/clone of an instance
- Disaster recovery setup
- Migrating to a new instance
- Setting up identical production/staging environments
You can set the default mode in your config file:
{
"sync": {
"mode": "deep"
}
}Override the default with command-line flags:
# Force shallow sync even if config says deep
./scripts/sync-uptime.sh primary secondary --shallow
# Force deep sync even if config says shallow
./scripts/sync-uptime.sh primary secondary --deepBackup any instance by name:
# Backup named instance from config
node src/uptime-kuma-backup.js primary
# Creates: uptime-kuma-backups/primary-2026-03-01T15-30-00.jsonOr with environment variables:
UPTIME_URL=https://uptime.example.com \
UPTIME_USER=admin \
UPTIME_PASS=password \
node src/uptime-kuma-backup.js productionRestore to a named instance:
node src/uptime-kuma-restore.js uptime-kuma-backups/primary-2026-03-01.json secondaryOr with environment variables:
TARGET_UPTIME_URL=https://uptime.example.com \
TARGET_UPTIME_USER=admin \
TARGET_UPTIME_PASS=password \
node src/uptime-kuma-restore.js uptime-kuma-backups/backup.jsonNote: Restoring will ADD monitors from the backup. It won't delete existing monitors.
Compare monitors between two instances to see what's different:
# Using bash wrapper
./scripts/diff-uptime.sh primary secondary
# Or run directly
node src/uptime-kuma-diff.js primary secondary
# Or with npm
npm run diff primary secondary
# Show condensed summary (TL;DR mode)
./scripts/diff-uptime.sh primary secondary --tldr
node src/uptime-kuma-diff.js primary secondary --tldrThe diff tool shows:
- Identical monitors - Monitors that match completely
- Different monitors - Monitors with the same name but different settings
- Only in source - Monitors that exist only in the first instance
- Only in target - Monitors that exist only in the second instance
TL;DR Mode: Use --tldr flag to show a condensed summary with just monitor names and the most common differences, perfect for a quick overview.
Output Example:
Comparing monitors from primary to secondary...
Fetched 201 monitors from primary
Fetched 202 monitors from secondary
=== Summary ===
Identical monitors: 160
Different monitors: 41
Only in primary: 0
Only in secondary: 1
--- Monitors with differences (41) ---
• Core Svcs [group] - 1 field(s) different
• DNS - bubs.us.to [dns] - 1 field(s) different
• WEB - Bandle [http] - 2 field(s) different
...
--- Most common differences ---
• tags: 31 monitor(s)
• childrenIDs: 9 monitor(s)
• pathName: 9 monitor(s)
Or for full detail (without --tldr):
=== Differences ===
Monitor: Disk Usage
childrenIDs: [147,146,145] → [224,223,222]
...
See README.diff.md for detailed documentation.
Docker Usage:
# Using docker-compose
docker-compose run --rm uptime-kuma-sync ./scripts/diff-uptime.sh primary secondary
docker-compose run --rm uptime-kuma-sync ./scripts/diff-uptime.sh primary secondary --tldr
# Using Docker wrapper script
./scripts/uptime-kuma-docker.sh diff primary secondary
./scripts/uptime-kuma-docker.sh diff primary secondary --tldrThe sync tool is bi-directional and safe - you can sync in either direction with automatic backups. Use the diff tool to determine which instance has the correct configuration:
Safety Features:
- ✅ Automatic backup of target instance before sync
- ✅ Non-destructive - updates existing monitors and creates missing ones (doesn't delete)
- ✅ Preserves instance-specific settings (intervals, timeouts, notifications)
Workflow to Get Instances In Sync:
# 1. Compare both directions to see what's different
./scripts/diff-uptime.sh primary secondary --tldr
./scripts/diff-uptime.sh secondary primary --tldr
# 2. Identify your "source of truth" (the instance with correct data)
# - Which has the correct tags/groups?
# - Which has the correct monitor configurations?
# - Which has the latest changes you want to keep?
# 3. Sync FROM your source of truth TO the other instance
./scripts/sync-uptime.sh <correct-instance> <target-instance>
# 4. Verify instances are now in sync
./scripts/diff-uptime.sh primary secondary --tldrExample Scenario:
Your diff shows secondary has 1 extra monitor and different tags on 31 monitors:
# Check what secondary would change in primary
./scripts/diff-uptime.sh secondary primary --tldr
# If secondary has the correct tags, sync it to primary
./scripts/sync-uptime.sh secondary primary
# Or if primary is correct, sync the other direction
./scripts/sync-uptime.sh primary secondaryBackup Location: The tool creates timestamped backups in uptime-kuma-backups/ before each sync. You can restore if needed:
./scripts/restore-uptime.sh uptime-kuma-backups/primary-2026-03-01T15-30-00.json primarySet up a cron job to run periodically:
# Run every hour - sync from primary to secondary
0 * * * * cd /path/to/project && ./scripts/sync-uptime.sh primary secondary >> /var/log/uptime-sync.log 2>&1
# Daily backup of production instance
0 2 * * * cd /path/to/project && node src/uptime-kuma-backup.js production >> /var/log/uptime-backup.log 2>&1Define all your instances in one place:
{
"instances": {
"production": {
"url": "https://uptime-prod.example.com",
"username": "admin",
"password": "prod-password",
"description": "Production monitoring"
},
"staging": {
"url": "https://uptime-staging.example.com",
"username": "admin",
"password": "staging-password",
"description": "Staging environment"
},
"local": {
"url": "http://localhost:3001",
"username": "admin",
"password": "admin",
"description": "Local development"
}
},
"backup": {
"directory": "./uptime-kuma-backups"
},
"sync": {
"mode": "shallow",
"excludedFields": [
"interval",
"retryInterval",
"resendInterval",
"maxretries",
"timeout",
"upside_down",
"maxredirects",
"dns_resolve_type",
"dns_resolve_server",
"notificationIDList"
]
}
}Sync Mode:
"mode": "shallow"(default) - Preserves instance-specific settings on target"mode": "deep"- Copies all settings for an exact replica- Can be overridden with
--deepor--shallowflags
Benefits:
- Define once, use everywhere
- Automatic backup naming based on instance
- Easy to manage multiple instances
- No need to remember URLs and credentials
- Version control friendly (add to .gitignore)
Choose meaningful names for your instances:
production/backupprimary/secondarydatacenter1/datacenter2aws/azuremain/failover
These names appear in:
- Backup filenames
- Sync console output
- Log files
Note: The fields below apply to Shallow Sync mode (default). For Deep Sync mode, ALL fields are copied including instance-specific settings. See the Sync Modes section for details.
- Monitor name
- Monitor type (HTTP, TCP, Ping, etc.)
- URL/hostname
- Port
- Description
- Accepted status codes
- Tags/groups (with colors)
- Headers
- Body
- Method
- Authentication settings
- Certificate settings
- Keywords
- Status pages (groups, monitor membership, page config)
- Check interval
- Retry interval
- Resend interval
- Max retries
- Timeout
- Status inversion (upside down)
- Max redirects
- DNS settings
- Notification settings
In Deep Sync Mode: All the above instance-specific fields ARE synced for an exact replica.
Edit uptime-kuma-config.json to customize which fields are excluded:
{
"sync": {
"excludedFields": [
"interval",
"your_custom_field"
]
}
}Remove fields from the excludedFields array to sync them between instances.
Backups are JSON files containing:
- All monitors with complete configuration
- All tags/groups with colors
- All status pages (config, groups, and monitor membership)
- Timestamp and instance information
When using named instances, backups are automatically named:
- Format:
{instance-name}-{timestamp}.json - Example:
primary-2026-03-01T10-30-00.json
This makes it easy to identify which instance a backup is from!
Default: ./uptime-kuma-backups/
Configure in uptime-kuma-config.json:
{
"backup": {
"directory": "/path/to/backups"
}
}Or with environment variable:
export BACKUP_DIR=/path/to/backups# Keep last 30 days
find uptime-kuma-backups/ -name "*.json" -mtime +30 -delete
# Keep last 10 backups per instance
for instance in primary secondary; do
ls -t uptime-kuma-backups/${instance}-*.json | tail -n +11 | xargs rm -f
doneIf a sync goes wrong, restore from the automatic backup:
# Find the latest backup
ls -lt uptime-kuma-backups/
# Restore to the named instance
node src/uptime-kuma-restore.js uptime-kuma-backups/secondary-2026-03-01T15-30-00.json secondary- Initial Setup: Configure both instances with their desired intervals, timeouts, and notification settings
- Add Monitors: Add monitors to your "source" instance with appropriate tags/groups
- Run Sync: Execute sync with instance names:
./scripts/sync-uptime.sh primary secondary - Verify: Check target instance - monitors should be there with target's existing timing settings
- Regular Syncs: Schedule periodic syncs to keep monitors in sync
- Verify both instances are accessible
- Check firewall rules
- Ensure correct URLs (include http:// or https://)
- Verify username and password in config
- Check if 2FA is enabled (not supported)
- Ensure the user has admin privileges
- Tags are matched by name AND color
- If colors differ, new tags will be created
- Manually merge tags in the target instance if needed
Error: Instance 'xyz' not found in uptime-kuma-config.json
Available instances: primary, secondary, local
- Check spelling of instance name
- Verify instance exists in config file
- List available instances:
cat uptime-kuma-config.json | jq '.instances | keys'
Use the --bidirectional flag (or make sync-bidir) to sync monitors in both directions in a single run:
# Sync primary → secondary, then copy secondary-only monitors back to primary
make sync-bidir
# Or directly:
./scripts/uptime-kuma-docker.sh sync primary secondary --bidirectionalConflict resolution: Source always wins. If a monitor exists on both instances, the source version is authoritative. The bidirectional pass only copies monitors that exist exclusively on the target back to the source.
Mutually exclusive with --prune — you can't prune and bidirectional-sync in the same run.
- uptime-kuma-sync.js - Sync monitors between two instances (auto-backup, incremental, prune, bidirectional)
- uptime-kuma-backup.js - Standalone backup tool for any instance
- uptime-kuma-restore.js - Restore monitors from a backup file
- uptime-kuma-list.js - List monitors in an instance grouped by parent group
- uptime-kuma-diff.js - Compare monitors between two instances
- uptime-kuma-daemon.js - Scheduled sync daemon with web status UI (run via
make daemon)
- sync-uptime.sh - Convenience wrapper for syncing
- backup-uptime.sh - Convenience wrapper for backups
- restore-uptime.sh - Convenience wrapper for restoring
- diff-uptime.sh - Convenience wrapper for diffing instances
- uptime-kuma-docker.sh - All-in-one Docker wrapper (recommended)
- Dockerfile - Container definition
- docker-compose.yml - For scheduled backups and easy deployment
- uptime-kuma-config.json - Instance configuration (create from .example file)
- uptime-kuma-config.json.example - Template configuration file
- .env.uptime-kuma - Environment variable template (optional)
- The script uses Socket.IO to communicate with Uptime Kuma
- Monitors are matched by name + type
- Existing monitors are updated, new ones are created
- Deleted monitors in source are NOT deleted in target by default — use
--pruneto remove them - Incremental sync skips monitors whose hash hasn't changed; use
--forceto bypass - Automatic backups are created before every sync - No data loss risk!
- Instance names in config make it easy to manage multiple environments
Uptime Kuma uses Socket.IO events:
login- AuthenticategetMonitorList- Get all monitorsgetMonitor- Get monitor detailsgetTags- Get all tagsaddTag- Create tagadd- Create monitoreditMonitor- Update monitor