Files
unraid-docker-manager/.planning/research/STACK.md
T

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.


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/graphql or http://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:

  1. Image Digest Comparison — Unraid's DockerManifestService compares local image digest with registry manifest
  2. Update Status File/var/lib/docker/unraid-update-status.json stores per-container status (true = up-to-date, false = update available, undef = unknown)
  3. 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.phpsyncVersions() 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)
  • 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

Investigated but rejected:

/var/lib/docker/unraid-update-status.json

Structure (observed):

{
  "container1": true,
  "container2": false,
  "container3": "undef"
}

Why not write directly:

  1. Format undocumented — File structure found via forum posts, not official docs
  2. No UI refresh trigger — Writing file doesn't notify WebGUI to refresh
  3. Race conditions — Unraid's update checker runs periodically, may overwrite changes
  4. 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_ANY only
  • 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_ANY permission
  • Add API key to .env.unraid-api file
  • Verify n8n container can reach http://host.docker.internal/graphql (add --add-host if 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):

  1. Apps → Search "Unraid Connect"
  2. Install plugin
  3. Settings → Management Access → API → Enable

Source: Unraid API Documentation


Open Questions & Validation Needed

Low-priority research flags:

  1. 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)
  2. 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)
  3. 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:

  1. 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
  2. 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
  3. 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

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:

Source Code:

Forum Discussions: