Server Setup Checklist

A collection of things to do/check when setting up a server.

Some of these (e.g. "A Little PHP Security") are only applicable on a shared host.

 

Check/fix your RSS feed title

Drupal assumes you have a site slogan, and will give your RSS feed a title of "SITENAME -" if you don't. Here is how to fix that:
Written in WikklyText.

Easy Drupal + FeedBurner integration

I can't take credit for this one, just a satisfied user: Drupal and FeedBurner shows you how to easily hook your Drupal RSS feed into FeedBurner.

Quick summary (see link above for details): I have Drupal configured as described here: Having Drupal live in a subdirectory. I was able to just add the above lines to the end of my existing .htaccess.

All existing subscribers will be transparently sent to feedburner, as will new subscribers. This redirection magic is really nice if you ever stop using feedburner — just remove the lines from .htaccess, and the feed is back on your site.

Written in WikklyText.

Having Drupal live in a subdirectory

The easiest way to install Drupal is to have it live in the root of your webserver. However, I don't like doing that, because I have other top-level directories under my webroot, and I don't want to clutter up the root with the Drupal files. Having Drupal in a subdirectory makes maintenance a lot easier (IMO, of course).

For reference, my webserver is set up like this:

I have to do three things to set it up the way I want:

  1. Redirect visitors from http://boodebr.org to http://boodebr.org/main
  2. Tell Drupal that it is living under "/main" and not under "/"
  3. Tweak the Apache httpd.conf so that URL rewriting will work under the VirtualHost.

Since Drupal will live in "/main", the first thing I want to do is redirect visitors from "http://boodebr.org", to "http://boodebr.org/main". While it's possible to do this with a short "index.html" file, it is faster to do it with mod_rewrite. This also makes the redirection invisible to the end user which gives a nicer frontpage URL. To do this, I create a file ".htaccess" located in /var/htdocs/boodebr:

# this redirects "/" to "/main" (while maintaining the original URL),
# (Drupal still adds the '/main' back in when you click on a topic,
# but having a clean frontpage URL is my main concern here.)

RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST} boodebr.org
# don't rewrite if it's already /main
RewriteCond %{REQUEST_URI} !main/
# don't rewrite requests for /javascript
RewriteCond %{REQUEST_URI} !javascript

# if it satisfies those conditions, here's the rewrite rule
RewriteRule ^(.*)$ http://boodebr.org/main/$1

 

Note that I had to add a rule to ignore a toplevel directory (/javascript) that shouldn't be rewritten. There may be a more generic way to do this, but I'm new to mod_rewrite.

The second thing that I need to do is modify the .htacess file that lives in the Drupal root (/var/htdocs/boodebr/main/.htaccess, in my case). Uncomment and edit the 'RewriteBase' line, for example:

  # Modify the RewriteBase if you are using Drupal in a subdirectory and
# the rewrite rules are not working properly.
RewriteBase /main

In the Apache httpd.conf file, my VirtualHost looks like:


<VirtualHost *>
ServerName boodebr.org
ServerAlias www.boodebr.org
DocumentRoot /www/htdocs/boodebr
</VirtualHost>

This is fine, but I need to add a <Directory> container above it (not sure if ordering matters) to make URL rewriting work for my VirtualHost. I added the following directive immediately before the <VirtualHost> container:


<Directory "/www/htdocs/boodebr">
AllowOverride All
<Directory>

After those modifications, URL rewriting works perfectly under Drupal. To turn it on, simply go into Settings->General Settings, run the "Clean URL test" (which should now work OK), and Enable clean URLs.

Password-protecting directories

Create a file named .htaccess in the directory you want to protect. For example, assuming that the directory is named /var/www/secret:

AuthUserFile "/var/www/secret/.htpasswd"
AuthGroupFile /dev/null
AuthName "My Secret Directory"
AuthType Basic
Require valid-user

Give one or more users access to the directory. For example, to create a user named "admin":

htpasswd -c /var/www/secret/.htpasswd admin

