# PHP sessions filling up disk

**URL:** <https://community.passbolt.com/t/php-sessions-filling-up-disk/10336>\
**Category:** Installation Issues\
**Created:** [July 6, 2024, 6:24pm UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336 "2024-07-06T18:24:54Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![tanji](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.passbolt.com/tanji/32/4232_2.png) [@tanji](https://community.passbolt.com/u/tanji)\
**Post date:** [July 6, 2024, 6:24pm UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336/1 "2024-07-06T18:24:54Z")

</div>

Hello,

we are running a Docker Passbolt CE installation for many years (always updated to latest version), however every few months I need to enter the volume and delete php session files manually in /var/lib/php/sessions, because these fill up the filesystem completely (no more inodes).

The specificity of this instance is that it’s running behind HAProxy. Initially I thought that using / as the healthcheck path was causing PHP to create a session for every hit, so I changed the haproxy healthcheck to /healthcheck/status. That works fine, but sessions are still created and fill up the disk.

I haven’t found any mentions of similar issues but I suppose we shouldn’t be the only company to run Passbolt behind HAProxy… Thanks in advance for any feedback that the community can provide.

---

<div class="post-metadata">

**Author:** ![Prasad](https://avatars.discourse-cdn.com/v4/letter/p/9de0a6/32.png) [@Prasad](https://community.passbolt.com/u/Prasad)\
**Post date:** [April 30, 2026, 2:00am UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336/2 "2026-04-30T02:00:07Z")

</div>

HI @tanji,

Iam also facing similar problem like you explained above. In the passbolt app docker container after few hours i see a message as “Cannot make/remove an entry for the specified session” and when i do a simple restart of container the app works again for few more hours.

Do you have any thoughts here ? did you find any resolution for your above query..

---

<div class="post-metadata">

**Author:** ![gyaresu](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.passbolt.com/gyaresu/32/5320_2.png) [@gyaresu](https://community.passbolt.com/u/gyaresu)\
**Post date:** [April 30, 2026, 4:32am UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336/3 "2026-04-30T04:32:31Z")

</div>

G’day Prasad.

The error `Cannot make/remove an entry for the specified session` comes from PHP’s session save handler when it cannot create a session file. The most common cause is the filesystem running out of inodes or free space, which fits tanji’s original symptom of `/var/lib/php/sessions` growing without bound, but it can also be a permissions or locking issue depending on your setup. Can you give us a bit of an idea what’s happening on your container?

The Debian PHP package ships a cron job at `/etc/cron.d/php` that runs `/usr/lib/php/sessionclean` every 30 minutes and deletes session files older than `session.gc_maxlifetime` (24 minutes by default). If that cron is healthy and `gc_maxlifetime` hasn’t been raised, the directory should hold steady rather than grow over weeks or months.

**Could you run this inside the passbolt container and share the output?**

```auto
docker exec <your-passbolt-container> sh -c '
  echo -n "cron running: "; pgrep -a cron || echo "no cron process"
  echo -n "/etc/cron.d/php: "; [-f /etc/cron.d/php] && echo "present" || echo "missing"
  echo -n "/run/systemd/system: "; [-d /run/systemd/system] && echo "present (sessionclean cron skips when this exists)" || echo "absent"
  echo -n "gc_maxlifetime: "; php -r "echo ini_get(\"session.gc_maxlifetime\");"; echo
  echo -n "save_path: "; php -r "echo ini_get(\"session.save_path\") ?: \"/var/lib/php/sessions (default)\";"; echo
  echo -n "session count: "; ls /var/lib/php/sessions/ 2>/dev/null | wc -l
  echo -n "newest session: "; ls -lt /var/lib/php/sessions/ 2>/dev/null | sed -n "2p"
  echo -n "oldest session: "; ls -lt /var/lib/php/sessions/ 2>/dev/null | tail -1
  echo -n "free inodes on /: "; df -i / | tail -1
  echo -n "free space on /: "; df -h / | tail -1
'

```

If your sessions live on a separate Docker volume, replace `/` with the mount point in the last two lines.

For reference, here’s the output from my demo container :

```auto
cron running: 1296 cron -f -l
/etc/cron.d/php: present
/run/systemd/system: absent
gc_maxlifetime: 1440
save_path: /var/lib/php/sessions
session count: 0
free inodes on /: overlay 6553600 282619 6270981 5% /
free space on /: overlay 98G 15G 79G 16% /

```

The newest/oldest lines are blank above because the directory was empty at the time. On a busy instance you’d see a non-zero count and timestamps within roughly the last `gc_maxlifetime` window if cleanup is keeping up.

It would also help to see your HAProxy `backend` config for passbolt, in particular the `option httpchk` line and the check interval. HAProxy probes do not carry session cookies, so depending on the route they hit they may or may not contribute to the file count, and that’s worth checking against your actual setup rather than guessing.

These are general workarounds that are safe regardless of root cause:

- Free the directory by hand: `docker exec <container> find /var/lib/php/sessions -name 'sess_*' -type f -delete` (this only removes session files; active users will be logged out and need to sign in again)
- If you can tolerate sessions being lost on container restart, mount `/var/lib/php/sessions` as a tmpfs in your compose file, the directory then lives in RAM and cannot exhaust real inodes
- Move sessions out of files entirely by setting `SESSION_DEFAULTS=database` in the passbolt environment (and loading `config/schema/sessions.sql` into your DB), or to a cache backend like Redis

Happy to give you more specific solutions if you can provide more info.

Chat soon.

Cheers,  
Gareth

---

<div class="post-metadata">

**Author:** ![tanji](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.passbolt.com/tanji/32/4232_2.png) [@tanji](https://community.passbolt.com/u/tanji)\
**Post date:** [April 30, 2026, 2:39pm UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336/4 "2026-04-30T14:39:38Z")

</div>

Hi Gareth,

apologies but your answer is partly misoriented, given that we are in container context.  
Passbolt container doesn’t ship with system cron. You’re getting “cron running” because they ship their own cron to process emails, but that is not executing /etc/cron.d/php

Now I can share my fix with others if interested:

Create this script in /usr/local/bin, for example; In my case, we’re assuming that the passbolt docker-compose file is in /opt/passbolt ; feel free to change that to reflect your own install

`#!/usr/bin/bash`  
`cd /opt/passbolt`  
`docker-compose exec --user root passbolt /bin/sh -c "`  
`save_path='/var/lib/php/sessions';`  
`gc_maxlifetime=24;`  
`for pid in \$(pidof php-fpm8.4); do`  
` echo \"Touching open session files for php-fpm8.2 process \$pid...\";`  
` find \"/proc/\$pid/fd\" -ignore_readdir_race -lname \"\$save_path/sess_*\" -exec touch -c {} \; 2>/dev/null;`  
`done;`  
`echo \"Deleting all session files older than \$gc_maxlifetime minutes...\";`  
`find -O3 \"\$save_path/\" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin \"+\$gc_maxlifetime\" -delete;`  
`"`

Run this script in a systemd timer, or in cron if you wish.

Another possibility would be to enable the php cron in the container but this solution would only work between upgrades.

Best

Guillaume

---

<div class="post-metadata">

**Author:** ![gyaresu](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.passbolt.com/gyaresu/32/5320_2.png) [@gyaresu](https://community.passbolt.com/u/gyaresu)\
**Post date:** [May 1, 2026, 1:26am UTC](https://community.passbolt.com/t/php-sessions-filling-up-disk/10336/5 "2026-05-01T01:26:31Z")

</div>

G’day Guillaume,

Yep, spot on.

Your script works. There’s also a one-liner that calls `sessionclean` directly:

```auto
docker compose exec --user root passbolt /usr/lib/php/sessionclean

```

Same logic, picks up whatever PHP version and `gc_maxlifetime` are actually configured rather than pinning them (e.g. `$(pidof php-fpm8.4)`).

To skip the cron problem altogether, move sessions out of files. Two options:

- DB-backed: `SESSION_DEFAULTS=database` plus the schema from [https://book.cakephp.org/4/en/development/sessions.html#database-sessions](https://book.cakephp.org/4/en/development/sessions.html#database-sessions)
- Redis or Valkey: `SESSION_DEFAULTS=cache` with `CACHE_CAKECORE_CLASSNAME=Cake\Cache\Engine\RedisEngine`, `CACHE_CAKECORE_HOST`, and `CACHE_CAKECORE_PORT` pointing at the cache.
  - My demo repo example: [https://github.com/gyaresu/gareth-passbolt#valkey-session-handling](https://github.com/gyaresu/gareth-passbolt#valkey-session-handling)

Either way `/var/lib/php/sessions` stops mattering.

Prasad, you’re hitting the same root cause at a faster rate. Errors every few hours means something is creating sessions much faster than normal user load, like a polling integration or a misconfigured probe. The DB-backed sessions switch above fixes it either way.

Cheers  
Gareth
