PHP Sessions not being deleted on Ubuntu Server

I came across an AWS Ubuntu 10.04 server running PHP 5.3.x that not was automatically clearing expired PHP session files. They were stacking up in /var/lib/php5/, to the tune of about 207k files and 834MB in just a few months. On an AWS EC2 instance with an 8GB boot partition, that was over 10% of the disk! If left unattended the issue would cause a system failure in a matter of months.

What the heck? The Ubuntu configuration for AWS is practically bullet proof. Linux has never been easier. Even log rotation works out of the box.

Did some investigation. First off, the php.ini file was setup to never garbage collect.

session.gc_probability = 0

That actually makes a lot of sense to me, thank you Ubuntu.

PHP can be configured to clean up expired sessions based on a random ‘/roll’, as configured by gc_probability / gc_divisor.  That doesn’t sound very robust.  I am not actually certain a user who’s request happens to trigger the cleanup would notice, but it raises my spidey sense in terms of race conditions, multi-threading errors, and the kind of strange bugs that are never replicable. Triggering disk cleanup at the exact millisecond you are trying to serve a request to a user – if it sounds like a bad idea, it probably is!

It makes more sense to control this sort of cleanup task with cron.  As it turns out, in /etc/cron.d/php the following job runs twice an hour (at :09 and :39 of every hour).

# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -delete

Note this reference: /usr/lib/php5/maxlifetime

Turned out on this server, the maxlifetime file did not exist! So the cron job wasn’t doing anything.  The one line command does the following:

  1. If /usr/lib/php5/maxlifetime exists and is executable, and…
  2. If the /var/lib/php5/ directory exists, then…
  3. Find the files in the php session directory X minutes older than the value reported by maxlifetime, and delete them.

I created that file and set it to echo the number of minutes the sessions should be kept around for:

sudo chmod +x /usr/lib/php5/maxlifetime

cat /usr/lib/php5/maxlifetime
#!/bin/bash
echo "60"

In this case, one hour seemed prudent. The default gc_maxlifetime is 1440, which is 24 minutes.  Watch out: the find command cmin argument is in minutes, but the php gc_maxlifetime is in seconds.

Here is the only other post I could find related to the issue. The bash script they did is a lot more complicated than simply setting a value, it parses php.ini and uses the value found there.

This entry was posted in Sys Admin. Bookmark the permalink.

Comments are closed.