# 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: " 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:** - [n8n API Authentication](https://docs.n8n.io/api/authentication/) - [n8n API Reference](https://docs.n8n.io/api/api-reference/) - [Disable Public API](https://docs.n8n.io/hosting/securing/disable-public-api/) --- ## 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:** ```bash # 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:** ```bash 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:** - [Tecnativa docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) - [LinuxServer socket-proxy](https://docs.linuxserver.io/images/docker-socket-proxy/) - [Wollomatic socket-proxy](https://github.com/wollomatic/socket-proxy) --- ## 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:** ```json // 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: ```javascript // In Code node const callbackData = $json.callback_query.data; const [action, container] = callbackData.split(':'); return { action, container }; ``` **Answer Callback Query (remove loading spinner):** ```json // 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:** - [n8n Telegram Callback Operations](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/callback-operations/) - [PR #17258: JSON Keyboard Support](https://github.com/n8n-io/n8n/pull/17258) - [Custom Telegram Node](https://github.com/topvisor/n8n-nodes-telegram-send-message-custom) - [Telegram Bot API - Inline Keyboards](https://core.telegram.org/bots/api#inlinekeyboardmarkup) --- ## 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: ```bash # 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:** - [Unraid Forum: Docker shows "update ready" after updating](https://forums.unraid.net/topic/157820-docker-shows-update-ready-after-updating/) - [Watchtower + Unraid Discussion](https://github.com/containrrr/watchtower/discussions/1389) - [Unraid Forum: Incorrect docker update notification](https://forums.unraid.net/bug-reports/stable-releases/regression-incorrect-docker-update-notification-r2807/) --- ## 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