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>
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 enabledN8N_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:
- Create API key in n8n Settings > n8n API
- Store key securely (not in repository)
- Use HTTP requests to n8n API endpoints
- 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:
- Cannot pass dynamic JSON for
reply_markup - Expressions in keyboard fields cause "The value is not supported!" errors
- 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:plexinstead ofstart: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
- PR #17258: JSON Keyboard Support
- Custom Telegram Node
- Telegram Bot API - Inline Keyboards
Unraid Integration
How Unraid Detects Updates
Unraid checks for Docker image updates by comparing local image digests against remote registry digests:
- Local image has digest (e.g.,
35049b54ac64) - Unraid queries registry for
latesttag digest (e.g.,96c1da19c304) - 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.jsonand 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:
- After bot successfully updates a container, delete the status file
- Document that users should click "Check for Updates" in Unraid UI to refresh badges
- 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:
- Unraid Forum: Docker shows "update ready" after updating
- Watchtower + Unraid Discussion
- Unraid Forum: Incorrect docker update notification
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
- Docker socket proxy - Security improvement, low risk, well-documented
- Telegram inline keyboards - UX improvement, proven pattern
- n8n API access - Developer tooling, not user-facing
- 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