Node Docker containers lack permission to access their mounted volumes…?

I’m doing my absolute best to run a dockerized Node server app on OpenSUSE Leap 16.0, but I’m having mighty mysterious problems with permissions to access mounted volumes…

How to reproduce

Using OpenSUSE’s official instructions, install Docker:

sudo zypper install docker docker-compose
sudo systemctl enable docker
sudo usermod -G docker -a $USER
sudo systemctl restart docker

Let’s make a test directory owned by the docker group while we’re at it:

newgrp docker
mkdir /home/$USER/test

Then run any Node app with a mounted volume – here, we mount the user’s home directory to /test and run the Node REPL for testing:

docker run -it --name node -v /home/$USER/test:/test bitnami/node

In the Node REPL, execute the following:

const fs = require('fs');
const os = require('os');
os.userInfo();
fs.readdirSync('/test');

The output I get is as following:

> os.userInfo()
[Object: null prototype] {
  uid: 0,
  gid: 0,
  username: 'root',
  homedir: '/root',
  shell: '/bin/bash'
}
> fs.readdirSync('/test');
Uncaught Error: EACCES: permission denied, scandir '/test'
    at Object.readdirSync (node:fs:1569:26) {
  errno: -13,
  code: 'EACCES',
  syscall: 'scandir',
  path: '/test'
}

What this tells me is that despite Docker running as root (UID 0; GID 0), and despite the user’s home directory being successfully mounted to /test in the container, the Docker container for some reason does not have permission to access (even read!) the directory.

What’s going on here…? 😵‍💫


The finer details…

I’ve confirmed that the directory has the correct permissions set…
user@localhost:~> ls -l
[…]
drwxr-xr-x. 1 user  docker    0 Dec 17 17:06 test
Here’s the output of sudo systemctl status docker, which may be relevant… There are some errors in there!
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled)
     Active: active (running) since Wed 2025-12-17 16:59:12 CET; 1min 21s ago
 Invocation: d5140dc502cc4e429c683ec722e7d9b4
TriggeredBy: ● docker.socket
       Docs: http://docs.docker.com
   Main PID: 1134 (dockerd)
      Tasks: 23
        CPU: 783ms
     CGroup: /system.slice/docker.service
             ├─1134 /usr/bin/dockerd --add-runtime oci=/usr/sbin/runc
             └─1206 containerd --config /var/run/docker/containerd/containerd.toml

Dec 17 16:59:10 localhost.localdomain systemd[1]: Starting Docker Application Container Engine...
Dec 17 16:59:12 localhost.localdomain dockerd[1134]: time="2025-12-17T16:59:12.565114345+01:00" level=warning msg="Error (Unable to complete atomic operation, key modified) deleting object [endpoint_count 402d1a6df161950b04de2c13910196723084b16bcca3b6a4446472926a32f6f1], retrying...."
Dec 17 16:59:12 localhost.localdomain systemd[1]: Started Docker Application Container Engine.
Dec 17 16:59:55 localhost.localdomain dockerd[1206]: time="2025-12-17T16:59:55.765036230+01:00" level=warning msg="cleaning up after shim disconnected" id=9e7f6a62c936ef01b6d7b9b18f66dd0903136545cf18b4e1985e1b23b845ceb9 namespace=moby
My actual use case, in case someone has the same issue down the line and needs to google it…

Trying to run Audiobookshelf, a Node server app, on OpenSUSE Leap 16.0, my compose.yaml looks like this:

services:
  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    ports:
      - 13378:80
    volumes:
      - /run/media/red/Audio:/audio:ro
      - /run/media/red/.config/audiobookshelf/config:/config
      - /run/media/red/.config/audiobookshelf/metadata:/metadata
    environment:
      - TZ=Europe/Stockholm

And docker compose up gives me the following error output:

Attaching to audiobookshelf-1
audiobookshelf-1  | Running in production mode.
audiobookshelf-1  | Options: CONFIG_PATH=/config, METADATA_PATH=/metadata, PORT=80, HOST=undefined, SOURCE=docker, ROUTER_BASE_PATH=/audiobookshelf
audiobookshelf-1  | [2025-12-17 16:53:22.337] INFO: === Starting Server ===
audiobookshelf-1  | [2025-12-17 16:53:22.340] INFO: [Server] Init v2.31.0
audiobookshelf-1  | [2025-12-17 16:53:22.340] INFO: [Server] Node.js Version: v20.19.6
audiobookshelf-1  | [2025-12-17 16:53:22.341] INFO: [Server] Platform: linux
audiobookshelf-1  | [2025-12-17 16:53:22.341] INFO: [Server] Arch: x64
audiobookshelf-1  | [2025-12-17 16:53:22.345] ERROR: [PlaybackSessionManager] cleanOrphanStreams failed [Error: EACCES: permission denied, scandir '/metadata/streams'] {
audiobookshelf-1  |   errno: -13,
audiobookshelf-1  |   code: 'EACCES',
audiobookshelf-1  |   syscall: 'scandir',
audiobookshelf-1  |   path: '/metadata/streams'
audiobookshelf-1  | }
audiobookshelf-1  | [2025-12-17 16:53:22.351] INFO: [Database] Initializing db at "/config/absdatabase.sqlite"
audiobookshelf-1  | [2025-12-17 16:53:22.379] ERROR: [Database] Failed to connect to db ConnectionError [SequelizeConnectionError]: SQLITE_CANTOPEN: unable to open database file
audiobookshelf-1  |     at Database.<anonymous> (/app/node_modules/sequelize/lib/dialects/sqlite/connection-manager.js:52:25) {
audiobookshelf-1  |   parent: [Error: SQLITE_CANTOPEN: unable to open database file] {
audiobookshelf-1  |     errno: 14,
audiobookshelf-1  |     code: 'SQLITE_CANTOPEN'
audiobookshelf-1  |   },
audiobookshelf-1  |   original: [Error: SQLITE_CANTOPEN: unable to open database file] {
audiobookshelf-1  |     errno: 14,
audiobookshelf-1  |     code: 'SQLITE_CANTOPEN'
audiobookshelf-1  |   }
audiobookshelf-1  | }
audiobookshelf-1  | [2025-12-17 16:53:22.382] FATAL: [Server] Unhandled rejection: Error: Database connection failed
audiobookshelf-1  |     at Database.init (/app/server/Database.js:188:13)
audiobookshelf-1  |     at async Server.init (/app/server/Server.js:159:5)
audiobookshelf-1  |     at async Server.start (/app/server/Server.js:223:5)
audiobookshelf-1  | promise: Promise {
audiobookshelf-1  |   <rejected> Error: Database connection failed
audiobookshelf-1  |       at Database.init (/app/server/Database.js:188:13)
audiobookshelf-1  |       at async Server.init (/app/server/Server.js:159:5)
audiobookshelf-1  |       at async Server.start (/app/server/Server.js:223:5)
audiobookshelf-1  | }
audiobookshelf-1  | [LogManager] Appended crash log [Error: EACCES: permission denied, open '/metadata/logs/crash_logs.txt'] {
audiobookshelf-1  |   errno: -13,
audiobookshelf-1  |   code: 'EACCES',
audiobookshelf-1  |   syscall: 'open',
audiobookshelf-1  |   path: '/metadata/logs/crash_logs.txt'
audiobookshelf-1  | }
audiobookshelf-1 exited with code 1