Temp folder configuration

Hi guys,

I need your help with some configuration related to the temp folder, I 'am trying to deploy my Docker project to an Openshift-OKD Nexus environment (on premise), I resolved to use two images, one for app and another image for NGINX as reverse proxy server, because of some restrictions in Openshift; in my local works fine, but when I pushed the images to Openshift I am getting this error: Error: EACCES: permission denied, mkdir '/opt/node_app/tmp'

I tried to change permissions from the dockerfile
RUN chmod -R a+rwX /opt/node_app

Also, I tried to mount the image to another location (new volume in Openshift) from the dockerfile
RUN mkdir /gaprh/node_app
WORKDIR /gaprh/node_app
RUN chmod -R a+rwX /gaprh/node_app

Also, I tried to change the config file from lib/setup/config.js
From: config.tmpFolder = toSystemPath(config.tmpFolder);
To: config.tmpFolder = '/gaprh/node_app';

And finally, I tried to add the key
"tmpFolder": "/gaprh/node_app/tmp"
in the ../app/config/config.json

But I still facing the error, my question is ¿Where should I change the value of the temp folder? to affect the remote Docker image effectively.

Images were built thru this command:
buildah bud --format=docker --file .wappler/targets/xxx_okd/app/Dockerfile.app --tag srv-osnexus01.my.domain:8006/xxx-backend-app-img:latest .

I'll appreciate any help.

Complete error log

2025-05-09T22:02:21.921Z server-connect:setup:config {
  port: '3000',
  debug: true,
  secret: 'XXXXXXXX',
  tmpFolder: '/opt/node_app/tmp',
  abortOnDisconnect: false,
  createApiRoutes: true,
  compression: true,
  redis: false,
  cron: true,
  static: { index: false },
  session: {
    name: 'talexxxxx.sid',
    resave: false,
    saveUninitialized: false,
    store: { '$type': 'memory', ttl: 86400 }
  },
  cors: {
    origin: true,
    methods: 'GET,POST,OPTIONS,PUT,HEAD,PATCH,DELETE,CONNECT',
    credentials: true,
    allowedHeaders: 'accept,authorization,content-type,origin,referer'
  },
  csrf: { enabled: false, exclude: 'GET,HEAD,OPTIONS' },
  rateLimit: {
    enabled: true,
    duration: 60,
    points: 100,
    private: { provider: 'security', duration: 3600, points: 10000 }
  },
  globals: {},
  rateLimiter: {},
  mail: {},
  auth: {},
  oauth: {},
  db: {},
  s3: {},
  jwt: {},
  stripe: {},
  env: {}
}
2025-05-09T22:02:22.307Z server-connect:setup:session init session store { '$type': 'memory', ttl: 86400 }
Error: EACCES: permission denied, mkdir '/opt/node_app/tmp'
    at Object.mkdirSync (node:fs:1364:26)
    at module.exports.makeDirSync (/opt/node_app/node_modules/fs-extra/lib/mkdirs/make-dir.js:23:13)
    at module.exports (/opt/node_app/lib/setup/upload.js:11:8)
    at Object.<anonymous> (/opt/node_app/lib/server.js:67:1)
    at Module._compile (node:internal/modules/cjs/loader:1730:14)
    at Object..js (node:internal/modules/cjs/loader:1895:10)
    at Module.load (node:internal/modules/cjs/loader:1465:32)
    at Function._load (node:internal/modules/cjs/loader:1282:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:235:24) {
  errno: -13,
  code: 'EACCES',
  syscall: 'mkdir',
  path: '/opt/node_app/tmp'
}

Bump!

Some idea?

From Chat Gippity:

ChatGPT said:

You're running into a common issue in OpenShift: default security constraints (SCC) enforce that containers run as a non-root user, which can cause permission problems when writing to certain directories, especially those created during image build with root permissions.

:mag: Root of the Problem

Your app is trying to create a tmp folder inside /opt/node_app, but OpenShift runs containers as a non-root user with a high UID, and this user likely does not have write permission to that directory, even after chmod.


:white_check_mark: Recommended Solutions

You need to ensure at runtime that the folder used for temporary files is writable by any UID, not just root.

Here are 3 solid options you can use:


:white_check_mark: Option 1: Use a Writable Directory (Best Practice)

Choose a directory that is writable by any user, such as /tmp, or use a location under a mounted volume with proper permissions.

Update your config to point to /tmp/myapp instead:

js

CopyEdit

config.tmpFolder = '/tmp/myapp';

Then ensure this directory exists on container startup.

In Dockerfile.app, add:

dockerfile

CopyEdit

RUN mkdir -p /tmp/myapp && chmod -R a+rwX /tmp/myapp

:white_check_mark: Option 2: Use fs.promises.mkdtemp() with /tmp

Node.js provides built-in support for creating secure temp dirs:

js

CopyEdit

const os = require('os');
const fs = require('fs/promises');

async function createTempDir() {
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'myapp-'));
  config.tmpFolder = tempDir;
}

