Independent tech intelligence, checked against primary sources.

TechPulseMind Useful technology.
No manufactured hype.

Fix the “Error: EACCES: permission denied, mkdir ‘/home/node/.n8n’” when running n8n in Docker inside an LXC on Proxmox VE

Learn how to fix the n8n EACCES permission denied error when running Docker inside an LXC on Proxmox with a simple chown fix.

Fix the “Error: EACCES: permission denied, mkdir ‘/home/node/.n8n’” when running n8n in Docker inside an LXC on Proxmox VE

Before you start: versions, package names and storage identifiers change over time. Check the commands against the official documentation for your setup before running them, especially anything that creates, deletes or overwrites data.

n8n exits immediately after docker compose up and the log ends with:

Error: EACCES: permission denied, mkdir '/home/node/.n8n'

Nothing is corrupted and Docker is working. The container cannot write to the directory you mounted, because of a user ID mismatch between the image and the host.

Why it happens

The n8n image does not run as root. It runs as a user called node, with UID and GID 1000:

$ docker exec n8n id
uid=1000(node) gid=1000(node) groups=1000(node)

When you bind-mount a host directory like ./n8n_data, Docker passes it through with its host ownership intact. If you created that directory as root — which is what happens when you run mkdir in a root shell, as most people do inside an LXC — it arrives owned by 0:0. UID 1000 then has no write permission, mkdir fails, and n8n exits before it can start.

The directory matters because it holds n8n’s SQLite database and, more importantly, the encryption key for your stored credentials.

Why an LXC makes this more likely

In an unprivileged Proxmox container, root inside the container is already mapped to a high-numbered unprivileged UID on the Proxmox host. That mapping is invisible from inside, so ownership can look correct at one layer and still be wrong at another. Judge it from inside the container — that is the view Docker acts on.

Fix 1: correct the ownership (keeping the bind mount)

Stop the stack, fix ownership, start it again:

docker compose down
sudo chown -R 1000:1000 ./n8n_data
ls -ldn ./n8n_data
docker compose up -d

Use ls -ldn rather than ls -ld: the -n flag prints numeric IDs. You want to see 1000 1000:

drwxr-xr-x 4 1000 1000 4096 Sep 20 05:40 ./n8n_data

With plain ls -ld you may see a host username that happens to own UID 1000, which tells you nothing useful about what the container sees.

Fix 2: use a named volume instead (recommended)

The mismatch only exists because you chose a host path. A named volume has no pre-existing host ownership, so Docker initialises it with the image’s own user and the problem cannot occur:

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - GENERIC_TIMEZONE=Europe/Rome
      - TZ=Europe/Rome
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

This is what the official n8n Docker instructions use (docker volume create n8n_data, then -v n8n_data:/home/node/.n8n).

The trade-off is real, so choose deliberately rather than by default:

Bind mount (./n8n_data) Named volume
Permission mismatch Likely; needs chown Cannot happen
Finding the files Right there in your project directory Under /var/lib/docker/volumes/
Backing up Copy the directory Needs a helper container or docker run --volumes-from

If you already have data in a bind mount, do not just switch the Compose file to a named volume — you will get an empty n8n and your credentials will be unreadable. Copy the contents across first.

Do not “fix” it by running as root

Adding user: root to the service makes the error disappear, which is why it gets suggested. It also discards the image’s privilege separation, and it rewrites the directory’s ownership to 0:0, so if you later revert to the default user you land back on the same error with a directory that is now harder to reason about. Set N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true and fix the ownership instead.

Verify

docker compose ps
docker compose logs -f n8n

A healthy start ends with a line reporting n8n listening on port 5678. Then load http://<container-ip>:5678. On a fresh instance it asks you to create an owner account — that is expected, and there is no supported way to disable it since n8n 1.0.

If the container now starts but the port does not answer, that is a different problem: see fixing “address already in use” on port 5678.

Sources

Related reading

Some links on this page may be affiliate links. If you buy through them we may earn a commission at no extra cost to you. See our affiliate disclosure.