[Help] "Read/Write Files" node says "not writable", but "Execute Command" (touch) works fine

Hi everyone,

I’m facing a weird permission issue on my Self-hosted n8n (Docker Compose) VPS instance. I hope someone can shed some light on this.

The Problem: I cannot use the “Read/Write Files from Disk” node to save a binary file. It always returns:

Error: The file "/home/node/video/myjsonfile.json" is not writable.

The Strange Part (Debugging):

  • OS Permissions are fine: I verified this by using the “Execute Command” node with touch /home/node/video/test.txt. This works successfully! The file is created.

  • Ownership is correct: The folder is owned by node:node (UID 1000).

  • Path: I have mapped the volume correctly in docker-compose.yml.

My Setup:

  • n8n Version: 2.1.4

  • Installation: Docker Compose (VPS-hosted)

  • OS: Ubuntu

  • User: node (UID 1000)

What I have tried:

  1. Volume Mapping: I tried mapping to both /home/node/video and /home/node/.n8n/video. Both result in the same error.

  2. Permissions: I ran chown -R 1000:1000 on the host folder. Inside the container, ls -ld shows drwxr-xr-x node node.

  3. Environment Variables:

    • I tried setting N8N_RESTRICT_FILE_ACCESS_TO=/home/node/video,/tmp

    • I also tried commenting it out completely (to disable restriction).

    • I ran docker compose down and up -d after every change.

Question: If the OS permission allows the n8n user to touch a file via the “Execute Command” node, why does the “Write to Disk” node block the operation? Is there a hidden security restriction in v2.1.4 preventing writes to specific mapped volumes?

my docker compose here:

services:
n8n:
image: docker.n8n.io/n8nio/n8n
restart: always
environment:

  • N8N_HOST=your-domain.com
  • N8N_EDITOR_BASE_URL=https://your-domain.com/
  • WEBHOOK_URL=https://your-domain.com/
  • N8N_SECURE_COOKIE=false
  • GENERIC_TIMEZONE=Asia/Bangkok
  • TZ=Asia/Bangkok
  • DB_TYPE=postgresdb
  • DB_POSTGRESDB_DATABASE=n8n
  • DB_POSTGRESDB_HOST=postgresql
  • DB_POSTGRESDB_PORT=5432
  • DB_POSTGRESDB_USER=n8n_user
  • DB_POSTGRESDB_SCHEMA=public
  • DB_POSTGRESDB_PASSWORD=your_db_password_here
  # Security & Command Execution Settings
  - NODES_EXCLUDE="[]"
  - N8N_NODES_CAN_EXECUTE_COMMANDS=true
  - N8N_RESTRICT_FILE_ACCESS_TO=/home/node/.n8n/video,/tmp

volumes:
  - n8n-data:/home/node/.n8n
  - ./video:/home/node/.n8n/video

depends_on:
  postgresql:
    condition: service_healthy
healthcheck:
  test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/healthz"]
  interval: 5s
  timeout: 20s
  retries: 10
ports:
  - "5678:5678"

postgresql:
image: postgres:16-alpine
restart: always
volumes:

  • postgresql-data:/var/lib/postgresql/data
    environment:
  • POSTGRES_USER=n8n_user
  • POSTGRES_PASSWORD=your_db_password_here
  • POSTGRES_DB=n8n
    healthcheck:
    test: [“CMD-SHELL”, “pg_isready -U n8n_user -d n8n”]
    interval: 5s
    timeout: 20s
    retries: 10

tunnel:
image: cloudflare/cloudflared:latest
restart: always

Hided sensitive token

command: tunnel --no-autoupdate run --token <YOUR_CLOUDFLARE_TOKEN_HERE>

volumes:
n8n-data:
postgresql-data:

Any help would be greatly appreciated!

Hi @peraphat.boonndet ,

It looks like you set the wrong path. In your config you have the dir which includes a .n8n sub dir

However in your node, you’re using a different path. Remove the “/.n8n” from the env var and try again

Make sure you are using the exact same paths as configured

2 Likes

Thanks you for the suggestions!
I managed to solve the issue. I decided to start fresh with a cleaner docker-compose.yml setup.

Here is what worked for me:

  1. Simplified Volume Mapping: I mapped a dedicated local folder (./local-files) to /files inside the container.

  2. Correct Permissions: I made sure to run chown -R 1000:1000 ./local-files on the host machine so the n8n user has full write access.

  3. Environment Variable: I explicitly set N8N_RESTRICT_FILE_ACCESS_TO=/files to whitelist the path.

Here is my working configuration:
services:
n8n:
image: docker.n8n.io/n8nio/n8n:2.1.4
restart: always
ports:

  • “5678:5678”
    environment:
  • N8N_HOST=————–
  • N8N_PORT=5678
  • N8N_PROTOCOL=https
  • N8N_RUNNERS_ENABLED=true
  • NODE_ENV=production
  • WEBHOOK_URL=————
  • GENERIC_TIMEZONE=Asia/Bangkok
  • TZ=Asia/Bangkok
  • NODES_EXCLUDE=
  • N8N_SECURE_COOKIE=false
    volumes:
  • n8n_data:/home/node/.n8n

This mapping solved the issue:

  • ./local-files:/files

cloudflared:
image: cloudflare/cloudflared:latest
restart: always
command: tunnel --no-autoupdate run
environment:

  • TUNNEL_TOKEN=YOUR_TUNNEL_TOKEN_HERE

volumes:
n8n_data:

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.