WHM/Cpanel per-user php.ini under Apache 2.x and suPHP

Print Friendly, PDF & Email

OK, time for another delve into the underbelly of WHM, and a short lesson in how to achieve something which seems so poorly covered (although Cpanel, to their credit have started to explain things a little more clearly) elsewhere, especially for folks who may not be uber-geeks (I make no such claim!).

Very often we want to tighten php.ini up to make our servers as secure as possible – but then there is always going to be a few accounts where for various reasons, you want to bend the rules. Well, now you can set up your WHM/Cpanel server with a central php.ni and yet allow selected users the ability to use a customised php.ini, managed and controlled by YOU!

About the mighty PHP.INI

First of all, a little about php.ini – this file contains all of the directives that determine how PHP (not necessarily Apache) will behave. You can see your active php.ini settings by using the phpinfo() function from within a php script.

Now, php.ini contains some pretty powerful stuff – not really the kind of stuff you want to allow any Tom, Dick, or Harry to alter (for example you can override the maximum file upload size). PHP, despite being reasonably secure these days, still has exploits so in a shared environment (where you are hosting multiple customers on a single logical server) it’s wise to be strict.

The default (as of today) in WHM, means that in order to customise PHP’s behaviour, all you need do is put a php.ini file in the same directory as your php script (you have to put a php.ini file in every directory where you want the custom changes to have effect, it doesn’t have recursive effects, like htaccess can do.) This is a bad idea for the reasons already explained.

Plus, most people who do this don’t prevent the php.ini file from being read by hackers, who can determine the structure of your code more easily. Also, it would appear many people don’t realise that php.ini files aren’t merged, but rather the local php.ini file you place on your website totally overwrites the core/default one, being that any settings carefully crafted by the administrator are totally scrubbed back to php’s defaults.


OK, first things first. You should really be running PHP with the suPHP mod enabled. If you are running PHP in DSO mode this won’t work. This can be checked in  Main >> Service Configuration >> Apache Configuration >> PHP and SuExec Configuration. I make NO WARRANTY that the following will just work – always carry out thorough testing to ensure your environment is safe before releasing it to production status! I have to say that, as there’s always someone out there who doesn’t want to take responsibility for themselves!

The simple answer – a fixed PHP.INI for all

OK, let’s get the sledge hammer out. You run the server and you want to law down the law. It’s pretty simple, on the current version of Cpanel, just SSH into a shell and go to


Somewhere towards the bottom you will find a section that looks like this:

;Uncommenting these will force all requests to that handler to use the php.ini
;in the specified directory regardless of suPHP_ConfigPath settings.

Just remove the comment markers (semi-colons) from the bottom three lines. SIMPLES! This will force every page in every account to use your central php.ini files. Anything in .htaccess files or httpd.conf that tried to redirect to a different php.ini will be ignored. To make this take effect, you will need to restart Apache.

PHP.INI on a per user basis

OK, this one is a little more complicated. We could, of course, start hacking away at the httpd.conf file putting in global php.ini settings at the top, and then entering individual php.ini directives for each virtual hosting account. This would be pretty pointless because a.) it’s hard work, and b.) it would get overwritten the minute you changed any hosting settings in WHM.

Instead, we will leverage the preferential include system that is part of Apache 2.x

The first job is to set a global php.ini file to be used by default.

We can do this by placing a *.conf file in /usr/local/apache/conf/userdata/ for example:


It should be empty or not exist at all on a standard install of WHM, so we just need to add:

<IfModule mod_suphp.c>
   suPHP_ConfigPath /usr/local/lib/

OK, so now we have put that there, we have effectively achieved the same thing as before – forcing everyone to use the core php.ini file. However, this won’t take immediate effect unless we run:

/scripts/ensure_vhost_includes --all-users

It also won’t take effect for NEW accounts or subdomains which we add. In order for that to happen we must also edit (if using apache 2.2):


around line 24 to read:

<IfModule mod_suphp.c>

   suPHP_UserGroup %user% %user%

   suPHP_ConfigPath /usr/local/lib/


note added 18 March 2010: You should monitor this file. As it will get overwritten when /scripts/upcp runs overnight (if automatic updates are selected) or whenever you perform a manual update. If you use CSF firewall, you can add the directory to the watch-for-changes list. Annoying, but no way to make it truly permanent until Cpanel add improvements.