(The "-c" assumes that .htpasswd doesn't exist yet.)

htpasswd will prompt you for the password.

Your directory is now password protected (through the webserver, at least).

Supposedly, you can put these same statements inside a <Directory> container in your httpd.conf file, but I was unable to get that to work.

drupal.notify & emailing unpublished comments

Updated Mar 13, 2007 to add instructions for Drupal 5.x.

The notify module (Drupal) is supposed to let you know via email when new content and/or new comments are available on your site. This is good from an adminstrators viewpoint since you don't need to periodically scan your logs to see if anything new has been submitted.

However, there is one problem I'm having with it: It won't notify you of unpublished comments. So if an anonymous user posts a comment, and it goes into the approval queue, you will not get an email notification. Coming from Wordpress, I see this as a big problem since Wordpress would notify you of comments that were awaiting approval. The only workaround seems to be to give all users (including anonymous users) the right to publish comments without approval. That was definitely not what I wanted.

Luckily, I was able to make a minimal patch to notify that seems to do the trick. I'm not going to post a diff, since the frequent CVS drops of notify would make it obsolete, however here is the method to patch it yourself:

Drupal 4.x:
  1. Open notify.inc, and find the function _notify_send()
  2. Locate the comment about 20 lines down that says
       
    <span style="font-family: courier new,courier; 
            font-weight: bold">// Fetch new comments
  3. In the SELECT statement under this, you should see that one of the WHERE conditions is c.status = 0 (or possibly c.status = %d, with a parameter of COMMENT_PUBLISHED). Modify the WHERE clause to remove the c.status check (I'm assuming you have a minimal amount of PHP know-how here).

Drupal 5.x:
  1. Open notify.module, and find the function _notify_send() (around line 320)
  2. Locate the code about 20 lines down:
    // Fetch new comments
    $cresult = db_query(db_rewrite_sql('SELECT c.nid,
           c.cid, c.subject, c.name FROM {comments} ...
  3. In the SELECT statement, you should see that one of the WHERE conditions is c.status = %d, with a parameter of COMMENT_PUBLISHED. Modify the WHERE clause to remove the text c.status = %d AND, and delete the text COMMENT_PUBLISHED, from the list that follows. (I'm assuming you have a minimal amount of PHP know-how here).

You should now receive notification emails for both published and unpublished comments. For that matter, if you didn't care about published comments, you could modify the same statement to only select non-published comments.

One trick is that you need to be logged in to your site already as an administrator (or anyone who can administer comments) so that the email link will take you straight to the comment that needs approval. Otherwise, the unpublished comments won't show up.
Written in WikklyText.

Drupal site not talking to pingomatic ... fixed!

Urgh ... boodebr.org wasn't talking to pingomatic, leaving me effectively "off the air" for the last couple of weeks. I had assumed that the point & click magic of Drupal was doing its thing and never checked till today, when I noticed that technorati hadn't updated me in a while.

Turned out that the problem was (obviously) that I didn't have a site slogan!! Surprised

There is a check in the ping module, in the function "ping_cron()":

 

if (variable_get('site_name', 0) && variable_get('site_slogan', 0))

 

In other words, if you don't have a site name and/or slogan, then it will never ping pingomatic. I don't see why a site must have a slogan ... but anyways, removing the check made ping happy and I'm back on the air Smile

Preventing snooping with .htaccess

When a visitor goes to your site, say http://www.example.com/foo, if the webserver doesn't find a file like "index.html", "index.php", etc. in "foo", it will by default let the visitor browse your directory tree. Personally, I think that this should be OFF by default, and only enabled if you really want people to freely browse your files. But, it is easy to turn off. All you have to do is place the following line in your .htaccess file:

Options -Indexes

If you place this in the .htaccess at the root directory of your site, it will automatically apply to all directories underneath. Then, if there are directories you want people to browse, you can enable them by placing an .htaccess in the particular directory with:

Options +Indexes

If you only want to block access to certain files, you can do that with:

IndexIgnore *.php *~

(This example blocks the listing of .php and *~ [backup] files.)

I was a little surprised to find that my webhost didn't set "Options -Index" by default, so it's a good thing to check.

A little PHP security

PHP logoI've been picking up a few things about securely running PHP apps while getting the site up and running. I am by no means a PHP security expert, but I thought I'd write down the things I've found out so far so I can find them again when I forget. The first big thing that bothered me was that I had to make all my files world-readable to get anything to work. This bugged me, so I searched around a while for a better way to do it.

On my webhost, PHP scripts are (by default) run with the Apache module mod_php. I imagine most shared hosting services have the same setup. Although mod_php has many benefits (speed, memory usage, resource sharing), it has some security implications on a shared server. Many PHP+MySQL applications (phpMyAdmin, Wordpress, etc.) will have a file where your MySQL database password is stored (this file is generally called "config.php", or similar). When using mod_php, your PHP application will run under the user id of the Apache server (usually an unprivileged user id). One effect of this is that you are forced to make all of the files that the PHP application needs to access world-readable (readable by any other user on the webhost). Even worse, if the PHP application needs to write any data, then you have to make those files/directories world-writable. Try running "ls ~/.." on your webserver sometime and you will see there are likely dozens of other accounts on the same machine as you. Once you make all of your files world-readable, any one of those users (and anyone they have given FTP access to) can chdir into your directory, read your config.inc.php files, and get all of your MySQL passwords. In the case of a world-writable directory, someone could use your space to set up their own MP3 file-swapping area. Do you trust the random people sharing the server with you? I sure don't.

Fortunately, there is a way around this. Instead of running your PHP scripts with mod_php, decent webhosts will allow you to run via cgiwrap (or equivalent - something like php4-cgiwrap, or suphp - check your webhost for site-specific details). When using cgiwrap, the PHP application will run under your user id, so you can remove all other file permissions from sensitive files. You probably do not want to just do a "chmod -R go-rwx" on your entire site, however, since there are likely non-PHP files that still need to be world-readable (images, style sheets, etc.). I just do "chmod go-rwx" on the specific files that have sensitive information in them (like config.inc.php).

Running scripts under your own user id isn't without its own set of security risks. If someone were to compromise your site (via a bug in a PHP script for example), they would have full access to read/change/delete all of your files, since they would be running as "you". When running under mod_php (as an unprivileged user), they would only be able to use whatever "world" permissions your have granted. It's definitely a tradeoff and you have to decide which is more appropriate for your site. For example, when running a stable/mature application, the CGI method may be better for security since you can lockdown all files and run under your user id. With a new application you might want to run under mod_php until you are fairly sure there are no security bugs in the application itself.

Note that running via CGI will incur a performance penalty compared to mod_php. There are solutions like fastcgi that can greatly improve performance, however I am not aware of any CGI-accelerators that also support running under your own user id. If your site gets enough traffic that CGI becomes a serious problem, you can likely justify moving to a dedicated server or VPS where you can safely make files world-readable (since there will be no other users on the system) and run mod_php.

Either way you go, it makes sense to me to prepare for the worst (i.e. expect to have your site hacked sooner or later), and take steps such as keeping daily backups of your site and databases. I personally wouldn't keep any data on a webhost that I would care too much if anyone saw. For sites that need to process confidential data, credit card numbers, etc., obviously much more is required beyond these simple steps.