Files
unraid-docker-manager/.planning/research/STACK.md
T
Lucas Berger 811030cee4 docs: complete v1.1 research (4 researchers + synthesis)
Files:
- STACK.md: Socket proxy, n8n API, Telegram keyboards
- FEATURES.md: Table stakes, differentiators, MVP scope
- ARCHITECTURE.md: Integration points, data flow changes
- PITFALLS.md: Top 5 risks with prevention strategies
- SUMMARY.md: Executive summary, build order, confidence

Key findings:
- Stack: LinuxServer socket-proxy, HTTP Request nodes for keyboards
- Architecture: TCP curl migration (~15 nodes), new callback routes
- Critical pitfall: Socket proxy breaks existing curl commands

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 22:09:06 -05:00

13 KiB

Stack Research: v1.1 Features

Project: Unraid Docker Manager Researched: 2026-02-02 Focus: Stack additions for n8n API, Docker socket security, Telegram keyboards, Unraid integration

n8n API Access

Overview

n8n provides a public REST API for programmatic workflow management. This enables Claude Code to read, update, and test workflows without manual UI interaction.

Authentication

Method: API Key via HTTP header

Setting Value
Header name X-N8N-API-KEY
Key location n8n UI: Settings > n8n API > Create an API key
Base path /api/v1

Environment Variables:

  • N8N_PUBLIC_API_DISABLED=false (default) - API enabled
  • N8N_PUBLIC_API_SWAGGERUI_DISABLED=false (default) - Swagger UI enabled

The API is enabled by default on self-hosted n8n. No additional configuration needed unless it was explicitly disabled.

Key Endpoints

Endpoint Method Purpose
/api/v1/workflows GET List all workflows
/api/v1/workflows/{id} GET Get workflow JSON
/api/v1/workflows/{id} PUT Update workflow
/api/v1/workflows/{id}/activate POST Activate workflow
/api/v1/workflows/{id}/deactivate POST Deactivate workflow
/api/v1/executions GET List executions (with logs)
/api/v1/executions/{id} GET Get execution details

API Playground

Self-hosted n8n includes a built-in Swagger UI at /api/v1/docs (or similar path based on configuration). This provides interactive documentation for testing API calls.

Integration with Claude Code

To enable Claude Code workflow management:

  1. Create API key in n8n Settings > n8n API
  2. Store key securely (not in repository)
  3. Use HTTP requests to n8n API endpoints
  4. Example: curl -H "X-N8N-API-KEY: <key>" http://localhost:5678/api/v1/workflows

Confidence: MEDIUM - Official docs confirm API exists and authentication method. Specific endpoint paths verified through multiple sources but not directly tested.

Sources:


Docker Socket Security

The Problem

Current setup mounts Docker socket directly into internet-exposed n8n container:

-v /var/run/docker.sock:/var/run/docker.sock

This is a security risk: if n8n is compromised, attacker has full Docker (root) access to the host.

Solution: Docker Socket Proxy

A socket proxy sits between containers and the Docker socket, filtering API requests to only allow specific operations.

Option Comparison

Feature Tecnativa LinuxServer Wollomatic
Base HAProxy (Alpine) HAProxy (Alpine) Go (scratch)
Image size ~10MB ~10MB ~3MB
Config method Environment variables Environment variables Regex allowlists
Granularity Per-API section Per-API section Per-endpoint regex
Active maintenance Yes Yes Yes
Unraid compatibility Yes Yes Yes

Recommendation: LinuxServer/socket-proxy

Why: Drop-in replacement for Tecnativa with better documentation and active LinuxServer community support. Familiar to Unraid users.

Configuration for This Project

The bot needs these Docker API operations:

  • List containers (/containers/json)
  • Inspect container (/containers/{id}/json)
  • Start container (/containers/{id}/start)
  • Stop container (/containers/{id}/stop)
  • Restart container (/containers/{id}/restart)
  • Pull image (/images/create)
  • Create container (/containers/create)
  • Remove container (/containers/{id})
  • Container logs (/containers/{id}/logs)

