Description
Summary
When ODS is installed on a host running Docker rootless (via rootlesskit), containers that run as a non-root user (n8n, hermes, whisper, tts, token-spy, privacy-shield, ape, langfuse) fail to start with EACCES: permission denied errors. The data directories created by the installer are owned by the host user (e.g. UID 1000), but in rootless mode, container UIDs are remapped to a different range (starting at 100000), so non-root container users cannot write to them.
Environment
- OS: Ubuntu (Linux)
- Docker: rootless mode (
rootlesskit + dockerd-rootless.sh)
- subuid/subgid:
maxs:100000:65536
- ODS version:
ods-cli v2.5.3
- Install path:
~/ods (owned by maxs, UID 1000)
Use Case
Problem
In Docker rootless mode, UID mapping works as follows:
| Container UID |
Host UID |
| 0 (root) |
1000 (host user) |
| 1000 (node, ubuntu, appuser, odser) |
100000 |
| 10000 (hermes) |
109000 |
The installer creates data directories under ~/ods/data/ owned by the host user (UID 1000). Containers running as root (UID 0) work fine because root in the container maps to the host user. However, containers running as a non-root user fail because their container UID maps to a host UID (100000+) that has no write permission on the directory.
Proposed Solution
Symptoms
n8n:
No encryption key found - Auto-generating and saving to: /home/node/.n8n/config
Error: EACCES: permission denied, open '/home/node/.n8n/config'
at writeFileSync (node:fs:2437:20)
at InstanceSettings.save (...)
Hermes:
mkdir: cannot create directory '/opt/data': Permission denied
Fixing ownership of /opt/data to hermes (10000)
Warning: chown failed (rootless container?) — continuing anyway
Dropping root privileges
mkdir: cannot create directory '/opt/data': Permission denied
Affected containers
| Service |
Container user |
Container UID |
| n8n |
node |
1000 |
| hermes |
hermes |
10000 |
| whisper |
ubuntu |
1000 |
| tts |
appuser |
1000 |
| token-spy |
odser |
1000 |
| privacy-shield |
— |
1000 |
| ape |
ape |
100 |
| langfuse-web |
nextjs |
1001 |
Containers running as root (open-webui, litellm, qdrant, embeddings, perplexica, searxng, llama-server, dashboard, dashboard-api) are not affected.
Reproduction
- Install Docker rootless on a Linux host (e.g.
dockerd-rootless.sh + rootlesskit).
- Ensure
subuid/subgid is configured: username:100000:65536.
- Run the ODS installer as a non-root user.
- Start ODS:
ods start
- Observe that n8n and hermes fail to start with
EACCES / Permission denied errors.
Alternatives Considered
Workaround
Manually fix ownership of each affected data directory using a container with root privileges (which maps to the host user in rootless mode):
# n8n (container UID 1000)
docker run --rm --user 0:0 -v ~/ods/data/n8n:/data alpine sh -c "chown -R 1000:1000 /data"
# hermes (container UID 10000)
docker run --rm --user 0:0 -v ~/ods/data/hermes:/data alpine sh -c "chown -R 10000:10000 /data"
# whisper, tts, token-spy, privacy-shield (container UID 1000)
for svc in whisper tts token-spy privacy-shield; do
docker run --rm --user 0:0 -v ~/ods/data/$svc:/data alpine sh -c "chown -R 1000:1000 /data"
done
# ape (container UID 100)
docker run --rm --user 0:0 -v ~/ods/data/ape:/data alpine sh -c "chown -R 100:100 /data"
# langfuse (container UID 1001)
docker run --rm --user 0:0 -v ~/ods/data/langfuse:/data alpine sh -c "chown -R 1001:1001 /data"
Then restart: ods restart
Suggested fix
The installer (or ods start / ods restart) should detect rootless mode and fix data directory ownership automatically. Possible approaches:
Option A — Detect rootless and chown after directory creation
After creating data directories in 06-directories.sh, check if Docker is running in rootless mode and, for each service that uses a non-root container user, chown the corresponding data directory to the container's UID:
# Detect rootless mode
_is_rootless_docker() {
docker info --format '{{.SecurityOptions}}' 2>/dev/null | grep -q rootless
}
if _is_rootless_docker; then
# Fix ownership for non-root containers
_chown_data_dir "n8n" 1000
_chown_data_dir "hermes" 10000
_chown_data_dir "whisper" 1000
_chown_data_dir "tts" 1000
_chown_data_dir "token-spy" 1000
_chown_data_dir "privacy-shield" 1000
_chown_data_dir "ape" 100
_chown_data_dir "langfuse" 1001
fi
Where _chown_data_dir uses a helper container (since the host user may not have sudo):
_chown_data_dir() {
local svc="$1" uid="$2"
local dir="$INSTALL_DIR/data/$svc"
[[ -d "$dir" ]] || return 0
docker run --rm --user 0:0 -v "$dir:/data" alpine \
sh -c "chown -R ${uid}:${uid} /data" 2>/dev/null || true
}
Option B — Use docker run --user 0:0 for the chown in the entrypoint
Services like hermes already attempt a chown in their entrypoint (Fixing ownership of /opt/data to hermes (10000)), but it fails because the container has already dropped root privileges or because rootless remapping prevents it. Running the chown before dropping privileges, or using user: "0:0" in the compose file for the initial setup step, would fix this.
Option C — Document the rootless requirement
At minimum, detect rootless mode during ods doctor / ods preflight and warn the user that non-root containers need manual permission fixes, with the workaround commands printed.
Additional context
- Docker rootless is increasingly common for security best practices (running the Docker daemon as a non-root user).
- The
hermes entrypoint already tries to chown /opt/data but fails with Warning: chown failed (rootless container?) — the detection is there but the fix is incomplete.
- This affects both fresh installs and reinstalls.
Description
Summary
When ODS is installed on a host running Docker rootless (via
rootlesskit), containers that run as a non-root user (n8n, hermes, whisper, tts, token-spy, privacy-shield, ape, langfuse) fail to start withEACCES: permission deniederrors. The data directories created by the installer are owned by the host user (e.g. UID 1000), but in rootless mode, container UIDs are remapped to a different range (starting at 100000), so non-root container users cannot write to them.Environment
rootlesskit+dockerd-rootless.sh)maxs:100000:65536ods-cli v2.5.3~/ods(owned bymaxs, UID 1000)Use Case
Problem
In Docker rootless mode, UID mapping works as follows:
The installer creates data directories under
~/ods/data/owned by the host user (UID 1000). Containers running as root (UID 0) work fine because root in the container maps to the host user. However, containers running as a non-root user fail because their container UID maps to a host UID (100000+) that has no write permission on the directory.Proposed Solution
Symptoms
n8n:
Hermes:
Affected containers
Containers running as root (open-webui, litellm, qdrant, embeddings, perplexica, searxng, llama-server, dashboard, dashboard-api) are not affected.
Reproduction
dockerd-rootless.sh+rootlesskit).subuid/subgidis configured:username:100000:65536.ods startEACCES/Permission deniederrors.Alternatives Considered
Workaround
Manually fix ownership of each affected data directory using a container with root privileges (which maps to the host user in rootless mode):
Then restart:
ods restartSuggested fix
The installer (or
ods start/ods restart) should detect rootless mode and fix data directory ownership automatically. Possible approaches:Option A — Detect rootless and chown after directory creation
After creating data directories in
06-directories.sh, check if Docker is running in rootless mode and, for each service that uses a non-root container user, chown the corresponding data directory to the container's UID:Where
_chown_data_diruses a helper container (since the host user may not have sudo):Option B — Use
docker run --user 0:0for the chown in the entrypointServices like hermes already attempt a
chownin their entrypoint (Fixing ownership of /opt/data to hermes (10000)), but it fails because the container has already dropped root privileges or because rootless remapping prevents it. Running the chown before dropping privileges, or usinguser: "0:0"in the compose file for the initial setup step, would fix this.Option C — Document the rootless requirement
At minimum, detect rootless mode during
ods doctor/ods preflightand warn the user that non-root containers need manual permission fixes, with the workaround commands printed.Additional context
hermesentrypoint already tries to chown/opt/databut fails withWarning: chown failed (rootless container?)— the detection is there but the fix is incomplete.