You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Introduced redis session handler does not work with non-root images #763
In commit 83ea69d, a redis session handler was intrododuced. But the file /usr/local/etc/php/conf.d/redis-session.ini can not be written when using a non-root image, because the folder is owned by root and the default www-data user does not have write permission.
/var/www/html # ls -lha /usr/local/etc/php/conf.d
total 72
drwxr-xr-x 1 root root 4.0K Feb 26 08:50 .
drwxr-xr-x 1 root root 4.0K Feb 26 07:34 ..
-rw-r--r-- 1 root root 35 Feb 26 08:50 docker-php-ext-apcu.ini
-rw-r--r-- 1 root root 18 Feb 26 08:47 docker-php-ext-exif.ini
-rw-r--r-- 1 root root 16 Feb 26 08:47 docker-php-ext-gd.ini
-rw-r--r-- 1 root root 21 Feb 26 08:50 docker-php-ext-imagick.ini
-rw-r--r-- 1 root root 18 Feb 26 08:48 docker-php-ext-intl.ini
-rw-r--r-- 1 root root 18 Feb 26 08:48 docker-php-ext-ldap.ini
-rw-r--r-- 1 root root 23 Feb 26 08:50 docker-php-ext-memcached.ini
-rw-r--r-- 1 root root 82 Feb 26 08:48 docker-php-ext-opcache.ini
-rw-r--r-- 1 root root 19 Feb 26 08:48 docker-php-ext-pcntl.ini
-rw-r--r-- 1 root root 23 Feb 26 08:49 docker-php-ext-pdo_mysql.ini
-rw-r--r-- 1 root root 23 Feb 26 08:49 docker-php-ext-pdo_pgsql.ini
-rw-r--r-- 1 root root 19 Feb 26 08:50 docker-php-ext-redis.ini
-rw-r--r-- 1 root root 20 Feb 26 07:34 docker-php-ext-sodium.ini
-rw-r--r-- 1 root root 17 Feb 26 08:49 docker-php-ext-zip.ini
-rw-r--r-- 1 root root 18 Feb 26 08:50 memory-limit.ini
-rw-r--r-- 1 root root 189 Feb 26 08:50 opcache-recommended.ini
For running my nextcloud image, I use the default non-privileged user www-data.
/var/www/html $ id
uid=82(www-data) gid=82(www-data) groups=82(www-data)
changed the title [-]Introduced redis session handler breaks entrypoint of non-root images[/-][+]Introduced redis session handler does not work with non-root images[/+]on May 30, 2019
Thanks for reporting this. I can reproduce the issue, but I'm not very happy with the proposed permission change in #764.
However, this should not break your NextCloud, you just have no Redis session handler. As a workaround, you can mount a redis-session.ini manually.
Change ownership of /usr/local/etc/php/conf.d/ to user www-data. The entrypoint creates redis-session.ini. Results in security concerns.
Create placeholder file /usr/local/etc/php/conf.d/redis-session.ini in the Dockerfile with no content. Change ownership of only /usr/local/etc/php/conf.d/redis-session.ini to user www-data. Content can be written in the entrypoint. More secure than 1. but if redis is not used, there is an empty file.
Create file /usr/local/etc/php/conf.d/session.ini in the Dockerfile with defaults from default config /usr/local/etc/php/php.ini-production. Change ownership of only /usr/local/etc/php/conf.d/session.ini to user www-data. Content can be replaced with sed in the entrypoint. Security equal to 2. but duplicate config for session.
Only write /usr/local/etc/php/conf.d/redis-session.ini when running as root, otherwise log a warning that the file must be mounted manually instead of throwing the error like described above. No security concerns.
Currently I think version 3 is the best trade-off. @J0WI what do you think?
@J0WI I prefer 3 over 2 because if redis host is not set, there is a file called redis-session.ini which might irritate users.
Best practices of writing Docker images says
All images in this project should run as non-root by default. Having this in mind, 4 is not an option. I will open a new PR that sets non-root users as default for all used images and examples. Not choosing 4 is a precondition for that.
1 and 2 are not really an option because it wouldn't work for users other than root and www-data. Instead we would need to chmod 777 them.
It there any difference between 1, 2 and 3 in terms of security? In each case php can modify it's own config.
All images in this project should run as non-root by default. Having this in mind, 4 is not an option. I will open a new PR that sets non-root users as default for all used images and examples. Not choosing 4 is a precondition for that.
The web server already runs as a non-root user (www-data) by default.
And i don't see how adding USER www-data to the Dockerfile will improve the security. If you don't trust the container to run apache as www-data you also can't trust the default user to be www-data.
The PID 1 process always runs as root by using the defaults.
And i don't see how adding USER www-data to the Dockerfile will improve the security. If you don't trust the container to run apache as www-data you also can't trust the default user to be www-data.
Have a look at the following blog post. There is a good explanation, why running images as root is not a good practice:
If the USER directive is set to www-data the attack vector is minimized when running with defaults. And if anyone wants to run the image as root this is still possible by manually changing the user.
1 and 2 are not really an option because it wouldn't work for users other than root and www-data. Instead we would need to chmod 777 them.
It makes no sense to use another user than root or www-data to run fpm or apache, other users do not have sufficient permissions.
Yes the entrypoint scipt and apache/fpm master process run as root by default. I meant that the processes that handle the requests and run the php code are run by a different user.
If the USER directive is set to www-data the attack vector is minimized when running with defaults. And if anyone wants to run the image as root this is still possible by manually changing the user.
Yes it will reduce the attack surface in case there is a bug in apache/fpm that allows code execution in the master process. But it won't help in the case of a malicious docker image. To protect against a malicious docker image you would need to override to default user for example in the docker-compose file.
Something like this should be done upstream in the php base image, then all php based images get the benefit.
It makes no sense to use another user than root or www-data to run fpm or apache, other users do not have sufficient permissions.
This is valid use case and it is supported by the upstream image. It should work, have you tried it? If there is a permission problem it is a bug.
I was not aware of that in docker-library/php#787 the permissions of folder /var/www/html were set to 777. So yes, every user can be used to run the php-fpm image.
I guess the upstream images will not set the user directive in the mid-term because that will break too many existing child images. So in my opinion, this should be treated proactive from the application side.
After the discussions above, how should we follow?
In the meantime, I am just happy if the entrypoint does not throw an exception anymore. And all following changes of this project should work user independent so that updating the image is always possible without manual testing in a sandbox environment.
I work around this by mounting redis-session.ini manually as a volume, i.e. touch ./nextcloud/redis/redis-session.ini and then add this flag to podman/docker on the nextcloud container:
Having the exact same problem. Thank you for the fix. Nextcloud should up their game on how to correctly use docker and providing images. The whole upgrade process with nextcloud is also horrendous. If there would be a viable alternative I would gladly take it.
OT: You may want to check out https://github.com/LorbusChris/nextcloud-quadlet for an alternative way of running a rootless setup. The stack is a bit different, using Valkey instead of Redis, and Envoy as proxy. I've been running this setup for ~4 months with automatic upgrades and without any issues.
Unlikely, due the reason mentioned in #763 (comment)
Making the server config world writeable would make the image less secure for everyone. Mounting a custom config is the way to go.
For people running a docker Nextcloud instance with a read-only root filesystem and a non-root user, I have found a workaround to this issue.
PHP allows you to change the directories in which it is going to look for ini configurations using the environment PHP_INI_SCAN_DIR variable.
So you can launch the container with PHP_INI_SCAN_DIR="/tmp/php_conf_d:" assuming you have mounted a tmpfs in /tmp (note that the trailing : tells PHP to append the specified directory to the existing set of PHP ini scan directories).
Then you can mount a custom script in /docker-entrypoint-hooks.d/before-starting/redis_config_generator.sh which could look something like this:
(Note that the redis environment variables are prefixed with HOOK_ to avoid Nextcloud attempting to generate its own configuration on top of yours using the REDIS_ environment variables)
This should enable you to have a custom Redis configuration readable by your custom --user and written to a writable location on the filesystem.
Hi, I have the same issue in a Kubernetes environment, using Nextcloud helm chart, in OpenShift with restrictive non root policy.
This is a workaround that works!! I couldn't mount an emptyDir directly to the /usr/local/etc/php/conf.d, because that would have overriden the existing file. So I created an emptyDir, and initContainer to create en empty file, what a workaround!!!
Thank you, that helped me fix my issue with the Helm chart as well. Just a note for anyone else that finds this issue trying to run as non-root along with the cronjob container, you have to set the securityContext on the init-redis-session-ini initContainer. podSecurityContext won't work because the cronjob container must run as root to work properly.
There is an open pull request (nextcloud/helm#703) to use a k8s CronJob resource instead which would solve this problem, in which case podSecurityContext should work if it's accepted.
Have the entrypoint script compute the complex Redis session save path (as it basically does currently) but instead of writing it out to an INI file, we export it as an environment variable.
Have our php.ini (or an included ini file - in our case probably nextcloud.ini) reference the environment variable(s) directly. **We already do this for PHP_MEMORY_LIMIT though it doesn't have any entrypoint logic since it's much simpler).
Specifically:
we drop redis-session.ini file entirely (no write required in the entrypoint)
instead of having the entrypoint's Redis config logic create the file, we have it build the appropriate session.save_path value just before launching apache/fpm and export it into an environment variable (e.g. PHP_REDIS_SESSION_SAVE_PATH). Also include others like PHP_REDIS_SESSION_HANDLER = "redis" and the locking settings
In nextcloud.ini we reference the environment variables just like we do for PHP_MEMORY_LIMIT/etc.
Add this logic to our entrypoint before PHP or the webserver runs:
if [ -n "${REDIS_HOST+x}" ]; then
# shell function to load REDIS_HOST_PASSWORD from file, if using Docker secrets
file_env REDIS_HOST_PASSWORD
if [ "$(echo "$REDIS_HOST" | cut -c1-1)" = "/" ]; then
# Unix socket path
if [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
if [ -n "${REDIS_HOST_USER+x}" ]; then
FINAL_SAVE_PATH="unix://${REDIS_HOST}?auth[]=${REDIS_HOST_USER}&auth[]=${REDIS_HOST_PASSWORD}"
else
FINAL_SAVE_PATH="unix://${REDIS_HOST}?auth=${REDIS_HOST_PASSWORD}"
fi
else
FINAL_SAVE_PATH="unix://${REDIS_HOST}"
fi
elif [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
# TCP with password
if [ -n "${REDIS_HOST_USER+x}" ]; then
FINAL_SAVE_PATH="tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth[]=${REDIS_HOST_USER}&auth[]=${REDIS_HOST_PASSWORD}"
else
FINAL_SAVE_PATH="tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth=${REDIS_HOST_PASSWORD}"
fi
else
# TCP without password
FINAL_SAVE_PATH="tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}"
fi
# Export as environment variable for PHP-FPM/apache
export PHP_REDIS_SESSION_SAVE_PATH="$FINAL_SAVE_PATH"
fi
# Optionally also set other session handler options
export PHP_REDIS_SESSION_HANDLER="redis"
export PHP_REDIS_SESSION_LOCKING_ENABLED=1
export PHP_REDIS_SESSION_LOCK_RETRIES=-1
export PHP_REDIS_SESSION_LOCK_WAIT_TIME=10000
# exec the CMD as usual at the end of your entrypoint script:
exec "$@"
Make our nextcloud.ini reference the above environment variables (i.e. add these to our Dockerfile-*.template files:
; Use Redis for PHP session handler if configured
session.save_handler = "${PHP_REDIS_SESSION_HANDLER}"
session.save_path = "${PHP_REDIS_SESSION_SAVE_PATH}"
redis.session.locking_enabled = ${PHP_REDIS_SESSION_LOCKING_ENABLED}
redis.session.lock_retries = ${PHP_REDIS_SESSION_LOCK_RETRIES}
redis.session.lock_wait_time = ${PHP_REDIS_SESSION_LOCK_WAIT_TIME}
In PHP 8.3+. we can even add clear fallbacks per PHP docs (though may be unnecessary since defaults are likely fine -- or we could handle it in our entrypoint logic too). Something like this I believe:
Activity
Fixes nextcloud#763, non-root usage with enabled redis session handler
Fixes nextcloud#763, non-root usage with enabled redis session handler
smueller18 commentedon May 30, 2019
Here is a command to reproduce this behavior:
[-]Introduced redis session handler breaks entrypoint of non-root images[/-][+]Introduced redis session handler does not work with non-root images[/+]Unb0rn commentedon Jun 2, 2019
Any workarounds? I have this problem too
J0WI commentedon Jun 4, 2019
Thanks for reporting this. I can reproduce the issue, but I'm not very happy with the proposed permission change in #764.
However, this should not break your NextCloud, you just have no Redis session handler. As a workaround, you can mount a
redis-session.inimanually.smueller18 commentedon Jun 4, 2019
I know changing the permissions is kind of a security issue. But running the image as root is even more.
What definitely does not work:
.user.inifile. According to PHP memory limit to 128 ? #447 (comment), this does not work for CLI mode.Here are some options that I figured out:
/usr/local/etc/php/conf.d/to userwww-data. The entrypoint createsredis-session.ini. Results in security concerns./usr/local/etc/php/conf.d/redis-session.iniin the Dockerfile with no content. Change ownership of only/usr/local/etc/php/conf.d/redis-session.inito userwww-data. Content can be written in the entrypoint. More secure than 1. but if redis is not used, there is an empty file./usr/local/etc/php/conf.d/session.iniin the Dockerfile with defaults from default config/usr/local/etc/php/php.ini-production. Change ownership of only/usr/local/etc/php/conf.d/session.inito userwww-data. Content can be replaced withsedin the entrypoint. Security equal to 2. but duplicate config for session./usr/local/etc/php/conf.d/redis-session.iniwhen running as root, otherwise log a warning that the file must be mounted manually instead of throwing the error like described above. No security concerns.Currently I think version 3 is the best trade-off. @J0WI what do you think?
J0WI commentedon Jun 5, 2019
Why would you prefer 3 over 2?
4 would also be an option for me, this is basically what happens now.
@tilosp what is your opinion?
smueller18 commentedon Jun 7, 2019
@J0WI I prefer 3 over 2 because if redis host is not set, there is a file called
redis-session.iniwhich might irritate users.Best practices of writing Docker images says
All images in this project should run as non-root by default. Having this in mind, 4 is not an option. I will open a new PR that sets non-root users as default for all used images and examples. Not choosing 4 is a precondition for that.
tilosp commentedon Jun 12, 2019
1 and 2 are not really an option because it wouldn't work for users other than root and www-data. Instead we would need to chmod 777 them.
It there any difference between 1, 2 and 3 in terms of security? In each case php can modify it's own config.
The web server already runs as a non-root user (www-data) by default.
And i don't see how adding
USER www-datato the Dockerfile will improve the security. If you don't trust the container to run apache as www-data you also can't trust the default user to be www-data.J0WI commentedon Jun 12, 2019
Not it terms of security, but I'd avoid changing upstream files.
smueller18 commentedon Jun 12, 2019
I can't verify that, have a look at the commands:
The PID 1 process always runs as root by using the defaults.
Have a look at the following blog post. There is a good explanation, why running images as root is not a good practice:
If the
USERdirective is set towww-datathe attack vector is minimized when running with defaults. And if anyone wants to run the image as root this is still possible by manually changing the user.It makes no sense to use another user than
rootorwww-datato run fpm or apache, other users do not have sufficient permissions.How should we go an with this issue?
tilosp commentedon Jun 12, 2019
Yes the entrypoint scipt and apache/fpm master process run as root by default. I meant that the processes that handle the requests and run the php code are run by a different user.
Yes it will reduce the attack surface in case there is a bug in apache/fpm that allows code execution in the master process. But it won't help in the case of a malicious docker image. To protect against a malicious docker image you would need to override to default user for example in the docker-compose file.
Something like this should be done upstream in the php base image, then all php based images get the benefit.
This is valid use case and it is supported by the upstream image. It should work, have you tried it? If there is a permission problem it is a bug.
smueller18 commentedon Jun 22, 2019
I was not aware of that in docker-library/php#787 the permissions of folder
/var/www/htmlwere set to777. So yes, every user can be used to run the php-fpm image.I guess the upstream images will not set the user directive in the mid-term because that will break too many existing child images. So in my opinion, this should be treated proactive from the application side.
After the discussions above, how should we follow?
In the meantime, I am just happy if the entrypoint does not throw an exception anymore. And all following changes of this project should work user independent so that updating the image is always possible without manual testing in a sandbox environment.
23 remaining items
phate7 commentedon Feb 13, 2024
Having the exact same problem. Thank you for the fix. Nextcloud should up their game on how to correctly use docker and providing images. The whole upgrade process with nextcloud is also horrendous. If there would be a viable alternative I would gladly take it.
hypery2k commentedon Apr 19, 2024
LorbusChris commentedon May 5, 2024
OT: You may want to check out https://github.com/LorbusChris/nextcloud-quadlet for an alternative way of running a rootless setup. The stack is a bit different, using Valkey instead of Redis, and Envoy as proxy. I've been running this setup for ~4 months with automatic upgrades and without any issues.
J0WI commentedon May 13, 2024
Unlikely, due the reason mentioned in #763 (comment)
Making the server config world writeable would make the image less secure for everyone. Mounting a custom config is the way to go.
guillaumedsde commentedon Mar 22, 2025
Hello 👋
For people running a docker Nextcloud instance with a read-only root filesystem and a non-root user, I have found a workaround to this issue.
PHP allows you to change the directories in which it is going to look for ini configurations using the environment
PHP_INI_SCAN_DIRvariable.So you can launch the container with
PHP_INI_SCAN_DIR="/tmp/php_conf_d:"assuming you have mounted a tmpfs in/tmp(note that the trailing:tells PHP to append the specified directory to the existing set of PHP ini scan directories).Then you can mount a custom script in
/docker-entrypoint-hooks.d/before-starting/redis_config_generator.shwhich could look something like this:(Note that the redis environment variables are prefixed with
HOOK_to avoid Nextcloud attempting to generate its own configuration on top of yours using theREDIS_environment variables)This should enable you to have a custom Redis configuration readable by your custom
--userand written to a writable location on the filesystem.antoinetran commentedon Mar 25, 2025
Hi, I have the same issue in a Kubernetes environment, using Nextcloud helm chart, in OpenShift with restrictive non root policy.
This is a workaround that works!! I couldn't mount an emptyDir directly to the
/usr/local/etc/php/conf.d, because that would have overriden the existing file. So I created an emptyDir, and initContainer to create en empty file, what a workaround!!!Aetylus commentedon Apr 10, 2025
Thank you, that helped me fix my issue with the Helm chart as well. Just a note for anyone else that finds this issue trying to run as non-root along with the cronjob container, you have to set the
securityContexton theinit-redis-session-iniinitContainer.podSecurityContextwon't work because the cronjob container must run as root to work properly.There is an open pull request (nextcloud/helm#703) to use a k8s CronJob resource instead which would solve this problem, in which case
podSecurityContextshould work if it's accepted.antoinetran commentedon Jun 17, 2025
For information, this is the PullRequest I created that fixed this issue: nextcloud/helm#717 . One day it will be merged!
agravgaard commentedon Jan 15, 2026
If I'm understanding nextcloud/helm#752 correctly, then this could currently be worked around by adding to the values:
This seems to work for me, but my testing has been limited so far.
(But my values file is already about 300 lines long and hard to maintain, so I'd prefer to get the above-mentioned fix merged)
Edit: a writable '/tmp' was also needed.
joshtrichards commentedon Jan 29, 2026
Here's a thought:
nextcloud.ini) reference the environment variable(s) directly. **We already do this forPHP_MEMORY_LIMITthough it doesn't have any entrypoint logic since it's much simpler).Specifically:
redis-session.inifile entirely (no write required in the entrypoint)session.save_pathvalue just before launching apache/fpm and export it into an environment variable (e.g.PHP_REDIS_SESSION_SAVE_PATH). Also include others likePHP_REDIS_SESSION_HANDLER = "redis"and the locking settingsnextcloud.iniwe reference the environment variables just like we do forPHP_MEMORY_LIMIT/etc.This should work.
Refs:
REDIS*config handling:docker/docker-entrypoint.sh
Lines 115 to 148 in 0af85f2
PHP_MEMORY_LIMIT):docker/Dockerfile-debian.template
Lines 99 to 123 in 0af85f2
php.inienvironment variable support: https://www.php.net/manual/en/configuration.file.php#configuration.fileProposed (untested):
nextcloud.inireference the above environment variables (i.e. add these to ourDockerfile-*.templatefiles:In PHP 8.3+. we can even add clear fallbacks per PHP docs (though may be unnecessary since defaults are likely fine -- or we could handle it in our entrypoint logic too). Something like this I believe:
feat(redis): config save_handler w/o modifying ini file in entrypoint
joshtrichards commentedon Mar 23, 2026
Early prototype of approach that eliminates entrypoint needing to modify redis-session.ini file is in draft PR #2550. Needs testing.