Now for the fun bit – adding a custom php.ini file for just a single user. OK. First we have to take a copy of our original php.ini file (in /usr/local/lib/) and place it somewhere safe, and out of reach of our users. So

mkdir -p /etc/phpconf/username
cp /usr/local/lib/php.ini /etc/phpconf/username/

Feel free to customise your new /etc/phpconf/username/php.ini file. Remember this file is not merged with the core php.ini – it entirely replaces it.

Then we have to make sure that the virtual host picks up the new php.ini file. Again we can use Apache 2.x’s include system.

mkdir -p /usr/local/apache/conf/userdata/std/2/username/mainaccountdomain.com

The std bit could also say ‘ssl’ if you wanted also to enjoy the custom php.ini on an ssl virtual host. Once you have created the directory, then place a file in it called suphp.conf, and edit the file as follows:

<IfModule mod_suphp.c>
suPHP_ConfigPath /etc/phpconf/username/

That’s it! All we need to do now, is rebuild the httpd.conf file and restart Apache. The eaiest way to do all this is:

/scripts/ensure_vhost_includes --all-users
or if you have zillions of accounts:
/scripts/ensure_vhost_includes --user=username

Go and try it out. Any php.ini files placed in your users’ accounts should now be ignored, but you can still provide tweaks for valued customers by giving them what they want (within reason of course!) 🙂 Enjoy.


Many thanks to Mike who commented below… after communicating with Mike by email and after much gnashing of teeth, this article was amended to the current edit above.

The only problem remaining is that modifying the cpanel templates put’s us back in the situation we were in originally in that the next Cpanel update could very well overwrite any modified templates. So we really need a final script to run on a cron to tell us if the core Cpanel templates have changed and email us to remind us to edit the mod back in again!

Tags: , ,

