Home > Server Admin > FastCGI with a PHP APC Opcode Cache

FastCGI with a PHP APC Opcode Cache

Hosting PHP web applications in a shared environment usually involves a choice between two exclusive options: host a fast application by using a persistent opcode cache, or host an application that your shared neighbors can’t snoop around or destroy. In this post I discuss a way to get the best of both worlds, by combining FastCGI with a single opcode cache per user.

This is a long post, ready to jump right in? Skip the history!

The evolution of mod_php to FastCGI

In the early days of all-you-can eat shared hosting, administrators served PHP via mod_php. mod_php loads the PHP interpreter into every web server process during server startup, thus alleviating the expense of starting an interpreter each time a script executes. This allowed executing PHP scripts relatively fast.

mod_php came with a few drawbacks:

  • Every server process, even those serving static files such as images and CSS scripts, contained the PHP interpreter. This caused a lot of bloat in the web server’s memory footprint. It also eliminated the ability to use mutil-threaded web servers as many PHP extensions are not thread safe.
  • Every PHP script ran as the same user as the web server. While web servers typically run as a non-privileged user such as nobody, multiple mutually untrusting shared accounts could easily access, disrupt or destroy each other by executing a PHP script.

FastCGI loads the PHP interpreter into a separate process. This process is still persistent across connections, but, using a mechanism such as suEXEC, can run as a different user. Static files can be served by a lightweight multi-threaded web server process while PHP scripts are served by a single-threaded FastCGI process. What’s more, if PHP crashes, it doesn’t bring down the entire web server.

In the shared hosting context, each user’s PHP scripts are executed with the user’s credentials. This leads to a more secure environment for both the host and the shared user.

The opcode cache

One of the easiest and most effective things you can do to speed up your PHP scripts is to enable an opcode cache such as APC, XCache or eAccelerator. An opcode cache caches the compiled state of PHP scripts in shared memory. Thus each time a PHP script is run, the server doesn’t have to waste time compiling the source code. Opcode caches can speed up execution of scripts by up to 5 times and decrease server load.

In my opinion running PHP on a webserver without an opcode cache is like restarting your car’s engine at every stop sign. You can still get where you’re going but it’s going to take longer and put a lot more wear and tear on your engine. An opcode cache is so important that APC is going to be included in the core of PHP 6.

An opcode cache requires that the PHP interpreter process persist between connections. Both mod_php and FastCGI satisfy this requirement. An opcode cache requires RAM, a precious commodity on a shared hosting server. By default, each cache allocates 30MB of shared memory. This can be easily configured up or down depending on the scripts you are running.

Combining FastCGI with an opcode cache

So if we agree that FastCGI and opcode caches are good (a must IMHO), why do most shared hosting providers only enable one? The answer is two-fold:

  1. RAM. Each opcode cache is typically 30MB. Each PHP process gets its own opcode cache. Each user must run its own PHP process for security. Thus each user requires at least 30MB of RAM on top of the RAM required for the PHP interpreter (a lot). All you can eat shared hosting companies typically oversell their servers. Overselling usually works when it comes to bandwidth, I/O and CPU time, however overselling RAM is harder. Remember the PHP processes stay in memory between connections. So a small site only getting a 100 hits a day still hogs the same amount of RAM as a busy site. This breaks the overselling model.
  2. FastCGI. In a typical configuration, FastCGI spawns many separate PHP processes per user. Each PHP process needs its own opcode cache. Instead of maintaining one opcode cache (per user), the server maintains multiple caches. This reduces the effectiveness of the cache and increases the strain on server resources.

Solving problem #1 is hard. Some have suggested a single cache that can be shared across multiple processes and users and still provide assurance that different users cannot mess with each other. This blog post is not about #1. There are many reasons to use unlimited shared hosting providers. Opcode caches are not one.

This blog post is about how to solve problem #2. The goal is to have a reasonable system that utilizes suEXEC, FastCGI and the APC opcode cache. Each user should have one and only one opcode cache. The administrator should be able to adjust the size of the cache for each individual user based on their needs (and monthly fee). Finally, the solution should decrease script load time and increase server performance while maintaining security and privacy between accounts.

mod_fastcgi vs mod_fcgid

I run Apache on my server. Many people suggest running a more lightweight server such as lighttpd. One day I may switch, but for now I’ve tuned my Apache server to be as fast as I need.

There are two modules to implement FastCGI on Apache – mod_fastcgi and the newer mod_fcgid. Both are binary compatible with each other and do basically the same thing. mod_fcgid sports better control over spawning processes and error detection. mod_fastcgi has been around longer. Both support suEXEC, and both separate PHP from Apache, thus allowing Apache to run threaded workers if desired.

As I mentioned in the combining FastCGI with an opcode cache section, the typical behavior of FastCGI is to spawn multiple PHP interpreters. The FastCGI process monitors each child process, kicking out processes with errors, restarting failed processes and sending incoming requests to the least busy child. This is usually the preferred behavior, and mod_fcgid implements it particularly well.

Opcode caches throw a wrench in this however, because of their inability to share the cache across FastCGI processes. Hopefully one day this will be remedied. Luckily, in the meantime, PHP is capable of playing “process manager” and a single PHP process can spawn several children to handle requests. This way the parent PHP process can instantiate the opcode cache and its children can share it. You’ll see this later when we set the PHP_FCGI_CHILDREN environment variable.

Both mod_fcgid and mod_fastcgi can be told to limit the number of PHP processes to 1 per user. The PHP process can then be told how many children to spawn. Unfortunately mod_fcgid will only send one request per child process. The fact that PHP spawns its own children is ignored by mod_fcgid. If we use mod_fcgid with our setup, we can only handle one concurrent PHP request. This is not good. A long running request could easily block multiple smaller requests.

mod_fastcgi will send multiple simultaneous requests to a single PHP process if the PHP process has children that can handle it. This is the reason we must use mod_fastcgi to achieve our goal of one cache per user.

Implementation

This section describes the steps I took to enable suEXEC FastCGI with a single APC opcode cache per user on Apache 2.2. These instructions may vary by Linux distribution and are not intended to be a cut-and-paste howto. I use Gentoo, so most steps will be geared towards a Gentoo install but the general idea should work on any distribution.

1. Install php-cgi and disable mod_php

The PHP interpreter can run in three different modes: as an Apache module, as a CGI binary or as a command line command. Typically, separate binaries are built for the CGI and CLI modes, php-cgi and php respectively. On Gentoo, each mode is associated with a USE flag: apache2 for mod_php, cgi for a CGI binary, and cli for command-line PHP. The cgi USE flag must be enabled. If it isn’t, add it to /etc/make.conf or /etc/portage/package.use and recompile PHP. On other distributions, search for a php-cgi binary.

You will want to disable mod_php (if it was enabled) before implementing FastCGI. This can be done by commenting out the appropriate LoadModule line in your Apache configuration file:

# LoadModule php5_module modules/libphp5.so

On Gentoo, this can be easily done by removing PHP5 from the APACHE2_OPTS variable in /etc/conf.d/apache2.

2. Install and enable mod_fastcgi Apache module

We already discussed why we must use mod_fastcgi instead of mod_fcgid. On Gentoo, installing mod_fastcgi can easily be done by running:

$ sudo emerge mod_fastcgi

For other distributions, try installing a mod_fastcgi package or see the FastCGI Installation Notes.

Make sure your Apache conf file contains the line:

LoadModule fastcgi_module modules/mod_fastcgi.so

On Gentoo, this line is found in /etc/apache/modules.d/20_mod_fastcgi.conf. mod_fastcgi is enabled by adding FASTCGI to the APACHE2_OPTS variable in /etc/conf.d/apache2.

3. Install and configure the APC Opcode Cache

To install APC on Gentoo, simply run:

$ sudo emerge pecl-apc

For other distributions, see the Alternative PHP Cache installation instructions.

Once installed, look for the apc.ini file in your php extension configuration directory (e.g. /etc/php/cgi-php5/ext-active). The default apc.ini works with one exception. You need to comment out apc.shm_size="30" (line 5 below). Commenting this line will enable us to set it per user later.

My apc.ini file looks like:

extension=apc.so
apc.enabled="1"
apc.shm_segments="1"
;commenting this out allows you to set it in each fastcgi process
;apc.shm_size="30"
apc.num_files_hint="1024"
apc.ttl="7200"
apc.user_ttl="7200"
apc.gc_ttl="3600"
apc.cache_by_default="1"
;apc.filters=""
apc.mmap_file_mask="/tmp/apcphp5.XXXXXX"
apc.slam_defense="0"
apc.file_update_protection="2"
apc.enable_cli="0"
apc.max_file_size="1M"
apc.stat="1"
apc.write_lock="1"
apc.report_autofilter="0"
apc.include_once_override="0"
apc.rfc1867="0"
apc.rfc1867_prefix="upload_"
apc.rfc1867_name="APC_UPLOAD_PROGRESS"
apc.rfc1867_freq="0"
apc.localcache="0"
apc.localcache.size="512"
apc.coredump_unmap="0"

4. Install/enable Apache suEXEC

Apache 2.2 contains built-in support for executing CGI programs as a different user id and group id than the webserver. This support must be compiled into Apache. On Gentoo, use the suexec USE flag and recompile apache. On other distributions, see Configuring & Installing suEXEC.

5. Create wrapper scripts

The Apache suEXEC security model requires that the CGI binary meet some pretty stringent requirements concerning file ownership and permissions. Rather than copying the php-cgi binary for each user, we create multiple wrapper scripts around the php-cgi binary. These wrapper scripts allow us to set options on a per-user basis.

I keep my wrapper scripts in /var/www/bin, though you may keep yours wherever you want. Each user has a directory in /var/www/bin, for example:

$ ls -l /var/www/bin
dr-xr-xr-x 2 bob bob 104 Jun 24 13:56 bob/
dr-xr-xr-x 2 sue sue 104 Jun 24 13:56 sue/
dr-xr-xr-x 2 joe joe 104 Jun 24 13:53 joe/

Inside each user’s bin directory is a single wrapper script, php-fastcgi:

$ ls -l /var/www/bin/bob/
-r-xr-x‐‐‐ 1 bob bob 145 Jun 24 13:56 php-fastcgi

I’ve shown the ls -l output to show the file and directory ownership and permissions. These are important, and Apache suEXEC will not work correctly if the owner and permissions are not correct.

The contents of the php-fastcgi file in each user’s bin directory (see below for an explanation):

#!/bin/sh

PHP_FCGI_CHILDREN=5
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=500
export PHP_FCGI_MAX_REQUESTS

umask 0022
exec /usr/bin/php-cgi -d apc.shm_size=25

PHP_FCGI_CHILDREN
This variable tells PHP how many child processes it should spawn. As we discussed earlier, our PHP process will act as “process manager” and pass incoming requests to its children. The parent will maintain a single opcode cache which each child will share. The PHP_FCGI_CHILDREN variable tells PHP how many children to spawn. Another way to think of this is the number of concurrent PHP requests that can be handled per user.

PHP_FCGI_MAX_REQUESTS
PHP is known for memory leaks in long running processes. This variable causes each child process to be restarted once it has served a given number of requests (e.g. 500). Only the child process is restarted, the parent process remains. Since the parent process maintains the opcode cache, the opcode cache persists.

umask 0022
This sets the umask the PHP binary will run under. Some people may prefer a stricter umask such as 0077, however I’ve found 0022 works best as it allows the Apache server running as nobody to read static files written earlier by a suEXEC’d PHP process. Some PHP applications (WordPress plugins) do not do a good job with permissions, and a strict umask can cause applications to fail.

exec /usr/bin/php-cgi -d apc.shm_size=25
This line calls the php-cgi binary and modifies the APC cache size. It is possible to configure this to use a separate php.ini file instead of setting configuration parameters on the command line, however I like the ability to share a single php.ini file.

6. Edit global Apache settings

There are two sets of settings you must configure in Apache: those that affect all users and those that affect a specific user. This section describes global settings that affect all users.

I like to keep my global settings in my /etc/apache/modules.d/20_mod_fastcgi.conf file, but these can go in any part of your http.conf file. Most of the time you do not want this in a VirtualHost section. My global mod_fastcgi settings look like this (see below for an explanation):

<IfDefine FASTCGI>
LoadModule fastcgi_module modules/mod_fastcgi.so

FastCgiConfig -idle-timeout 20 -maxClassProcesses 1
FastCgiWrapper On

AddHandler php5-fcgi .php
Action php5-fcgi /cgi-bin/php-fastcgi


<Location "/cgi-bin/php-fastcgi">
   Order Deny,Allow
   Deny from All
   Allow from env=REDIRECT_STATUS
   Options ExecCGI
   SetHandler fastcgi-script
</Location>

</IfDefine>

FastCgiConfig
The FastCgiConfig configuration directive sets parameters for all dynamic FastCGI processes. The idle-timeout causes FastCGI to abort a request if there is no activity for more than 20 seconds. The maxClassProcesses option is very important: it tells FastCGI to only spawn one php-cgi process regardless of how many requests are pending. Remember that our PHP process will spawn its own children, so FastCGI only needs to spawn one. Until this APC bug is fixed, this is necessary to allow sharing the APC cache among children.

FastCgiWrapper
The FastCgiWrapper configuration directive is needed to allow suEXEC to work.

AddHandler / Action
The AddHandler and Action configuration directives tell Apache to handle all files ending in .php with the php-fastcgi script in cgi-bin. In the next step, you’ll see how we alias this cgi-bin directory for each individual user.

Location
The Location directive tells Apache how to handle requests to /cgi-bin/php-fastcgi. The Allow from env=REDIRECT_STATUS on line 13 prevents users from executing this script directly. With this line, the only way to execute php-fastcgi is by requesting a file ending in .php.

7. Edit per-user Apache settings

On my host, every virtual host is associated with one user. And every user has exactly one opcode cache. A single user can have multiple virtual hosts, but these virtual hosts share the same opcode cache.

For each virtual host, I add the following lines, customized for the user associated with that virtual host:

<VirtualHost *:80>
ServerName www.sue.bltweb.net
...
<IfModule mod_fastcgi.c>
   SuexecUserGroup sue sue
   Alias /cgi-bin/ /var/www/bin/sue/
</IfModule>
...
</VirtualHost>

When combined with the global apache settings and the wrapper scripts, this will launch the php-cgi binary using suEXEC to execute as the appropriate user and group whenever a .php file is requested.

