15 KiB
Technology Stack — Unraid Update Status Sync
Project: Unraid Docker Manager Milestone: Update Status Sync (v1.3) Researched: 2026-02-08
Executive Summary
Recommendation: Use Unraid's native GraphQL API with updateContainer mutation to sync status after bot-initiated container updates.
This approach leverages Unraid's official API (available since 7.2, via Connect plugin for <7.2) to call the same update mechanism the WebGUI uses. The GraphQL updateContainer mutation triggers Dynamix Docker Manager's update workflow, which automatically handles image digest comparison and updates /var/lib/docker/unraid-update-status.json.
Confidence: HIGH — Based on official Unraid API documentation, source code analysis, and GraphQL schema.
Recommended Stack Additions
1. Unraid GraphQL API Client
| Component | Version | Purpose | Why |
|---|---|---|---|
| HTTP Request (n8n built-in) | n8n 1.x | GraphQL API calls | Already available, no new dependencies |
| Unraid API | 7.2+ or Connect plugin | Container update status sync | Official Unraid API, supported mechanism |
Installation: None required in n8n container. Requires Unraid API key creation on host.
Network Access:
- From n8n container → Unraid host:
http://host.docker.internal/graphql(requires--add-host=host.docker.internal:host-gateway) - Or use Unraid server IP:
http://192.168.x.x/graphqlorhttp://tower.local/graphql
2. Authentication
| Component | Purpose | Storage | Why |
|---|---|---|---|
| Unraid API Key | GraphQL authentication | .env.unraid-api (gitignored) |
Same pattern as n8n API credentials |
Permissions Required:
unraid-api apikey --create \
--name "Docker Manager Bot" \
--permissions "DOCKER:UPDATE_ANY" \
--description "Telegram bot container updates" \
--json
Minimum permission: DOCKER:UPDATE_ANY (allows calling updateContainer mutation)
Integration Architecture
How Unraid Tracks Update Status
Three-layer system:
- Image Digest Comparison — Unraid's
DockerManifestServicecompares local image digest with registry manifest - Update Status File —
/var/lib/docker/unraid-update-status.jsonstores per-container status (true= up-to-date,false= update available,undef= unknown) - Template Metadata — XML templates in
/boot/config/plugins/dockerMan/templates-user/store container configuration and version info
Critical Finding: Unraid does NOT auto-detect external updates (e.g., via Watchtower or direct Docker API). The updateContainer mutation must be called to sync status.
Source: limetech/dynamix DockerClient.php — syncVersions() function updates status file after successful update.
Update Sync Workflow
Bot updates container (current approach)
↓ docker pull + recreate via Docker API
↓ Container running new image
↓ Unraid still shows "update available" ← PROBLEM
↓
Call Unraid GraphQL API (new addition)
↓ mutation { docker { updateContainer(id: "...") { ... } } }
↓ Unraid's DockerService → Dynamix scripts
↓ syncVersions() writes to unraid-update-status.json
↓ Unraid UI shows "up-to-date" ← SOLVED
Idempotency: Safe to call updateContainer even if already updated — Unraid checks current vs. remote digest and no-ops if already synced.
GraphQL API Details
Endpoint
http://<unraid-host>/graphql
Authentication: Header x-api-key: <your-api-key>
Key Mutations
mutation UpdateSingleContainer {
docker {
updateContainer(id: "docker:HmiXBlJefBRPMS0m4iNYc") {
id
name
state
}
}
}
mutation UpdateMultipleContainers {
docker {
updateContainers(ids: ["docker:abc123", "docker:def456"]) {
id
name
state
}
}
}
Container ID Format: docker:<container_name> or retrieve via query first.
Source: Unraid API generated-schema.graphql
n8n Integration Pattern
Node: HTTP Request (built-in)
Configuration:
- Method:
POST - URL:
http://host.docker.internal/graphql(or Unraid IP) - Authentication: Header Auth
- Name:
x-api-key - Value:
{{$env.UNRAID_API_KEY}}(from.env.unraid-api)
- Name:
- Body (JSON):
{ "query": "mutation { docker { updateContainer(id: \"docker:{{$json.containerName}}\") { id name state } } }" }
Data Flow:
Telegram callback (container updated)
→ Extract container name
→ HTTP Request to Unraid GraphQL
→ Parse response
→ Telegram confirmation message
Alternatives Considered
| Approach | Pros | Cons | Verdict |
|---|---|---|---|
GraphQL API updateContainer |
Official API, handles all sync logic, idempotent, supported | Requires API key setup | RECOMMENDED |
Direct file write to unraid-update-status.json |
Simple, no auth needed | Brittle (file format undocumented), doesn't trigger UI refresh, race conditions with Unraid's update checker | DO NOT USE |
| Shell exec via Docker socket | Could call Dynamix scripts directly | Extremely fragile, requires PHP runtime, breaks on Unraid updates | DO NOT USE |
| Watchtower pattern (do nothing) | No code changes | Leaves stale "update available" badges, false-positive notifications | Current problem |
GraphQL updateAllContainers |
Syncs everything | Overkill (re-checks all containers), slower | Use for batch sync only |
File System Access (NOT Recommended)
Investigated but rejected:
/var/lib/docker/unraid-update-status.json
Structure (observed):
{
"container1": true,
"container2": false,
"container3": "undef"
}
Why not write directly:
- Format undocumented — File structure found via forum posts, not official docs
- No UI refresh trigger — Writing file doesn't notify WebGUI to refresh
- Race conditions — Unraid's update checker runs periodically, may overwrite changes
- Brittle — File location/format could change without notice
Confidence: MEDIUM (structure inferred from forum posts, confirmed in source code)
Source: Unraid Forums — Docker Update Status
/boot/config/plugins/dockerMan/templates-user/
Contains: XML templates with container configuration, including <Date> and <DateInstalled> fields (internal, auto-managed by Unraid).
Why not modify: Templates are for configuration, not runtime status. Unraid ignores template dates for update checking (uses image digests instead).
Network Configuration
Docker Network Modes in Unraid
| Mode | Access Unraid Host | Use Case |
|---|---|---|
| Bridge | Via 172.17.0.1 (gateway) or host.docker.internal |
Default, port mapping |
| Host | Via localhost |
Direct host network access |
| Custom:br0 | Via Unraid IP (macvlan, separate network) | Own IP on LAN |
n8n container likely uses: Bridge mode (most common for Unraid containers)
Accessing Unraid API from n8n Container
Option 1: host.docker.internal (recommended)
# Add to n8n container config (via Unraid Docker template):
--add-host=host.docker.internal:host-gateway
# Then in n8n workflow:
URL: http://host.docker.internal/graphql
Option 2: Unraid hostname/IP
URL: http://tower.local/graphql
# or
URL: http://192.168.1.100/graphql # Replace with actual Unraid IP
Verification:
# From inside n8n container:
docker exec -it n8n curl -I http://host.docker.internal/graphql
# Should return HTTP 400 (GraphQL requires POST) or 200
Source: Docker host.docker.internal guide
Security Considerations
API Key Management
Storage:
- Add to
.env.unraid-api(already gitignored) - Load in n8n workflow via environment variables
Permissions:
- Use least privilege:
DOCKER:UPDATE_ANYonly - Avoid
--roles ADMIN(grants full access)
Rotation:
- API keys don't expire, but should be rotated periodically
- Delete via CLI:
unraid-api apikey --delete <key-id>
Source: Unraid API Key Management
Network Exposure
Unraid API runs on:
- HTTP (port 80) or HTTPS (port 443) on Unraid host
- Same interface as WebGUI
Risk: n8n container can access full GraphQL API (not just Docker mutations)
Mitigation: Use scoped API key (limits permissions to Docker operations only)
Implementation Checklist
- Create Unraid API key with
DOCKER:UPDATE_ANYpermission - Add API key to
.env.unraid-apifile - Verify n8n container can reach
http://host.docker.internal/graphql(add--add-hostif needed) - Create HTTP Request credential in n8n (Header Auth with
x-api-key) - Add GraphQL mutation call to Update sub-workflow after successful Docker API update
- Test: Update container via bot → verify Unraid UI shows "up-to-date"
- Handle errors: GraphQL response parsing, network failures, auth errors
What NOT to Add
Do NOT add:
- ❌ File system watchers for
/var/lib/docker/unraid-update-status.json - ❌ Custom PHP scripts to call Dynamix functions
- ❌ Cron jobs to periodically sync status
- ❌ Docker socket mounting to execute Unraid shell commands
- ❌ Watchtower or similar auto-update tools (conflicts with bot's update control)
Why: These approaches are brittle, unsupported, or conflict with the bot's explicit update model.
Version Compatibility
| Unraid Version | API Availability | Notes |
|---|---|---|
| 7.2+ | Built-in | Native GraphQL API |
| 6.9 - 7.1 | Via Connect plugin | Install from Community Applications |
| <6.9 | Not available | Upgrade Unraid required |
Check version:
# SSH to Unraid:
cat /etc/unraid-version
Install Connect plugin (pre-7.2):
- Apps → Search "Unraid Connect"
- Install plugin
- Settings → Management Access → API → Enable
Source: Unraid API Documentation
Open Questions & Validation Needed
Low-priority research flags:
-
Container ID resolution — Does GraphQL require
docker:<name>prefix, or just<name>?- Resolution: Query containers first to get exact ID format
- Impact: Low (easily testable during implementation)
-
Rate limiting — Does Unraid API have rate limits for mutations?
- Confidence: LOW (not documented)
- Impact: Low (bot updates are infrequent, <10/min even in batch mode)
-
GraphQL subscription for status changes — Could bot subscribe to Docker events?
- Finding: Schema includes subscriptions, but not needed for status sync
- Verdict: Defer to future enhancement (real-time status monitoring)
Sources & Confidence Assessment
| Finding | Confidence | Primary Source |
|---|---|---|
| GraphQL API exists with updateContainer mutation | HIGH | Unraid API Schema |
| updateContainer triggers Dynamix sync workflow | HIGH | DeepWiki — Docker Integration |
| syncVersions() updates status JSON file | HIGH | limetech/dynamix source |
| API key requires DOCKER:UPDATE_ANY permission | MEDIUM | API Key Management (exact permission not explicitly stated) |
| Container ID format is "docker:" | MEDIUM | Unraid API examples (needs verification) |
| host.docker.internal works in Unraid Docker | MEDIUM | Forum discussions (standard Docker feature, but Unraid-specific confirmation limited) |
| /var/lib/docker/unraid-update-status.json structure | MEDIUM | Forum posts (observed, not officially documented) |
| No rate limiting on GraphQL API | LOW | Assumption (not documented either way) |
Overall Confidence: HIGH — Core approach (GraphQL API) is well-documented and official. Implementation details need testing but low-risk.
Next Steps for Roadmap
Phase structure recommendations:
-
Phase 1: API Setup & Testing
- Create API key
- Test GraphQL query/mutation from command line
- Verify network access from n8n container
- Why first: Validates approach before n8n integration
-
Phase 2: n8n Integration
- Add HTTP Request node to Update sub-workflow
- GraphQL mutation call after Docker update
- Error handling for API failures
- Why second: Builds on validated API access
-
Phase 3: Batch Sync Support
- Optional: Call
updateContainers(plural) for batch updates - Handle partial failures (some containers sync, others fail)
- Why third: Enhancement after core functionality works
- Optional: Call
Research flags:
- Phase 1: Likely needs deeper research (network access testing, container ID format verification)
- Phase 2: Standard patterns, unlikely to need additional research
- Phase 3: Defer until Phase 2 validates approach
Additional Resources
Official Documentation:
Community Resources:
- Unraid MCP Server — Reference implementation of GraphQL client
- Home Assistant Unraid Integration — Another GraphQL client example
Source Code:
- limetech/dynamix — Unraid's Docker Manager plugin
- unraid/api — Official API monorepo
Forum Discussions: