RSS Feeds

More fun with the Webfusion configuration

This is a follow-up to my article on building a Webfusion test VM.  My aim is to create a test environment which reflects my Webfusion environment at a file system organisation and PHP programmatic level.  The Webfusion service itself uses name-based dynamically configured mass virtual hosting that is more complex than the examples in this Apache technical note, and its implementation requires patches to the Apache build.  (See below for more details).  In my case, it is a lot simpler to stick to a standard Debian Apache configuration, with a virtual host for each site to be tested in the /etc/apache2/sites_available directory as in listing 1 below, as this removes the need to add rewrite rules in the <VirtualHost> section and works with an “out of the box” Apache install.  Note that 192.168.1.245 is my static IP address for my VM and this would need updating for another installation.  With this configuration, I now have full access to the error and rewrite logs and can now fully debug my applications locally.

The last thing that I need to do is to set up my D/B account (either in phpMyAdmin or by executing the following from the MySQL root account, with the database name, username and password as appropriate):

   CREATE DATABASE dddddddddddddd   CHARACTER SET utf8;
   CREATE USER    'uuuuuuuuuuuuuu'@'localhost' IDENTIFIED BY 'pppppppppppppp';
   GRANT  ALL ON   dddddddddddddd.* TO 'uuuuuuuuuuuuuu'@'localhost';

And also adding the D/B server name (in my case cust_mysql01) as an alias for localhost in /etc/hosts.

Listing 1 – Apache configuration changes to mirror the Webfusion service

# Change the StartServers,MinSpareServers,MaxSpareServers,MaxClients to 2,1,3,50
sed -i -f - /etc/apache2/apache2.conf <<END
/mpm_prefork_module/,+6 {
  s/\(StartServers\W*\)[0-9]*/\12/
  s/\(MinSpareServers\W*\)[0-9]*/\11/
  s/\(MaxSpareServers\W*\)[0-9]*/\13/
  s/\(MaxClients\W*\)[0-9]*/\150/
}
/ports.conf/s/^/#/
END

# Create VirtualHost configuration for test hosts
cat > /etc/apache2/sites-available/webfusion <<END
Listen 192.168.1.245:80
NameVirtualHost 192.168.1.245:80
<VirtualHost 192.168.1.245:80>
    ServerSignature      On
    UseCanonicalName     Off
    UseCanonicalPhysicalPort Off

    ServerName  ellisons.org.home
    ServerAlias blog.ellisons.org.home test.blog.ellisons.org.home

    AddDefaultCharset ISO-8859-1

    suPHP_Engine on

    DocumentRoot /websites/LinuxPackage02/el/li/so/ellisons.org.uk/public_html

    LogLevel  debug
    LogFormat "02 %{VHOST}e %V %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost
    CustomLog "/var/log/apache2/access.log" vhost

    DirectoryIndex index.html index.php index.htm

    RewriteLog "/var/log/apache2/rewrite.log"
    RewriteLogLevel 6

    Setenv DOCUMENT_ROOT_REAL /websites/LinuxPackage02/el/li/so/ellisons.org.uk/public_html
    RewriteEngine On

    <Directory /websites/LinuxPackage??/??/??/??/*/public_html/>
      AllowOverride All
      Options       SymLinksIfOwnerMatch IncludesNOEXEC Multiviews -Indexes
    </Directory>

    <Files php.ini>
        Order deny,allow
        Deny from all
    </Files>

    RLimitCPU 15
    RLimitNPROC 7
    RLimitMEM 95000000
</VirtualHost>
END

rm /etc/apache2/sites-enabled/000-default
ln -s ../sites-available/webfusion /etc/apache2/sites-enabled/000-webfusion

Some details on the Webfusion implementation

I have merged in the relevant content of the Webfusion Apache configuration into my VM’s Debian-type Apache configuration given above.  The rewrite directives in the Webfusion configuration are perhaps worth a little futher discussion.  These were:

     RewriteMap  wfvhost      prg:mod_rewrite_scripts/wf-rewrite-vhost.pl
     RewriteMap  wfgetbase    prg:mod_rewrite_scripts/wf-rewrite-base.pl

(1A) RewriteCond %{ENV:SSL}   ^1$
(1)  RewriteRule .*   -                 [skip=3]
(2)  RewriteRule ^(/websites/(LinuxPackage\d+|symlinks)/../../../([^/]+)/.*)$ \
                      $1                [E=VHOST:${wfvhost:$3},skip=5]
(3)  RewriteRule ^/websites/(LinuxPackage\d+|symlinks) \
                      x                 [F]
(4)  RewriteRule ^/~([^/_@]+[_@])?([^/]+)(/.*)?$ \
                      ${wfgetbase:$2}$3 [E=VHOST:${wfvhost:$2},skip=3]
(5A) RewriteCond %{HTTP_HOST}  ^$
(5)  RewriteRule .*   -                 [F]
(6)  RewriteRule .*   -                 [E=VHOST:${wfvhost:%{HTTP_HOST}}]
(7)  RewriteRule (.*) ${wfgetbase:%{ENV:VHOST}}$1
(8)  RewriteRule .*   -                 [E=DOCUMENT_ROOT_REAL:${wfgetbase:%{ENV:VHOST}}]

where I’ve removied the comment text and numbered the RewriteRules to make skip calculations easier.  As far as I can see the Webfusion guys have modified the Apache code to use the environment variable DOCUMENT_ROOT_REAL as a way of dynamically initialising DOCUMENT_ROOT.  However, this implementation is unnecessarily inefficient as each cycle can call up to 3 rewrite map functions.  Also not only can the user .htaccess rewrites generate additional rewrite cycles, but also rules (2), (4) and (7) can all trigger another rewrite cycle likewise.  Hence on my initial system test (which was a close copy of the Webfusion setup), my blog rules were generating 18-21 map calls per request. 

Apache implements each prg: map by forking off a child process when the Apache server is started, and the rewriting engine then calls this as an out-of-process function: that is on each map-function lookup Apache sends the input key as a string on a socket connected to the process’s stdin and then reads its returned looked-up value as a string from its stdout.  Hence 20 map requests will generate 40 process context-switches.  However, the two perl scripts referenced in the maps cache previous lookups in a hash, so even though a database query is still required for any cache miss, any subsequent lookups are quite cheap with the main cost is that these are out of process calls. 

However, there should be no need to do more than two calls per request, and most retries can easily be avoided by using the persistent environment variables. (I did a few tweaks to these rules and got this down to 4 map calls per request, but it’s not my job to debug the Webfusion installation.)