There are several different ways to call the FastCGI binary. On my hosts, users don’t have access to their cgi-bin directory. The /var/www/bin directory is not accessible by ordinary users. This doesn’t have to be the case, the cgi-bin directory could be stored in the user’s directory. It is important to note that allowing the user to modify php.ini values allows them to modify their opcode cache size, which could have severe repercussions on RAM usage.

Pros and Cons

The implementation described above is only one of many ways to implement FastCGI and APC. In my opinion, it is the best way to meet my goals, but in this section I’ll try to outline some of the advantages and disadvantages of my setup.

Advantages
  • Different users can have different APC cache sizes
  • Multiple concurrent PHP requests can be handled simultaneously
  • RAM usage is predictable as a product of the number of users on the host
  • Server is better secured against attacks from the inside since PHP processes run as the user who owns the script
  • Resource usage can be monitored since each user has a separate PHP process
  • A PHP crash doesn’t mean an Apache crash. If a PHP process crashes it is restarted automatically.
Disadvantages
  • The process manager built into mod_fastcgi isn’t used. One of the motivations behind mod_fcgid was to improve upon the process manager in mod_fastcgi.
  • The newer mod_fcgid cannot be used as it will only send one request at a time to the PHP process, thus multiple requests can’t be handled simultaneously
  • Maintaining separate opcode caches per user uses a considerably larger amount of RAM than a single opcode cache used with mod_php
  • Users cannot alter php.ini files
  • If a PHP script crashes it has potential to take down all of the PHP requests currently being processed for that user

Performance

In my next post I’ll try to cover RAM usage, performance, benchmarks, compatibility and best practices. This post is already way too long; I’m surprised you are even still reading it!

Stay tuned for more information on using FastCGI with a PHP APC opcode cache. In the meantime let me know what you think of this approach. Have you tried it? Know of a better way? Found any bugs or problems? Leave a comment below!

