How To Speed Up Drupal 7.7 With Boost And nginx (Debian Squeeze) - Page 2

Want to support HowtoForge? Become a subscriber!
 
Submitted by falko (Contact Author) (Forums) on Thu, 2011-08-18 15:36. ::

Finally go to the .HTACCESS tab - here we create the Apache rewrite rules that will tell Apache to check for a cached copy of the requested file (only for anonymous users, authenticated users will always get a fresh copy) in the /var/www/www.example.com/web/cache directory. Again, the default values are ok, so click on Save configuration:

Now click on the .htaccess Generation button, and you should see the Apache rewrite rules that we must add to our .htaccess file (/var/www/www.example.com/web/.htaccess):

These are the rewrite rules that Boost generated for me:

  ### BOOST START ###

  # Allow for alt paths to be set via htaccess rules; allows for cached variants (future mobile support)
  RewriteRule .* - [E=boostpath:normal]

  # Caching for anonymous users
  # Skip boost IF not get request OR uri has wrong dir OR cookie is set OR request came from this server OR https request
  RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [OR]
  RewriteCond %{REQUEST_URI} (^/(admin|cache|misc|modules|sites|system|openid|themes|node/add|comment/reply))|(/(edit|user|user/(login|password|register))$) [OR]
  RewriteCond %{HTTPS} on [OR]
  RewriteCond %{HTTP_COOKIE} DRUPAL_UID
  RewriteRule .* - [S=3]

  # GZIP
  RewriteCond %{HTTP:Accept-encoding} !gzip
  RewriteRule .* - [S=1]
  RewriteCond %{DOCUMENT_ROOT}/cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html -s
  RewriteRule .* cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html [L,T=text/html,E=no-gzip:1]

  # NORMAL
  RewriteCond %{DOCUMENT_ROOT}/cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html -s
  RewriteRule .* cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html [L,T=text/html]

  ### BOOST END ###

The interesting part is the RewriteCond %{HTTP_COOKIE} DRUPAL_UID line. Boost sets a cookie named DRUPAL_UID for all logged in users - if this cookie is set, the user will not get cached content. This makes sure that only anonymous users get cached content.

Boost also tells you where exactly you have to place these in the .htaccess file:

Copy this into your .htaccess file below

  # If your site is running in a VirtualDocumentRoot at http://example.com/,
  # uncomment the following line:
  # RewriteBase /

and above

  # Pass all requests not referring directly to files in the filesystem to
  # index.php. Clean URLs are handled in drupal_environment_initialize().

Open your .htaccess file:

vi /var/www/www.example.com/web/.htaccess

First we comment out the <IfModule mod_expires.c>...</IfModule> section because we don't want browsers to cache our content in addition to our file cache because otherwise you lose control over what the visitor actually sees. Instead, we add some headers that tell browsers to never cache our content:

[...]
##<IfModule mod_expires.c>
##  # Enable expirations.
##  ExpiresActive On
##
##  # Cache all files for 2 weeks after access (A).
##  ExpiresDefault A1209600
##
##  <FilesMatch \.php$>
##    # Do not allow PHP scripts to be cached unless they explicitly send cache
##    # headers themselves. Otherwise all scripts would have to overwrite the
##    # headers set by mod_expires if they want another caching behavior. This may
##    # fail if an error occurs early in the bootstrap process, and it may cause
##    # problems if a non-Drupal PHP file is installed in a subdirectory.
##    ExpiresActive Off
##  </FilesMatch>
##</IfModule>

<IfModule mod_headers.c>
  Header set Expires "Sun, 19 Nov 1978 05:00:00 GMT"
  Header set Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
</IfModule>
[...]

(It is ok to make browsers cache static files such as images, Javascript, css, etc. - take a look at Make Browsers Cache Static Files With mod_expires On Apache2 (Debian Squeeze) to find out how to do this - but you should not allow to cache HTML!)

Further down in the .htaccess file, there are two (currently commented out) rewrite rules that either redirect your users to your www. prefixed site (e.g. example.com will be redirected to www.example.com) or the other way round (www.example.com will be redirected to example.com). You should use one of these rules because otherwise Boost will create two copies of each cached page, one for www.example.com and one for example.com which makes your cache far less effective.

[...]
  # If your site can be accessed both with and without the 'www.' prefix, you
  # can use one of the following settings to redirect users to your preferred
  # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  #
  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  #
  # To redirect all users to access the site WITHOUT the 'www.' prefix,
  # (http://www.example.com/... will be redirected to http://example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  # RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301]
[...]

Finally, we add the Boost rewrite rules below RewriteBase / and above RewriteCond %{REQUEST_FILENAME} !-f:

[...]
  # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
  # VirtualDocumentRoot and the rewrite rules are not working properly.
  # For example if your site is at http://example.com/drupal uncomment and
  # modify the following line:
  # RewriteBase /drupal
  #
  # If your site is running in a VirtualDocumentRoot at http://example.com/,
  # uncomment the following line:
  # RewriteBase /

  ### BOOST START ###

  # Allow for alt paths to be set via htaccess rules; allows for cached variants (future mobile support)
  RewriteRule .* - [E=boostpath:normal]

  # Caching for anonymous users
  # Skip boost IF not get request OR uri has wrong dir OR cookie is set OR request came from this server OR https request
  RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [OR]
  RewriteCond %{REQUEST_URI} (^/(admin|cache|misc|modules|sites|system|openid|themes|node/add|comment/reply))|(/(edit|user|user/(login|password|register))$) [OR]
  RewriteCond %{HTTPS} on [OR]
  RewriteCond %{HTTP_COOKIE} DRUPAL_UID
  RewriteRule .* - [S=3]

  # GZIP
  RewriteCond %{HTTP:Accept-encoding} !gzip
  RewriteRule .* - [S=1]
  RewriteCond %{DOCUMENT_ROOT}/cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html -s
  RewriteRule .* cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html [L,T=text/html,E=no-gzip:1]

  # NORMAL
  RewriteCond %{DOCUMENT_ROOT}/cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html -s
  RewriteRule .* cache/%{ENV:boostpath}/%{HTTP_HOST}%{REQUEST_URI}_%{QUERY_STRING}\.html [L,T=text/html]

  ### BOOST END ###

  # Pass all requests not referring directly to files in the filesystem to
  # index.php. Clean URLs are handled in drupal_environment_initialize().
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteRule ^ index.php [L]
[...]

Finally, we must disable Drupal's built-in cache under Home > Administration > Configuration > Development > Performance (otherwise it will be difficutl to predict what users see when you use two caches):

Now we need to make changes in two Drupal files to make sure that user logins and logouts work reliably with Boost. First open /var/www/www.example.com/web/modules/user/user.module:

vi /var/www/www.example.com/web/modules/user/user.module

In the function user_authenticate($name, $password), please add the following lines in lines 2191 - 2193 to make sure that the DRUPAL_UID cookie gets set when a user logs in:

[...]
function user_authenticate($name, $password) {
  $uid = FALSE;
  if (!empty($name) && !empty($password)) {
    $account = user_load_by_name($name);
    if ($account) {
      // Allow alternate password hashing schemes.
      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
      if (user_check_password($password, $account)) {
        // Successful authentication.
        $uid = $account->uid;

        if ($uid && !isset($_COOKIE['DRUPAL_UID'])) {
           setcookie('DRUPAL_UID', $uid, $_SERVER['REQUEST_TIME'] + ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'));
        }

        // Update user to new password scheme if needed.
        if (user_needs_new_hash($account)) {
          user_save($account, array('pass' => $password));
        }
      }
    }
  }
  return $uid;
}
[...]

Then open /var/www/www.example.com/web/sites/all/modules/boost/boost.module:

vi /var/www/www.example.com/web/sites/all/modules/boost/boost.module

Comment out line 544 and add line 545 in the boost_set_cookie($uid, $expires = NULL) function to make sure that the DRUPAL_UID cookie is deleted when a user logs out:

[...]
function boost_set_cookie($uid, $expires = NULL) {
  if (!$expires) {
    $expires = ini_get('session.cookie_lifetime');
    $expires = (!empty($expires) && is_numeric($expires)) ? REQUEST_TIME + (int)$expires : 0;
    setcookie(BOOST_COOKIE, strval($uid), $expires, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure') == '1');
  }
  else {
    //setcookie(BOOST_COOKIE, '0', $expires, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure') == '1');
    setcookie(BOOST_COOKIE, '', $expires, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure') == '1');
  }
}
[...]

That's it. Now after the first anonymous users have visited your site, you should see your cache directory fill:

ls -l /var/www/www.example.com/web/cache/normal/www.example.com/

root@server1:~# ls -l /var/www/www.example.com/web/cache/normal/www.example.com/
total 36
-rw-rw-r-- 1 www-data www-data 11465 Aug 10 11:59 _.html
-rw-rw-r-- 1 www-data www-data  9619 Aug 10 11:59 nginx-413-request-entity-too-large_.html
-rw-rw-r-- 1 www-data www-data  9628 Aug 10 12:00 postfix-mail-loops-back-to-myself_.html
root@server1:~#

Browse your site as an anonymous user and take a look at the source code. For pages that are served from the cache, you should see a comment at the end of the source code saying <!-- Page cached by Boost -->.

You should test if users can log in and out without problems. With the changes made in the user.module and boost.module files, this should work without problems.

Drupal's cron will take care of cleaning up the cache directory, i.e., if you have told Boost to cache for one hour, cached files older than one hour will be deleted from the cache. Also, if you update your site (insert or update a page or add a comment), the cache will be cleaned as well to make sure users don't see outdated content.

You can now use a tool like Apache Benchmark (ab) to test your site's performance, and you should see that it is able to handle much more requests per second than before.


Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.