Required Environment Variables:

# LinuxServer socket-proxy configuration
CONTAINERS=1      # Container list/inspect
IMAGES=1          # Image pull
POST=1            # Enable POST requests (needed for start/stop/restart/create)
ALLOW_START=1     # /containers/{id}/start
ALLOW_STOP=1      # /containers/{id}/stop
ALLOW_RESTARTS=1  # /containers/{id}/restart (also enables /kill)

# Keep defaults (already enabled)
EVENTS=1          # Default
PING=1            # Default
VERSION=1         # Default

Deployment Architecture

                    [Internet]
                         |
                    [n8n container]
                         |
                    [socket-proxy]  <-- internal network only
                         |
                    [Docker socket]

n8n container changes:

  • Remove: -v /var/run/docker.sock:/var/run/docker.sock
  • Add: DOCKER_HOST=tcp://socket-proxy:2375
  • Add: Connect to same Docker network as socket-proxy

Socket-proxy container:

docker run -d \
  --name socket-proxy \
  --restart=unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --read-only \
  --tmpfs /run \
  -e CONTAINERS=1 \
  -e IMAGES=1 \
  -e POST=1 \
  -e ALLOW_START=1 \
  -e ALLOW_STOP=1 \
  -e ALLOW_RESTARTS=1 \
  --network internal \
  lscr.io/linuxserver/socket-proxy:latest

CRITICAL: Never expose socket-proxy port (2375) to external networks. Use internal Docker network only.

Confidence: HIGH - Official documentation from both Tecnativa and LinuxServer confirms configuration options and security model.

Sources:


Telegram Inline Keyboards

The Problem

n8n's native Telegram node has limitations with inline keyboards:

  1. Cannot pass dynamic JSON for reply_markup
  2. Expressions in keyboard fields cause "The value is not supported!" errors
  3. PR #17258 adding JSON keyboard support has been pending since July 2025

Solution Options

Option Approach Pros Cons
HTTP Request node Direct Telegram API calls Full control, no dependencies Token in URL, more setup
Custom community node @topvisor/n8n-nodes-telegram-send-message-custom Easy JSON support External dependency
Wait for PR #17258 Native n8n support No workarounds needed Indefinite timeline

Recommendation: HTTP Request Node

Why: No external dependencies, full Telegram API access, already proven pattern in similar projects.

Implementation

Send Message with Inline Keyboard:

// HTTP Request node
// URL: https://api.telegram.org/bot{{ $credentials.telegramApi.token }}/sendMessage
// Method: POST
// Body Type: JSON
{
  "chat_id": "={{ $json.message.chat.id }}",
  "text": "Select a container:",
  "parse_mode": "HTML",
  "reply_markup": {
    "inline_keyboard": [
      [
        {"text": "plex", "callback_data": "start:plex"},
        {"text": "sonarr", "callback_data": "start:sonarr"}
      ],
      [
        {"text": "radarr", "callback_data": "start:radarr"},
        {"text": "Cancel", "callback_data": "cancel"}
      ]
    ]
  }
}

Handle Callback Query:

The workflow already handles callback_query via the Telegram Trigger node (confirmed in current workflow). The callback_data format action:container allows parsing:

// In Code node
const callbackData = $json.callback_query.data;
const [action, container] = callbackData.split(':');
return { action, container };

Answer Callback Query (remove loading spinner):

// HTTP Request node
// URL: https://api.telegram.org/bot{{ $credentials.telegramApi.token }}/answerCallbackQuery
// Method: POST
{
  "callback_query_id": "={{ $json.callback_query.id }}",
  "text": "Processing..."
}

Callback Data Limits

Telegram limits callback_data to 64 bytes. Use short encodings:

  • s:plex instead of start:plex
  • Single char actions: s=start, t=stop, r=restart, u=update, l=logs

Alternative: Custom Community Node

If HTTP Request becomes unwieldy, install:

Settings > Community Nodes > Install
Package: @topvisor/n8n-nodes-telegram-send-message-custom

This allows passing any Telegram API parameters as JSON, including reply_markup.

Confidence: MEDIUM - HTTP Request approach confirmed working by multiple community members. Native node limitations confirmed by open issues and PR #17258.

Sources:


Unraid Integration

How Unraid Detects Updates

Unraid checks for Docker image updates by comparing local image digests against remote registry digests:

  1. Local image has digest (e.g., 35049b54ac64)
  2. Unraid queries registry for latest tag digest (e.g., 96c1da19c304)
  3. If different, shows "Update Available" badge

Update status is stored in: /var/lib/docker/unraid-update-status.json

The Problem

When containers are updated externally (Watchtower, Portainer, or our bot), Unraid doesn't detect the change:

  • Container updates successfully
  • Unraid still shows "Update Available" badge
  • Manual "Check for Updates" doesn't fix it
  • Only deleting unraid-update-status.json and re-checking clears it

Root Cause

Unraid only checks for newly available updates, not for containers that are no longer out of date. This is a known regression/limitation in Unraid's Docker management.

Solution Options

Option Approach Reliability
Delete status file rm /var/lib/docker/unraid-update-status.json after update HIGH - forces full recheck
Trigger recheck Unraid WebUI "Check for Updates" after file delete MEDIUM - requires UI or API
Accept mismatch Document that badge may be stale LOW - poor UX

Recommendation: Delete Status File + Document

Approach:

  1. After bot successfully updates a container, delete the status file
  2. Document that users should click "Check for Updates" in Unraid UI to refresh badges
  3. Future enhancement: investigate if Unraid has an API to trigger update check

Implementation:

Add to update workflow after successful container recreation:

# In Execute Command node (runs on Unraid host)
rm -f /var/lib/docker/unraid-update-status.json

Caveat: This requires the n8n container to have access to /var/lib/docker/ on the host, which is a security consideration. Alternative: document the manual step.

Integration Points

File/API Purpose Access Method
/var/lib/docker/unraid-update-status.json Update badge status Host filesystem
Unraid WebUI Trigger update check Manual (no API found)

Confidence: MEDIUM - File location and behavior confirmed by multiple Unraid forum threads. No official Unraid API documentation found for programmatic update checks.

Sources:


Recommendations Summary

Stack Additions

Component Recommendation Confidence
n8n API Use existing public API with API key auth MEDIUM
Docker security LinuxServer socket-proxy HIGH
Telegram keyboards HTTP Request node to Telegram API MEDIUM
Unraid sync Delete status file after update MEDIUM

Implementation Order

  1. Docker socket proxy - Security improvement, low risk, well-documented
  2. Telegram inline keyboards - UX improvement, proven pattern
  3. n8n API access - Developer tooling, not user-facing
  4. Unraid update sync - Nice-to-have, requires additional host access

No New Dependencies Required

All solutions use existing n8n capabilities:

  • HTTP Request node (Telegram API, Docker via proxy)
  • Execute Command node (Unraid file deletion)
  • n8n public API (existing feature)

The only new container is socket-proxy, which is infrastructure, not application code.

Key Risks

Risk Mitigation
Socket proxy misconfiguration Test each Docker operation after setup
Telegram API token exposure Use n8n credentials, never log full URLs
Unraid status file access May need additional volume mount or manual step
n8n API key security Store outside repository, rotate periodically

Metadata

Research date: 2026-02-02 Valid until: 2026-03-02 (30 days)

Confidence breakdown:

  • n8n API: MEDIUM - Docs confirm existence, specific endpoints need validation
  • Docker socket proxy: HIGH - Official docs, multiple implementations
  • Telegram keyboards: MEDIUM - Community-confirmed workarounds
  • Unraid integration: MEDIUM - Forum-confirmed behavior, no official API

Gaps:

  • n8n API specific endpoint paths should be validated via Swagger UI
  • Unraid may have undocumented API for update checks (not found)
  • PR #17258 merge timeline unknown