Posts Tagged ‘apache’

Log PHP memory usage per-request

Tuesday, January 12th, 2010

You can easily log how much memory each request for a PHP page takes by modifying the LogFormat:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b %{mod_php_memory_usage}n \"%{Referer}i\" \"%{User-Agent}i\"" combined-php

Note the latter definition, which includes %{mod_php_memory_usage}n — this will print out the amount of memory, in bytes, required to execute the script as requested. Big help in finding memory leaks. To use, just change the log definition to the newly-created "combined-php" format:

CustomLog logs/fever-access_log combined-php

Do note that this may (probably will) break Apache log parsers that are expecting the standard combined format. If using for troubleshooting, I recommend logging to an alternate location so as to not screw up log statistics.

Credit to Brad Ison for this find

Block POSTs from blank referrers

Thursday, December 31st, 2009

I found a great article on Secure Computing: Sec-C that includes some excellent, simple Apache configurations and RewriteRules to blog various annoyances and compromises. A wonderful example is this bit, designed to stop POST requests that have no referrer set. There's no reason for anyone to be trying to post arbitrary data to a script to not have a referrer, as that would indicate a direct hit — which is bad juju.

# Identify if a Referer is used
SetEnvIf Referer "^$" no_referer=1
<Limit POST>
Order Allow,Deny
Allow from all
Deny from env=no_referer
</Limit>

Lots of other fascinating security and forensics insights on the Sec-C blog as well!

Push email on iPhone and other smartphones… without Exchange

Friday, November 20th, 2009

Tonight, I found a clever open-source project entitled Z-Push. This small collection of PHP sits in a web directory and responds to ActiveSync queries — the protocol used for Exchange. It then checks and delivers email.

This is useful because of the limitations of some smartphones — such as the iPhone — wherein Exchange-hosted mail is delivered instantly, while standard POP3 or IMAP mail accounts suffer a long polling delay.

On the server side, configuration is fairly simple:

  1. wget http://download.berlios.de/z-push/z-push-1.3RC.tar.gz
  2. tar xzvf z-push-1.3RC.tar.gz
  3. mv z-push /var/www/html
  4. yum install php-imap
  5. chown apache:apache /var/www/html/z-push/state
  6. vi /var/www/html/z-push/config.php and configure the following:
  7. $BACKEND_PROVIDER = “BackendIMAP”;
    define(’IMAP_SERVER’, ‘localhost’);
    define(’IMAP_PORT’, 143);
    define(’IMAP_OPTIONS’, ‘/notls/norsh’);

  8. Add the following Alias to an Apache SSL VirtualHost:
  9. Alias /Microsoft-Server-ActiveSync /var/www/html/z-push/index.php

  10. Restart Apache

On your phone, simply create a new Exchange-type account that points to your server as if it was an Exchange server. Send a test mail and marvel at how fast it appears on your phone! Tested on iPhone and Motorola Droid with excellent success.

Enable WebDAV with Plesk

Friday, September 25th, 2009

Configuring WebDAV in Apache is simple, but it's even easier to configure and manage with Plesk!

1. Create a Protected Directory
Log into Plesk and select the domain that is to receive the DAV repository. Click on "Protected Directories" and create a new one – name it as the DAV share will be named, for they are one and the same.

2. Configure WebDAV Users
Add users who should have access to this DAV repo.

3. Edit vhost.conf and Reconfigure Plesk
On the server, edit the domain's vhost.conf and enter the following:

<Directory "/var/www/vhosts/domain.com/httpdocs/DAVdir">
DAV on
AllowOverride None
</Directory>

Regenerate Apache's configuration and you're golden:

/usr/local/psa/admin/bin/websrvmng -av

