diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..40dbb5f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "🚀 1. n8n: Run local test container", + "detail": "Run n8n locally using docker with official image mapped to port 5678", + "type": "shell", + "command": "docker run -d --name n8n-local-test -p 5678:5678 n8nio/n8n:2.8.3", + "group": "build", + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared" + } + }, + { + "label": "🛑 2. n8n: Stop and remove local container", + "detail": "Forces stop and removal of the test container", + "type": "shell", + "command": "docker rm -f n8n-local-test", + "group": "test", + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared", + "close": true + } + }, + { + "label": "✅ 3. n8n: Validate render.yaml syntax", + "detail": "Use a temporary docker container to check YAML syntax", + "type": "shell", + "command": "docker run --rm -v \"${workspaceFolder}:/workspace\" -w /workspace mikefarah/yq -e . render.yaml", + "group": "test", + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared" + } + } + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 46bf0e0..0000000 --- a/Dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -# ETAP 1: Pobieramy apk -FROM alpine:latest AS builder -RUN apk add --no-cache apk-tools-static - -# ETAP 2: Docelowy obraz n8n -FROM n8nio/n8n:2.8.3 - -USER root - -# Krok 1: Przywracamy apk -COPY --from=builder /sbin/apk.static /sbin/apk -RUN /sbin/apk -X http://dl-cdn.alpinelinux.org/alpine/latest-stable/main -U --allow-untrusted --initdb add apk-tools - -# Krok 2: Instalujemy Pythona, venv oraz GIT-a -RUN apk update && apk add --no-cache python3 py3-pip py3-virtualenv git - -# Krok 3: Odtworzenie brakującego kodu runnera Pythona (Błąd obrazu n8n) -RUN mkdir -p /usr/local/lib/node_modules/@n8n && \ - git clone --depth 1 https://github.com/n8n-io/n8n.git /tmp/n8n-repo && \ - cp -r /tmp/n8n-repo/packages/@n8n/task-runner-python /usr/local/lib/node_modules/@n8n/ && \ - rm -rf /tmp/n8n-repo - -# Krok 4: Budowa .venv i instalacja zoptymalizowanej paczki ETL (~220MB) -RUN cd /usr/local/lib/node_modules/@n8n/task-runner-python && \ - python3 -m venv .venv && \ - .venv/bin/pip install --no-cache-dir requests websockets pandas numpy openpyxl beautifulsoup4 python-dateutil && \ - chmod -R 777 /usr/local/lib/node_modules/@n8n/task-runner-python && \ - chown -R node:node /usr/local/lib/node_modules/@n8n/task-runner-python - -# Krok 5: Utworzenie bezpiecznego folderu tymczasowego (rozwiązanie "insufficient permissions") -RUN mkdir -p /tmp/n8n_runner && \ - chown -R node:node /tmp/n8n_runner && \ - chmod -R 777 /tmp/n8n_runner - -# Krok 6: Nadanie domyślnych uprawnień dla procesu n8n -RUN chown -R node:node /usr/local/lib/node_modules/n8n && \ - mkdir -p /home/node/.n8n && chown -R node:node /home/node/.n8n - -USER node -WORKDIR /home/node diff --git a/manual step by step instructions b/MANUAL_DEPLOY.md similarity index 100% rename from manual step by step instructions rename to MANUAL_DEPLOY.md diff --git a/README.md b/README.md index df707f6..e5ae13c 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,39 @@ -# 🚀 n8n v2.8.3 with Fixed Python Support for Render.com +# n8n v2.8.3 Render Blueprint -[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/api29200/n8n_v2.8.3-render-python) +[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy) -This repository provides a custom, production-ready Docker image for **n8n v2.8.3** that fixes the "Virtual environment is missing" and "insufficient permissions" errors specifically on Render.com. +This repository provides a Render Blueprint (`render.yaml`) to deploy the official n8n v2.8.3 Docker image (`docker.io/n8nio/n8n:2.8.3`) to Render with a persistent disk. -## 🛠️ The Fix (Internal Task Runner) -The official n8n Docker image for 2.8.3 is missing the Python Task Runner source code, and Render's security policy (`noexec` on `/tmp`) blocks default execution. +The service is blueprint-only. It does not build or publish a custom Docker image. -**This repo fixes it by:** -- **Code Injection:** Cloning the missing `@n8n/task-runner-python` source directly into the image. -- **Dependency Fix:** Pre-installing `websockets` (missing in original runner) and common ETL libs (`pandas`, `numpy`, `requests`, `beautifulsoup4`). -- **Permission Bypass:** Redirecting the runner to `/tmp/n8n_runner` with full ownership for the `node` user. +## One-Click Installation -## 📸 Proof it Works -![Python Node Working](https://raw.githubusercontent.com/api29200/n8n_v2.8.3-render-python/main/screenshot1.png) -*Success! Python Code Node executing with external libraries on Render.* +1. Deploy this repository as a Render Blueprint. +2. Use a paid instance plan that supports persistent disks. +3. Set `WEBHOOK_URL` and `N8N_EDITOR_BASE_URL` to the public Render service URL. +4. Set `N8N_ENCRYPTION_KEY` once and keep it stable across redeploys. +5. Deploy the service and confirm `/healthz` is healthy. -## 🚀 One-Click Installation -1. Click the **Deploy to Render** button above. -2. Select **Starter** plan (required for Disk persistence). -3. Set your `WEBHOOK_URL` (the URL Render gives you). -4. **Done!** Python nodes will work out of the box. +## Repository Contents -## 📦 Pre-installed Python Packages -- `pandas` & `numpy` (Data Processing) -- `requests` (API interaction) -- `beautifulsoup4` (Scraping) -- `openpyxl` (Excel support) -- `websockets` (Core requirement) +- `render.yaml`: Render Blueprint configuration for the official n8n image, environment variables, health check, and persistent disk. +- `MANUAL_DEPLOY.md`: Optional manual deployment notes if this file exists in your branch. -## 🔧 Why use this instead of official image? -The official image throws an `Attempt to read execution was blocked due to insufficient permissions` error on Render. This happens because the runner fails to start due to missing files in `/usr/local/lib/node_modules/@n8n/`. We've reverse-engineered the path traversal and restored the environment. +## Configuration ---- -Created by [api29200](https://github.com/api29200) | Found a bug? Open an issue! +The Blueprint configures: + +- `runtime: image` with `docker.io/n8nio/n8n:2.8.3` +- `N8N_PORT=5678` +- SQLite persistence at `/home/node/.n8n/database.sqlite` +- Disk persistence at `/home/node/.n8n` +- Bangkok timezone defaults + +## Production hardening + +- Uses Render's prebuilt-image Blueprint syntax with `runtime: image` and the official `docker.io/n8nio/n8n:2.8.3` image. +- Prompts for `WEBHOOK_URL` and `N8N_EDITOR_BASE_URL` during Blueprint setup so deploy URLs are not hard-coded in git. +- Keeps `N8N_ENCRYPTION_KEY` outside git so encrypted credentials survive redeploys when the same value is reused. +- Keeps execution data smaller by saving errors, pruning old executions, and avoiding successful/manual execution data by default. +- Emits JSON logs to stdout for cleaner Render log search and external log shipping. +- Attaches a persistent disk at `/home/node/.n8n`; increase it before it fills because Render disks can be expanded but not reduced. diff --git a/render.yaml b/render.yaml index c48cbff..49642e5 100644 --- a/render.yaml +++ b/render.yaml @@ -1,38 +1,79 @@ services: - type: web - name: n8n-v2-8-3-python - env: docker + name: patsticker-n8n + runtime: image plan: starter - region: frankfurt - disk: - name: n8n_data - mountPath: /home/node/.n8n - sizeGB: 1 + image: + url: docker.io/n8nio/n8n:2.8.3 + healthCheckPath: /healthz + autoDeploy: true + maxShutdownDelaySeconds: 120 envVars: + - key: NODE_ENV + value: production + - key: PORT + value: 5678 - key: N8N_PORT value: 5678 + - key: N8N_LISTEN_ADDRESS + value: 0.0.0.0 - key: N8N_PROTOCOL value: https - - key: N8N_HOST - value: 0.0.0.0 - - key: N8N_RUNNERS_MODE - value: internal - - key: N8N_RUNNERS_TEMP_DIRECTORY - value: /tmp/n8n_runner - - key: N8N_ENCRYPTION_KEY - generateValue: true + - key: N8N_PROXY_HOPS + value: 1 - key: WEBHOOK_URL sync: false - placeholder: "https://your-service-name.onrender.com" - - key: N8N_NODES_CODE_CAN_REQUIRE_MODULES_BUILTIN - value: fs,path,child_process,os,util - - key: N8N_NODES_CODE_CAN_REQUIRE_MODULES_EXTERNAL - value: "*" - - key: N8N_RUNNERS_EXTERNAL_ALLOW - value: "*" - - key: N8N_RUNNERS_STDLIB_ALLOW - value: "*" - - key: EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS - value: "false" + - key: N8N_EDITOR_BASE_URL + sync: false + - key: N8N_ENCRYPTION_KEY + sync: false + - key: DB_TYPE + value: sqlite + - key: DB_SQLITE_DATABASE + value: /home/node/.n8n/database.sqlite + - key: DB_SQLITE_VACUUM_ON_STARTUP + value: "true" + - key: N8N_USER_FOLDER + value: /home/node/.n8n + - key: GENERIC_TIMEZONE + value: Asia/Bangkok + - key: TZ + value: Asia/Bangkok + - key: EXECUTIONS_TIMEOUT + value: 900 + - key: EXECUTIONS_TIMEOUT_MAX + value: 3600 - key: EXECUTIONS_DATA_SAVE_ON_ERROR value: all + - key: EXECUTIONS_DATA_SAVE_ON_SUCCESS + value: none + - key: EXECUTIONS_DATA_SAVE_ON_PROGRESS + value: "false" + - key: EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS + value: "false" + - key: EXECUTIONS_DATA_PRUNE + value: "true" + - key: EXECUTIONS_DATA_MAX_AGE + value: 168 + - key: EXECUTIONS_DATA_PRUNE_MAX_COUNT + value: 5000 + - key: N8N_LOG_LEVEL + value: info + - key: N8N_LOG_OUTPUT + value: console + - key: N8N_LOG_FORMAT + value: json + - key: N8N_GRACEFUL_SHUTDOWN_TIMEOUT + value: 110 + - key: N8N_DIAGNOSTICS_ENABLED + value: "false" + - key: N8N_VERSION_NOTIFICATIONS_ENABLED + value: "false" + - key: LINE_CHANNEL_SECRET + sync: false + - key: ALLOW_LINE_SIGNATURE_BYPASS + value: "false" + disk: + name: n8n-data + mountPath: /home/node/.n8n + sizeGB: 5