Server Admin , , , ,

  1. July 28th, 2009 at 14:45 | #1

    HI Brandon,
    Thanks for this valuable information. Is it possible, if i can use suphp + APC caching. Is that wrapper script works in case of suphp. I am having ubuntu box with php 5.2.4 + APC 3.1.2. I was struggling with apc + suphp combination from last three days. But today i got what that was not working. Let me know if that wrapper script can work in case of suphp.

    By the way, Thanks for this article. It contains very useful contents.

    Thanks

  2. July 28th, 2009 at 15:27 | #2

    @Rimpy
    I’m not entirely sure, as I have never worked with suPHP, but I don’t think it will work. The whole idea behind FastCGI is that it keeps the PHP interpreter (and thus the opcode cache) loaded between requests. Without FastCGI, PHP essentially shuts down after every request, and must be started again on the next request.

    I do not think the Apache module used in suPHP keeps the interpreter loaded between requests. Therefore, while configuring APC may appear to work, the opcode cache is effectively cleared after every request and thus it is useless.

    Depending on your setup, you may consider using suEXEC instead of suPHP as I describe in my post. It assumes that each virtual host will run as one and only one user. Normally this is not a problem, but you may have a special case.

  3. Larry E. Dickey
    August 2nd, 2009 at 22:10 | #3

    Hello Brandon,

    I’ve got a Gentoo system set up with a `basic’ LAMP scenario. I’ve been doing some programming with PHP5. I read this post, and found it very interesting. However, it’s a bit too complex for my current needs. I’m wanting to tryout php running as fastcgi on my localhost machine. I’m not running multiple sites. I’m not at that level yet. I’d like to learn about virtual hosting one day, but I’m just not there yet. I’ve emerged mod_fastcgi, configured php5 with fastcgi support, and looked at the configuration files for both apache2 and mod_fastcgi. How in the world do I do a basic configuration of fastcgi/php/apache just to test it from localhost? Any help would be greatly appreciated. I know it’s got something to do with the two config files, but I’m not sure what to add to them to get it working from localhost.

  4. August 2nd, 2009 at 22:19 | #4

    @Larry E. Dickey
    If you aren’t worried about multiple users, you can basically ignore all the suEXEC stuff in my post.

    Here’s one way to do it. Since you say you’re on Gentoo, I’ll assume you are running Apache as user apache:
    * Follow my steps 1-4 above
    * On step 5, rather than ‘bob’ use the user ‘apache’. The directory will be named ‘apache’, the wrapper owned by apache, etc.
    * In step 6, add the following line to your 20_mod_fastcgi.conf file (above the Location block):
    Alias /cgi-bin/ /var/www/bin/apache/
    * Ignore step 7

    Essentially what you are doing is creating one wrapper script and all PHP scripts will use it to execute. There is no need to mess with the suEXEC stuff because you are running your scripts as the webserver user, apache.

  5. Larry E. Dickey
    August 3rd, 2009 at 18:11 | #5

    I followed your modified instructions and I’m still unable to get it working correctly. Now, when I attempt to load a php script from my document root, I’m thrown a:

    `You don’t have permission to access /cgi-bin/php-fastcgi/fontwrap.php on this server.’

    Prior to trying this fastcgi setup, I was successfully loading php scripts from /var/www/localhost/htdocs without any problem whatsoever. This is baffling to me because, other than this situation, I’m a pretty savvy gentooist. I can create overlays and ebuilds for either 3rd party apps or packages that have a portage block on them. I’ve also done some kernel programming. I’ve worked on the ext3/dcache in the fs.

    One of the things I don’t quite understand with the directions you gave me is: Do I have to create the cgi-bin directory, or can I just set this up to use the default docroot directory which has been working for me just fine with mod_php?

    Even though I’m not a dns or network admin, it seems (according to your directions), that /cgi-bin/ and /var/www/bin/apache fall outside of the docroot.

    Could that be part of my problem? I’ve never created a cgi-bin directory before so I’m not sure exactly whats going on. Would there be a way to achieve this by still being able to serve the scripts out of the /var/www/localhost/htdocs directory instead of how you suggested the `Alias /cgi-bin/ /var/www/bin/apache/’?

    This is frustrating the heck out of me. It just seems like it shouldn’t be this difficult to resolve.

  6. August 3rd, 2009 at 18:31 | #6

    @Larry E. Dickey
    I keep my cgi-bin directories outside of user control as a personal preference. I keep mine in /var/www/bin/%username%.

    You may keep your user directories anywhere you wish. The only requirement is that you set an Alias somewhere that points URL requests to /cgi-bin to your physical location (e.g. /var/www/bin/apache in my case, or /var/www/localhost/cgi-bin if you prefer).

    Here are some checks:

    1. Do you have a /etc/apache/modules.d/20_mod_fastcgi.conf file like in step 1?
    2. Does it have the AddHandler and Action lines as in step 6?
    3. Do you have a directory somewhere that has the php-fastcgi wrapper script in it (e.g. /var/www/bin/%username%)? Is that directory aliased to the /cgi-bin URL using an Alias line as in my comment’s modified instructions?
    4. Is the php-fastcgi wrapper executable by the webserver as in step 5?
    5. Does the /usr/bin/php-cgi file exist?

    If all of these things are true, I’m not sure what the problem is. You could try emailing me or posting your 20_mod_fastcgi.conf file.

    One thing to note is that I do not have cgi-bin directory anywhere on my system. The cgi-bin is only an Apache URL alias to /var/www/bin/%username%, where in your case %username% is apache.

    Also, FastCGI is notoriously hard to set up, which is one reason why a lot of people end up going with mod_php. You are definitely not alone in your frustration.

  7. Larry E. Dickey
    August 3rd, 2009 at 20:21 | #7

    The answer is yes to your questions about the checks. Do I have to `physically’ create a /cgi-bin/ directory from the “/” (root) hierarchy of the filesystem and then that is what is being aliased with the Alias line? I don’t quite understand.

    Here is 20_mod_fastcgi.conf:

    LoadModule fastcgi_module modules/mod_fastcgi.so

    FastCgiConfig -idle-timeout 20 -maxClassProcesses 1

    AddHandler php5-fcgi .php
    Action php5-fcgi /cgi-bin/php-fastcgi

    Alias /cgi-bin/ /var/www/localhost/htdocs/cgi-bin/

    Order Deny,Allow
    Deny from All
    Allow from env=REDIRECT_STATUS
    Options ExecCGI
    SetHandler fastcgi-script

    # vim: ts=4 filetype=apache

    Also, here is tail -f of /var/log/apache2/error_log:

    [Mon Aug 03 20:16:02 2009] [notice] FastCGI: process manager initialized (pid 5480)
    [Mon Aug 03 20:16:02 2009] [notice] Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.8k mod_fastcgi/2.4.6 configured — resuming normal operations
    [Mon Aug 03 20:16:08 2009] [error] [client 127.0.0.1] (2)No such file or directory: FastCGI: stat() of “/var/www/localhost/cgi-bin” failed
    [Mon Aug 03 20:16:12 2009] [error] [client 127.0.0.1] (2)No such file or directory: FastCGI: stat() of “/var/www/localhost/cgi-bin” failed
    ^C

  8. Larry E. Dickey
    August 3rd, 2009 at 21:50 | #8

    YEAH!!!!!! I got it man. I kept staring at the error_log and that stat() error gave me the clue. I had created the cgi-bin directory in /var/www/localhost/htdocs/cgi-bin. The stat() call message in the error_log and what I had in the Alias line in the 20_mod_fastcgi.conf file where different.

    You could tell that I was getting close by looking at the first line in the error_log. The FastCGI process manager was indeed initialized. It was the classic `one off’ on the location of the cgi-bin directory. So, basically I just moved the cgi-bin directory back one level into /var/www/localhost/cgi-bin instead of /var/www/localhost/htdocs/cgi-bin.

    As soon as I did that and refreshed the test.php info page, it fired. Looking at that, the Server API part showed that it had changed to CGI/FastCGI. Wow, what a head trip! That was definitely tricky for me anyway.

    I kept thinking to myself, man, if I was able to set up a firewall and iptables with this system, surely I should be able to figure this out. But, in my case, when your not used to working with servers and all the different protocols on a routine basis, the smallest configuration details and such can literally seem monumental.

    Thank you Brandon for your help on this issue. It means alot because it kept me going at this.

  9. August 4th, 2009 at 00:31 | #9

    @Larry E. Dickey
    Glad you figured it out. Those things can be such a pain. It’s amazing how many times our eyes can skip right over something like that.

  10. September 27th, 2009 at 13:57 | #10

    What about using Apache for the front end and passing all the non-php files via proxy to Lighttpd? That way you get the best of both worlds, the mod_rewrite from apache and the speed and low memory footprint of lighttpd

  11. October 19th, 2009 at 12:33 | #11

    Thanks for this. It covered exactly what I needed!

  12. December 12th, 2009 at 13:50 | #12

    For aditional performance, have you tried to tune ZEND_MM_MEM_TYPE and ZEND_MM_SEG_SIZE ?

  13. December 12th, 2009 at 14:24 | #13

    “The newer mod_fcgid cannot be used as it will only send one request at a time to the PHP process, thus multiple requests can’t be handled simultaneously” Where do you get that information?

  14. December 12th, 2009 at 15:13 | #14

    @Walter Cruz
    I experienced the mod_fcgid one request per process myself during testing. There is also some discussion on the mod_fcgid mailing list. There is also some mention of this on the new mod_fcgid documentation on Apache’s website (see the Special PHP considerations section), although this documentation didn’t exist at the time of my post.

  15. December 12th, 2009 at 15:20 | #15

    Thank you for the links.. there was some move on fastcgi code in the last months, maybe they will launch a new version.. in 2010 ;)

  16. January 14th, 2010 at 03:04 | #16

    Hi Brandon,

    thanks a lot for this awesome piece of documentation.
    It allowed me to finally get our PHP-fastcgi setup working 100%.
    There are so many half-assed tutorials out there that end up costing the user more in terms of trouble and grief than they are worth. Incidentally, I followed one of those when I first implemented PHP as a CGI…
    Yours is an outstanding positive example.

    Best Regards,
    Rainer

  17. January 25th, 2010 at 22:24 | #17

    @Rainer
    Thanks! I’m glad to hear it is working for you!

  18. John
    February 6th, 2010 at 07:28 | #18

    Hi Brandon, its a great tutorial and works fine!

    But i found out, that suexec doesnt work properly when using fastcgid instead of fcgid.

    It doesnt really matter, which user and which group I set to own a file or virtual host!

    Usually, i give each VHost another user to protect them from each other. In a fcgid-Environment, it is very important here to set the really rights and Ownership per each file, otherwise suexec will quit its work (as expected and documented).

    But, followed your tutorial and changed from fcgid to fastcgi, the ownership is not asked any more by suexec.
    I can define for one VHost “SuexecUserGroup user1 user1″ and can execute files with the ownership user2/user2 without errors :(

    This is not possible using fcgid, but with fastcgi/suexec.

    Havent you ever checked this out?

    Regards, John!

  19. February 6th, 2010 at 11:31 | #19

    @John
    Hmm. Can you give an example of a file you are executing with a different owner?

    In this post I describe setting up a wrapper around php-cgi. This wrapper is executed by Apache’s suEXEC. I describe the file ownership permissions for this wrapper, and if I deviate from these I get a 500 error response.

    Apache is configured to use the php-cgi wrapper to for all PHP files. In this configuration the wrapper is executed by suEXEC and the actual PHP file is read by php-cgi. This means that if the PHP file is readable by the suEXEC user it will execute, regardless of owner. If this isn’t what you want, set the unix permissions of each PHP file accordingly.

    You mention that you can execute files with a different owner/group then what you define in SuexecUserGroup. I’ve tested this and cannot get this behavior on my system – which is why I ask, what files are you trying to execute?

  20. Jason Williams
    June 20th, 2010 at 17:04 | #20

    Hi Brandon,

    Just wanted to echo the thanks of others here as I now have APC+FastCGI setup as you described, and it’s working a treat.

    I had a few gotcha’s to contend with along the way as is only natural with different flavours of Linux. Now working great under Ubuntu 10.04 LTS.

    Thanks again.

  21. June 28th, 2010 at 21:31 | #21

    Thanks Brandon, was needing this for a small ubuntu server and it’s working as it should.

    It’s worth to mention the fact that I learnt the hard-way (meaning pulling my hair out for a couple of hours) that the ScriptAlias directive on apache .conf had to be commented out in case it exists or else I was having a 404 error to an incorrect cgi path when i clicked on any .php file.

    Thx again.

  22. July 19th, 2010 at 13:20 | #22

    @Brandon
    I know this post was written a while ago. Do you have any updates to add or is this still the defacto method?

    Seems in 2010 this should have been figured out without jumping thru hoops. A shared hosting enviro should be secure and utilize a opcode. Hard to believe there is not an out of the box setup.

    • July 19th, 2010 at 13:29 | #23

      This is still the method I use. On some boxes I run the fastcgi php processes externally via a process watcher such as daemontools, but it’s still the same general idea.

      Typical shared hosting providers oversell which would prohibit them from dedicating the ram needed to support opcode caches per user. I’m sure some companies are doing it, but I can’t imagine it will ever be the “norm”.

  23. July 26th, 2010 at 09:46 | #24

    Excellent article Brandon, Thanks.
    I can wait to read your next article about benchmarks

  24. Eric
    July 28th, 2010 at 13:12 | #25

    Thanks a lot for this tutorial !

    I’ve lost some hours trying to figure why my apc cache was restarted every request (apc.php show me uptime 0 and the start time was always the current time.)

    It was because I wrote “FastCgiConfig …” line after the line “FastCgiWrapper on” in the config …

    Perhaps this tip will help some people ;)

  25. george
    August 27th, 2010 at 07:30 | #26

    Thanks Brandon this is a brilliant article so clear and concise and easy to understand!

  26. Christopher
    September 3rd, 2010 at 08:20 | #27

    Brandom, thanks for this detailed article. I’m wondering if you or anyone has experienced errors with apc? I’m currently getting the following almost continuously when apc is enabled: unable to allocate memory for pool

  27. September 3rd, 2010 at 09:41 | #28

    @Christopher
    I haven’t seen the error messages you’re seeing, but you might have a look at pecl bug #16966.

  28. levin
    November 25th, 2010 at 00:33 | #29

    Hi Brandon, this is a nice article! thanks!!, however I was encountered internal error sometime for my wordpress and horde, do you have any hints for that?

    FastCGI: incomplete headers (0 bytes) received from server

  29. December 22nd, 2010 at 17:44 | #30

    @Brandon Hi Brandon, Thanks for the guide definitely helped me understand the process. My problem is when running ‘apc.php’ It looks like the cache is new on every request(the uptime is 0 minutes). Is this because PHP is terminating after every request? If that is so does that mean that FastCGI is handling the process management instead of PHP? Or is just that PHP is exiting on its own? I am guessing that this is a PHP configuration problem, but I not entirely sure. Any help would be great.

    Thanks,
    Ben

  30. December 23rd, 2010 at 09:10 | #31

    So just a follow up to my last post. The reason PHP was not persisting was because CGI and not FastCGI was being used.

  31. Joe
    February 21st, 2011 at 02:47 | #32

    The best way would be to cache the pages via a cache or accelerator like Varnish. We’ve released a Varnish plugin for cPanel and the performance improvement is even better than any opcode cache. Check it out if interested: http://www.unixy.net/varnish

  32. March 4th, 2011 at 06:39 | #33

    goodness. great article. thanks, really helped with a new vps installation/

  33. Henrique
    September 16th, 2011 at 16:11 | #34

    Hey Brandon, i am having sometrouble, if i have an domain with shared users…

    like http://www.example.com/user1 and http://www.example.com/user2
    I need to have for each user1 and user2 diferentes suexecs, but with this option SuexecUserGroup sue sue

    I can not get it, only works for entire virtualhost.

    I try to use mod_userdir but is simple does nto work with fastcgi or suexec… i am out of ideas

    Do you have any tips?

    Thanks and Great Post

  34. December 14th, 2011 at 10:35 | #35

    @Rimpy
    I know this is old, but it should be noted that SuPHP will not work properly with APC since each request spawns a new php process and APC will only cache for the duration of a process.

  35. Nik
    March 9th, 2012 at 02:54 | #36

    I hope someone is still reading this… I found this article VERY helpful.

    One question, though:

    Unfortunately mod_fcgid will only send one request per child process.

    Is this still accurate? I couldn’t find this info anywhere in the current fcgid docs.

  36. March 9th, 2012 at 09:59 | #37

    @Nik
    As far as I know this is still the case. See http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#examples (see the Special PHP Considerations note).

  37. Nik
    March 9th, 2012 at 14:44 | #38

    I see. Thanks! I missed that.

    Been trying to get this up but I can’t get it to work. I keep getting internal server errors and the like. I think I’m just gonna have to accept that this level of server administration is just not (yet) for me…

    Thanks again for a wonderful article though!

  38. May 8th, 2012 at 12:29 | #39

    Great article, thanks! I found it very helpful and just rolled your recommendations into the mod_fastcgi package in repoforge.

    Best,
    -Bill

  39. Ipo Ima
    July 20th, 2012 at 16:52 | #40

    Hello Brandon,

    thank you for the good article.

    Can you please tell me how did you prevent user access to their cgi-bin directory (/var/www/bin/username)?

    In your setup isn’t it possible for a user to alter the content of the “username” directory (and maybe of the wrapper itself) executing a properly written php script?

    Thank you
    Ipo

  40. November 23rd, 2012 at 15:08 | #41

    Brandon,

    Great article. I recently wrote about my own experience with APC and the (unexpected) gains in memory it provided. I don’t think FastCGI would help on my own site since the static content is hosted somewhere else — so in effect my Apache Httpd only delivers dynamic content (mod_php and mod_perl). I may look into using a front-end though, like nginx to do some caching of the dynamic content. For those readers interested in FastCGI and APC, I linked your article for additional information (see last paragraph at http://surniaulula.com/2012/11/22/save-memory-with-alternative-php-cache-apc/).

    Thanks,

    js.

  41. Ralf Strehle
    December 21st, 2012 at 19:02 | #42

    Hi Brandon,

    after reading https://bugs.php.net/bug.php?id=57825 until the very end it seems that php-fpm (http://php.net/manual/en/install.fpm.php) is now the preferred solution for solving the problem with FastCGI spawning many separate PHP processes per user. What do you think, is the problem solved with php-fpm being part of the PHP 5.3.3 core?

    Thanks
    Ralf

  42. ewwink
    February 4th, 2013 at 12:28 | #43

    its really hard to install fastcgi+suexec+apc, the easiest way is using mod_ruid2+apc

  43. August 26th, 2013 at 17:00 | #44

    Natural ovarian cyst treatment is also inexpensive, unlike surgery, which costs thousands of dollars.
    Polycystic Ovary Syndrome (PCOS) is a ailment in which numerous smaller growths form within
    the ovaries. Other notable things about this book are the seven
    things women need to know about the food they eat to get rid of cysts as well as
    other diseases.

  44. September 14th, 2013 at 17:05 | #45

    Regular daily activities such as riding in the car or folding laundry together can also be excellent times to talk.

    So make sure to brush your teeth before even thinking about oral sex.
    Anna walked for what must have been half a block in search of a cab
    to take her home and though she was not what could be described as.

  45. October 6th, 2013 at 14:26 | #46

    Visualize: Visual information can have a powerful impact on brain and can
    help you memorize details distinctly. Now I happen to think his auditory memory is
    exceptional and in many ways, a much better memory than mine.

    Sometimes forgetting can be a small issue like not remembering
    your associate’s birthday.

  46. October 6th, 2013 at 16:40 | #47

    This is great for letting him go a little deeper than usual.
    The sexologists Masters and Johnson are known for really looking deeply into the average
    American’s sex life. Confidence and swagger both have so
    much to do with how you act in the bedroom.

  47. October 17th, 2013 at 12:43 | #48

    As an example, you can look at joining the neighborhood gym to become a lot more fitter and stronger or
    you might even elect to get involved with active community service.
    If you are unsure what child maintenance is, child maintenance is the United Kingdom’s version of
    American child support. This is what I like to describe as “planting the seed”.

  48. October 17th, 2013 at 14:25 | #49

    Using the equipment will also help you to lose some weight.
    Resting 30-60 seconds will let your muscles regain energy and oxygen to the cells, BUT your body (heart) will stay in an increased performance state using more calories than
    if you were sitting. A basic 15 minutes a few times per
    week is all that is needed to see positive impact.

  49. October 18th, 2013 at 01:52 | #50

    There is always two ends to an issue – a GIVE party and a TAKE
    party. They simply block the tracking device inside a vehicle.

    This is what I like to describe as “planting the seed”.

  50. October 18th, 2013 at 15:09 | #51

    WOW just what I was looking for. Came here by searching for
    carb nite solution free

Comment pages
1 2 3 4
  1. December 28th, 2009 at 11:48 | #1
  2. January 21st, 2010 at 16:11 | #2
  3. August 13th, 2011 at 12:49 | #3
  4. August 31st, 2011 at 07:39 | #4
  5. January 10th, 2012 at 17:23 | #5
  6. May 22nd, 2012 at 22:32 | #6
  7. September 2nd, 2012 at 20:37 | #7
  8. November 16th, 2012 at 14:00 | #8
  9. November 23rd, 2012 at 14:55 | #9
  10. April 27th, 2013 at 22:35 | #10
  11. May 4th, 2013 at 22:18 | #11
  12. June 30th, 2013 at 10:28 | #12
  13. October 2nd, 2013 at 09:38 | #13
  14. May 3rd, 2014 at 06:39 | #14
  15. July 24th, 2014 at 08:41 | #15
  16. July 25th, 2014 at 09:16 | #16
  17. September 22nd, 2014 at 13:13 | #17
  18. September 23rd, 2014 at 15:32 | #18
  19. December 9th, 2014 at 02:49 | #19
  20. January 12th, 2015 at 23:21 | #20
  21. January 31st, 2015 at 09:17 | #21
  22. March 14th, 2015 at 10:19 | #22
  23. August 5th, 2015 at 03:17 | #23
  24. October 14th, 2015 at 10:02 | #24
  25. November 11th, 2015 at 19:40 | #25
  26. July 6th, 2017 at 21:29 | #26
  27. November 24th, 2017 at 13:01 | #27
  28. December 14th, 2017 at 21:16 | #28
  29. July 19th, 2018 at 15:09 | #29