4. Test
You can easily test DAV configuration by using a DAV client such as `cadaver'.

[kale@superhappykittymeow ~]$ cadaver http://www.domain.com/DAVdir
Authentication required for on server `domain.com':
Username: kale
Password:
dav:/DAVDir/> ls
Listing collection `/DAVDir/': collection is empty.

Success! You can manage access to the DAV share through the Plesk interface.

mod_auth_mysql and segfaults

Sunday, August 30th, 2009

Symptom: seemingly random PHP scripts are causing Apache to segfault.

Looking deeper: all the PHP scripts that are causing segfaults make database queries (specifically, MySQL).

Look even closer: the following line is in your Apache configuration:

LoadModule auth_mod_mysql modules/mod_auth_mysql.so

Solution: comment that line out of your Apache configuration and restart Apache.

Why: If the PHP code is run through Apache, you've essentially got one process making the SQL queries (if your PHP code makes it so). However, while your code made the connection and is expecting responses and whatnot, Apache, with mod_auth_mysql loaded, is ready and willing to make and take database connections. When a connection that returns a response is made from your PHP code, Apache will attempt to accept the response and handle it itself, instead of passing it to PHP. Since Apache is not expecting the data it's getting, it has no error handling code for this situation and simply segfaults.

Disable mod_auth_mysql by commenting it out and everything will work without issue.

Apache MultiViews and RewriteRules

Sunday, August 30th, 2009

Don't work together.

I think it's a bug in mod_rewrite, to be honest, though more of a "not thinking these two modules would ever be used together" kind of oversight, rather than a full bug.

Essentially, if you are using MultiViews to make for pretty URLs (say, http://www.foo.com/bar, where 'bar' doesn't exist, but instead loads the content from bar.php), and you attempt to implement RewriteRules to modify the URL, you will see erratic results.

If, for example, you have a RewriteRule as follows:

RewriteCond %{HTTP_HOST} !^www\.foo\.com
RewriteRule (.*) http://www.foo.com/$1 [R=301,L]

which, essentially, takes all non-WWW requests and makes them www.foo.com, you will find that MultiView URLs will be redirected to their real resources if the URL matches a rule. For example,

http://foo.com/bar

will become

http://www.foo.com/bar.php

after going through the MultiView filter and the RewriteRules. This is due to the way the rules work — essentially, the request will be parsed through mod_rewrite to find a match. If no match against the URL, the MultiView is processed to get the real resource which is then presented to the end user. If a match is made, however, mod_rewrite has mod_negotiation process the MultiView to find the real resource so it can properly do the rewrite — it is never changed back, however, to the pretty MultiView URL. If your goal is pretty URLs without any effort expended, relying on MultiView, you will find that RewriteRules are your nemesis.

There are a few routes available to get around this odd behavior, but my favorite (and easiest to implement) is to move the RewriteRule logic to the site code. It's much harder to implement MultiView-esque functionality than it is to re-implement RewriteRules.

To implement the above RewriteRule, redirecting non-www to www, simply add an auto_prepend_file to your .htaccess in lieu of the RewriteRule as such:

php_value auto_prepend_file "/var/www/html/prepend.php"

This file contains simply:

<?
if ( !( preg_match('/^www/', $_SERVER['SERVER_NAME']) ) ) {
    header("Location: http://www.$_SERVER[SERVER_NAME]$_SERVER[REQUEST_URI]");
    }
?>

With this code prepended to every PHP script (assuming your site is written in PHP, of course), all non-www requests will be redirected to www — *after* the MultiView is processed and not interfering with its inner workings.

Enable core dumps with apache, RHEL5

Thursday, July 23rd, 2009

From this post on Jared's tech blog:

echo "ulimit -c unlimited >/dev/null 2>&1″ >> /etc/profile
echo "DAEMON_COREFILE_LIMIT='unlimited'" >> /etc/sysconfig/init
echo 1 > /proc/sys/fs/suid_dumpable
echo "core.%p" > /proc/sys/kernel/core_pattern
echo "CoreDumpDirectory /var/apache-core-dumps" > \
/etc/httpd/conf.d/core_dumps.conf
mkdir /var/apache-core-dumps
chown apache: /var/apache-core-dumps
source /etc/profile
/etc/init.d/httpd restart

Now you can test it by sending a SIGSEGV to a random apache child process:

tail -f /var/log/httpd/error_log | grep -i seg &
ps auxwww |grep httpd (pick a random pid not owned by root)
kill -11 2014
[Mon Jul 06 21:05:39 2009] [notice] child pid 2014 exit signal
Segmentation fault (11), possible coredump in /var/apache-core-dumps
cd /var/apache-core-dumps
ls
core.2014

You can then get a backtrace using gdb:

gdb /usr/sbin/httpd core.2014
(gdb) > bt full

Brilliant -- thanks Jared, I fought Apache for an hour to enable CoreDumps before putting my fist through the monitor!

Installing mod_fastcgi on RHEL4/5

Friday, April 10th, 2009

http://rugmonster.org/2009/03/building-mod_fastcgi-on-rhel5/

Who's connecting to Apache?

Saturday, March 28th, 2009

Spot DDoS's and the like quickly:

netstat -plan | grep :80 | awk '{print $5}' | sed 's/:.*$//' | sort | uniq -c | sort -rn |head

What is Apache doing?

Monday, March 9th, 2009

Ever wish you knew what Apache was working on at any given moment, but kicking yourself because you forgot to enable a server-status directive? This snippet will help you diagnose timeouts and long-running scripts (for bad coders like myself):

for i in `ps -elf |grep http|awk '{print $4}'|sort|uniq`; do ls -la /proc/$i/cwd ; done|awk '{print $11}'|sort|uniq -c |sort -nr

Practical awk (for Apache logs)

Wednesday, March 4th, 2009

Who is hotlinking?

awk -F\" '($2 ~ /\.(jpg|gif)/ &amp;&amp; $4 !~ /^http:\/\/www\.yourdomain\.com/){print $4}' access_log.processed \
| sort | uniq -c | sort

Blank referrers (usually indicates direct hits, such as a user typing in yourdomain.com, or a script):

awk -F\" '($6 ~ /^-?$/)' access_log.processed | awk '{print $1}' | sort | uniq

How many different IPs visited on a specific day (and how often they visited):

grep '12/Dec/2008′ access_log.processed | \
  awk '{cnt[$1]++;} END{for (ip in cnt){printf("%-15s visited: %04d time(s).\n", ip, cnt[ip])}}'

Amount of data transferred for a specific date:

grep '12/Dec/2008′ access_log.processed | awk '{ SUM += $10} END { print SUM/1024/1024 }'