11 Responses to “WHM/Cpanel per-user php.ini under Apache 2.x and suPHP”

  1. Edward Beckett February 16, 2013 at 7:44 pm #

    “Re: You should monitor this file. ” …

    You forgot to update apache_distiller … conf directives can be over-ridden as long as you remember to save the state …

    /usr/local/cpanel/bin/apache_conf_distiller –update –main …

    /usr/local/apache/bin/apachectl -t

    /usr/local/apache/bin/apachectl -k restart

    • Steve February 28, 2013 at 3:49 pm #

      Thanks Ed… but I think


      Is out of reach of distiller. This is a cpanel template file.

  2. endoet March 24, 2010 at 5:22 am #

    and also i have remove semi colons on /opt/suphp/etc/suphp.conf

  3. endoet March 24, 2010 at 2:41 am #


    This configuration are not work on my server.

    1. I create a file on /usr/local/apache/conf/userdata/suphp.conf containing :

    suPHP_ConfigPath /usr/local/lib/

    and modify /usr/local/cpanel/etc/httptemplates/apache2_2/default

    2. And then run /scripts/ensure_vhost_includes –all-users
    3. Copy /usr/local/lib/php.ini to /etc/phpconf/someuser/php.ini
    4. Create directory /usr/local/apache/conf/userdata/std/2/someuser/somedomain.com and add suphp.conf contains :

    suPHP_ConfigPath /etc/phpconf/someuser/

    5. Then again run /scripts/ensure_vhost_includes –all-users

    Loaded Configuration File is still on /usr/local/lib/php.ini.

    Have i miss something ?

    Thanks in Advance

    • Steve March 24, 2010 at 8:44 am #

      I’m not sure what is wrong. Obviously, this relies on your using Apache 2.2 or at least 2.0 for the cpanel templates to have an effect. The only thing missing is the conditional checks around the main statement

      suPHP_ConfigPath /etc/phpconf/florida1/

      But as long as you have suPHP running, then they aren’t absolutely necessary (in my understanding). I’m sorry I can’t be any more help. Also, you could try putting the user-specific *.conf file in:
      /usr/local/apache/conf/userdata/std/2/someuser/suphp.conf instead of
      This way it should apply to all domains on the account.
      Further than that I’m afraid I am at a loss – maybe one for forums.cpanel.net ?

  4. Ben March 12, 2010 at 6:01 pm #


    I have maked your Learn in my server , so i customized : /etc/phpconf/username/php.ini for my an account , But it don’t working now 🙁

    Plase Help Me Rather…
    Thank You

    • Steve March 13, 2010 at 11:19 am #

      Sorry, Ben. I’m having difficulty understanding your post. You only appear to have placed a modified php.ini file somewhere safe on your server. You need to point to it via /usr/local/apache/conf/userdata/std/2/username/mainaccountdomain.com – assuming you are using apache 2.x and this is NOT an ssl host. And then you must reload the conf files, and restart apache as described in the original post. This is just how it works for my standard Cpanel installs.

  5. Mike February 18, 2010 at 4:52 pm #


    Great writeup. You have articulated the procedure extremely well, far better than I could have. I’m sure your instructions will help a lot of people provide a more secure hosting environment. I’m going to proceed with the edit in the httptemplates tree now 🙂


  6. Mike February 17, 2010 at 6:48 pm #


    “You seem to have found this out yourself by creating /usr/local/apache/conf/userdata/suphp_configpath.conf – I’m not aware of this method, and am unsure if this affects all users, as it doesn’t seem to be user specific.”

    Yes, this does affect all users / all user domains irrespective of whether they are using SSL or not.

    My intention is/was:

    1. To create a single conf file that will apply the php.ini restriction [force the use of global php.ini, disallow the use of custom php.ini] to all users / all domains].

    2. Then create a single conf file for each user (or a single domain) that requires a custom php.ini

    So I think I have accomplished #1 best by using a single /usr/local/apache/conf/userdata/suphp_configpath.conf rather than potentially hundreds of /usr/local/apache/conf/userdata/std|ssl/2/username/[domainname]/suphp_configpath.conf files

    My problem was that when I create a brand new account, it doesn’t automatically “inherit” the forced suphp.ini.

    I’m going to add the same suphp_configpath info to /usr/local/apache/conf/includes/pre_main_global.conf, rebuild httpd.conf, and then add a new account to see if that new account inherits the force suphp.ini setting.


  7. Mike February 17, 2010 at 5:17 pm #

    Let me caution about the procedure you mention for using the include system.

    Im running Apache 2.2.x, suPHP. If I simply add your code to /usr/local/apache/conf/includes/pre_main_global.conf and then rebuild httpd.conf using /scripts/ensure_vhost_includes –all-users , the changes do not take effect. If I stick a php.ini file in a user’s public_html directory with “disable functions =” in it and then view phpinfo for that site, it will reveal:

    Loaded Configuration File: /home/username/public_html/php.ini


    disable_functions =

    The only way I could get apache to do what you suggest is to create a file inside /usr/local/apache/conf/userdata with the appropriate suPHP_ConfigPath directive.

    I created /usr/local/apache/conf/userdata/suphp_configpath.conf

    In that file I added:

    suPHP_ConfigPath /usr/local/lib/

    I then ran /scripts/ensure_vhost_includes –all-users

    Now, if I view the phpinfo for the same site (with the php.ini file in the public_html folder that has “disable_functions =” in it, I see:

    Loaded Configuration File: /usr/local/lib/php.ini

    I have not been able to correctly get what you have listed in your post to work if I put it in /usr/local/apache/conf/includes/pre_main_global.conf

    Also, readers should be aware that when a new account is added [using my method], it does not automatically inherit that configuration. After a new account is added I have to run /scripts/ensure_vhost_includes –all-users or /scripts/ensure_vhost_includes –user=new_account_username (where new_account_username = the username of the newly created account of course)


    • Steve February 17, 2010 at 5:34 pm #

      Hi Mike. If you only modify usr/local/apache/conf/includes/pre_main_global.conf then that won’t be enough – as you found out. My post makes it clear you must also place a file called suphp.conf into /usr/local/apache/conf/userdata/std/2/username/mainaccountdomain.com/

      Without the second stage, it leaves you open to local php.ini files

      You seem to have found this out yourself by creating /usr/local/apache/conf/userdata/suphp_configpath.conf – I’m not aware of this method, and am unsure if this affects all users, as it doesn’t seem to be user specific.

      I am sure (but may be wrong!) if you used my full method BEFORE creating the user account concerned, then it would get the new settings as httpd.conf is rebuilt and apache restarted as a matter of course by WHM when adding a new account. Obviously, doing any of this retrospectively will require the main httpd.conf to be rebuilt using the command listed and apache restarted.

Leave a Reply

Bot test * Time limit is exhausted. Please reload the CAPTCHA.