February
27th, 2008
Speed up Apache - how I went from F to A in YSlow
I decided to embark on figuring out how to make my site as fast as possible. There were a few tips I was already aware of but decided to grade myself using YSlow. My initial score was bad, an F. I realized I had to do a few things.
- Compress text/* files using gzip
- Decrease HTTP requests by combining multiple JavaScript (and CSS) files into single files
- Add aggressive caching since the site isn’t updated very often (especially images, JavaScript and CSS files)
Here’s what my original scores looked like.



Making fewer HTTP requests
In order to make fewer HTTP requests I knew that I had to combine my 3 CSS files into one as well as my 7 JavaScript files. I decided to use a little bit of Apache’s mod_rewrite magic. I set up a rewrite rule for any file which didn’t exist inside my js directory. The rule looks like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\?*$ compress.php?__args__=$1 [L,QSA]
This let’s me have a script tag that looks like this.
<script src="file1.js|file2.js|file3.js"></script>
I have a php file named compress.php which takes the file names in the query string and concatenates them together. That file looks like this.
ini_set('include_path', '.');
header('Content-Type: text/javascript');
if(!empty($_GET['__args__']))
{
$files = (array)explode('|',$_GET['__args__']);
foreach($files as $file)
{
if(file_exists(dirname($_SERVER['SCRIPT_FILENAME']) . '/' . $file) && strstr($file, '..') === false)
{
readfile($file);
echo "\n";
}
}
}
I did the exact same thing for CSS files so I won’t go into great detail with that.
Adding expire tags to the HTTP headers
The next step was to add expires headers to the response. I originally thought about doing it with PHP but decided that it would be a much better idea to do it using Apache. I am not going to go into the details of caching (maybe another post someday). I decided to add expiration headers by file type. This can be done using Apache by using mod_expires. You can turn this on in your httpd.conf file by searching for mod_expires and making sure it’s commented out. Once that’s done you can add the following to your configuration files. I did mine inside of my VirtualHost block.
ExpiresActive On ExpiresByType text/html "A7200" ExpiresByType text/javascript "A604800" ExpiresByType text/css "A604800" ExpiresByType image/x-icon "A31536000" ExpiresByType image/gif "A604800" ExpiresByType image/jpg "A604800" ExpiresByType image/jpeg "A604800" ExpiresByType image/png "A604800" Header set Cache-Control "must-revalidate"
You first have to Enable the module and then you can specify when you want specific file types to expire. The syntax for the 2nd parameter is [A|M]seconds. So A3600 would mean one hour since it was last accessed and M60 would mean one minute since it was last modified. I also added the must-revalidate cache control so that all browsers and proxies let me specify exactly how my site handles caching.
Compressing files (text/*)
This one was easy. I suggest using Apache’s mod_deflate or mod_gzip to do this but I was getting lazy and decided to do it with PHP. It was a one liner for me and I only had to add it in one spot for my entire site to obey it. Doing this also took care of minifying JS listed as #10.
ob_start('ob_gzhandler');
Configuring ETags
I had no idea what ETags were so I had to look them up. ETags are server generated ids for each object. The nice thing about this is that it can be updated programatically to let the browser or proxy know that a new file is available. I decided to have apache handle this for all requests and base it off of the modification time and the file size. I added the following immediately below the cache configurations in my VirtualHost block.
FileETag MTime Size
The results…
The results were pretty good. I can do some more tweaking but a few of the remaining issued are due to my usage of Google Analytics and the Photagious API. My final score was an A (92).


![]()

February 27th, 2008 at 10:29 am
You should check into PHP Speedy. It consolodates your js and css calls as well as compress and minifys them. All on the fly.
http://aciddrop.com/php-speedy/
February 27th, 2008 at 1:00 pm
There is a very excellent script that does something similar: http://rakaz.nl/item/make_your_pages_load_faster_by_combining_and_compressing_javascript_and_css_files
February 28th, 2008 at 4:41 pm
@louis & Ozh,
Both of those seem to be pretty good scripts. It would be cool to look under the hood and see if they do anything really clever. Hopefully this article helps people understand the core concepts of speeding up a site.
March 2nd, 2008 at 8:02 am
Thanks, very good.
I posted a link at http://www.apachelounge.com/forum/viewtopic.php?p=10207
Steffen
March 2nd, 2008 at 8:05 am
Sorry wrong link
http://www.apachelounge.com/forum/viewtopic.php?p=10210
March 2nd, 2008 at 1:51 pm
You still need to minify your javascript files for better gzip compression(Because minified javascript compresses even better). Test it out with stats from Yslow and you get a B for #10 and not an A. For the rest nice article.
March 2nd, 2008 at 5:13 pm
@Alfred. Unfortunately the JS files that YSlow complains about are 3rd party JavaScript files. One being for Google Analytics and the other being for the Photagious API.
March 2nd, 2008 at 5:14 pm
@Steffen, thanks for linking to the article.
November 26th, 2008 at 6:24 pm
hey jaisen,
I have pretty good experiences with minify [http://code.google.com/p/minify/].
It groups js and css files, minifies them, handles the gzip and the corresponding headers. You can also define dynamic groups and don’t have to worry about users using outdated scripts. The dynamic group checks for the last modification date of every single file in your groups and creates a timestamp-path.
It is very easy to install / use too.
November 27th, 2008 at 2:51 am
@Leonie, Very cool. I’ll definitely give that a try. Thanks for sharing.