This ensures you're using a system-writable path.


:white_check_mark: Option 3: Patch Permissions Using an OpenShift Init Container

If your app must write to /opt/node_app/tmp, mount an emptyDir volume there and use an init container to chown it.

In your OpenShift deployment YAML:

yaml

CopyEdit

volumes:
  - name: tmp-folder
    emptyDir: {}

containers:
  - name: app
    volumeMounts:
      - mountPath: /opt/node_app/tmp
        name: tmp-folder

initContainers:
  - name: fix-permissions
    image: busybox
    command: ["sh", "-c", "chmod -R 777 /opt/node_app/tmp"]
    volumeMounts:
      - mountPath: /opt/node_app/tmp
        name: tmp-folder

:exclamation: Extra Note on Dockerfile Permission Fixes

chmod -R a+rwX /opt/node_app runs at build time and affects files owned by root. But OpenShift runs your container with a random UID, so permissions must allow others (o+w) to write to the folder — or ownership needs to be set dynamically via a volume or init container.

Would you like me to help you adjust your Dockerfile or OpenShift deployment YAML to apply one of these solutions?

You said:

Yes please

ChatGPT said:

Great! Let's go with the most robust and OpenShift-friendly solution, which is:


:white_check_mark: Mount a Volume for /opt/node_app/tmp and Fix Permissions with an Init Container

This keeps your app logic clean and satisfies OpenShift's security constraints.


:wrench: 1. Update Your Deployment YAML

Here’s a full example of how to mount a writable volume and fix permissions using an init container:

yaml

CopyEdit

apiVersion: apps/v1
kind: Deployment
metadata:
  name: your-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: your-app
  template:
    metadata:
      labels:
        app: your-app
    spec:
      containers:
        - name: app
          image: srv-osnexus01.my.domain:8006/xxx-backend-app-img:latest
          ports:
            - containerPort: 3000
          volumeMounts:
            - name: tmp-folder
              mountPath: /opt/node_app/tmp
      initContainers:
        - name: init-permissions
          image: busybox
          command: ["sh", "-c", "chmod -R 777 /opt/node_app/tmp || true"]
          volumeMounts:
            - name: tmp-folder
              mountPath: /opt/node_app/tmp
      volumes:
        - name: tmp-folder
          emptyDir: {}

This does three things:

  • Mounts an emptyDir volume to /opt/node_app/tmp.
  • Runs a busybox container first to make the directory writable (777 for simplicity).
  • Starts your app after that.

:whale: 2. Update Dockerfile (Optional Cleanup)

Your Dockerfile.app likely has something like:

Dockerfile

CopyEdit

RUN mkdir -p /opt/node_app/tmp && chmod -R a+rwX /opt/node_app

You can keep this as a fallback, but it won't help in OpenShift without the proper volume and runtime ownership.


:file_folder: 3. Update App Config to Use That Path

Make sure your app is using this path:

js

CopyEdit

config.tmpFolder = '/opt/node_app/tmp';

Or in config.json:

json

CopyEdit

{
  "tmpFolder": "/opt/node_app/tmp"
}

Obviously can't take any credit if the above solution works? Worth a shot though @Luis_Saldana

I simply pasted your above question in as a prompt...

Bash script (obviously make sure to read through the script and understand it before running it):

deploy_with_tmp_fix.sh

#!/bin/bash

# Variables (customize as needed)
APP_NAME="your-app"
IMAGE="srv-osnexus01.my.domain:8006/xxx-backend-app-img:latest"
NAMESPACE="your-namespace"
PORT=3000

# Create Deployment YAML with tmp volume and initContainer
cat <<EOF > ${APP_NAME}_deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    metadata:
      labels:
        app: ${APP_NAME}
    spec:
      containers:
        - name: app
          image: ${IMAGE}
          ports:
            - containerPort: ${PORT}
          volumeMounts:
            - name: tmp-folder
              mountPath: /opt/node_app/tmp
      initContainers:
        - name: init-permissions
          image: busybox
          command: ["sh", "-c", "chmod -R 777 /opt/node_app/tmp || true"]
          volumeMounts:
            - name: tmp-folder
              mountPath: /opt/node_app/tmp
      volumes:
        - name: tmp-folder
          emptyDir: {}
EOF

# Apply the deployment
echo "Applying deployment..."
oc apply -f ${APP_NAME}_deployment.yaml

# Optional: Print deployment info
echo "Deployment '${APP_NAME}' applied to namespace '${NAMESPACE}'."
oc get pods -n ${NAMESPACE} -l app=${APP_NAME}

To run the script:

chmod +x deploy_with_tmp_fix.sh
./deploy_with_tmp_fix.sh
1 Like

Hi @Cheese

Thanks for the suggestions I'll try to change the OpenShift deployment YAML, because I did not try it before, and certenelly I made a mount volume, but I think could be help If I can change the temp folder path from the origin.

Thanks for taking your time in this!

1 Like