Moving WordPress to a New URL and New Permalink Structure

When I decided to change the permalink structure and move my WordPress blog from raamdev.com to raamdev.com/blog/, I knew it was going to be a delicate process. I have over a thousand posts, more than three hundred of which have been indexed by Google. A huge portion of my traffic comes from Google, so my biggest concern was that the old URLs redirect to the new location.

Step 1: Disable plugins

It's a good idea to disable your plugins before making these changes. At the very least, if you have a caching plugin installed (such as WP Super Cache), delete the cache and then disable that plugin.

Step 2: Change the blog URL

First, I had to change the WordPress blog URL from raamdev.com to raamdev.com/blog/. This is simply a matter of updating the "WordPress address" and "Blog address" options from within the WordPress Administration panel (Settings -> General).

Second, I wanted the final URL to be raamdev.com/, instead of raamdev.com/blog/. To do this, I first changed the "Blog address" to raamdev.com/. Now to get WordPress working on the web root (raamdev.com/), I had to move /blog/index.php to the web root (/index.php) and then edit index.php and change this line,

require('./wp-blog-header.php');

to this,

require('./blog/wp-blog-header.php');

Now, when index.php is loaded, it knows to look for all the WordPress files in /blog/ and since WordPress has been configured to use raamdev.com/ as the "Blog address", it will automatically handle everything else.

Step 3: Redirect old URLs to the new URL

The blog. sub-domain maps to a directory in the web root called /blog/. If someone visits a link to a page that includes the sub-domain, the web server needs to tell the browser the new location. To do this, I needed to recreate the /blog/ directory and add the following to an .htaccess file:

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTP_HOST} ^raamdev.com$ [NC]
RewriteRule ^(.*)$ https://raamdev.com/wordpress/blog/$1 [R=301,L]

Now, if someone tries to visit https://raamdev.com/2010/01/28/some-blog-post, the web server will do a 301 redirect to https://raamdev.com/wordpress/blog/2010/01/28/some-blog-post.

What's a 301 redirect? Well, when you move a web page from one location to another, you can specify the type of redirection. A 301 redirect means the web page has been moved permanently. This is useful for keeping indexes updated. For example, if someone searches Google and finds an old link, Google will detect the 301 redirect and update its index with the new URL, thereby keeping your URL's page rank.

Step 4: Change Permalink structure

To change the permalink structure, I used the awesome Permalink Migration plugin by Dean Lee. With this plugin, I just specify the old permalink structure (in my case, this was /%year%/%monthnum%/%postname%/) and then change the permalink structure in WordPress (Settings -> Permalinks) to the new format (I'm using /%postname%/).

Now whenever someone visits a URL using the old permalink structure, Dean's plugin sends a 301 redirect to the new URL.

Summary

With the .htaccess rewrite rule and Dean's Permalink Migration plugin, we now have a double 301 redirect to make sure the old URLs redirect to the new ones:

  1. Someone searches Google and finds this link to my site: https://raamdev.com/2010/01/28/some-blog-post
  2. The .htaccess rule rewrites the URL and redirects: https://raamdev.com/wordpress/blog/2010/01/28/some-blog-post
  3. Dean's Permalink Migration plugin redirects to the new permalink structure: https://raamdev.com/wordpress/blog/some-blog-post

PHP Session Permission Denied Errors with Sub-Domains and IE7 or IE8

I encountered a strange problem with IE7 and IE8 where if I visited `example.com` first and then visited `sub-domain.example.com`, Apache would return Permission Denied errors errors when trying to access the PHP session files for `sub-domain.example.com`.

After some investigation, it appears this is a problem with the way IE7 and IE8 request session data from Apache, or possibly because IE7 and IE8 have a non-standard way of announcing the domain they're requesting session data for.

Here's my scenario:

I'm running Apache 1.3 with two domains, each has their own account with their own users:

    Domain: mycompany.com
    Session path: /tmp/
    Webserver user: mycompanycom

    Domain: support.mycompany.com
    Session path: /tmp/
    Webserver user: nobody

Here is what happens during a normal visit with Firefox/Safari/Chrome:

  1. I visit `mycompany.com` and session file is created in /tmp/ owned by the user mycompanycom
  2. I then visit `support.mycompany.com`, and second session file is created in /tmp/ owned by user nobody
  3. Apache doesn't get confused and the correct session files are returned

However, here's what happens during a visit with IE7 and IE8:

  1. I visit `mycompany.com` and a session file is created in /tmp/ owned by the user mycompanycom
  2. I then visit `support.mycompany.com` and, instead of creating second session file in /tmp/ owned by the user nobody as you would expect (and as happens when using Firefox/Safari/Chrome), Apache tries to return the session file for mycompany.com.
  3. The session file for `mycompany.com` is owned by the user mycompanycom, so the web server, running as user nobody cannot access it. Permission is denied.

I searched Google for a solution and came across this question on StackOverflow. Several users suggested creating a separate directory in /tmp/ to separate the stored session data for `support.mycompany.com` from the session data for `mycompany.com` and then telling PHP to store all session data for `support.mycompany.com` in the new directory. This worked perfectly!

Here's what I did. First, create the new session directory (Note: Make sure the new directory resides inside /tmp/!):

    mkdir /tmp/support.mycompany.com
    chown nobody:nobody /tmp/support.mycompany.com

I then added the following to an .htaccess file in the root web directory for `support.mycompany.com`:

    php_value session.save_path '/tmp/support.mycompany.com'

And finally, I removed all existing session data in /tmp/ to ensure the new session path would get used immediately:

    rm -f /tmp/sess_*

And that's it! Now IE7 and IE8 work properly because when visiting `support.mycompany.com`, IE7 and IE8 do not accidentally find session data for `mycompany.com` and try to use it.

I'm fairly certain this problem has to do with how IE7 and IE8 request session data from Apache. They probably first request session data for `mycompany.com` and THEN request session data for `support.mycompany.com`, even though the latter was the only doman entered in the address bar.

Installing Apache 1.3 on Debian Etch

I few days ago I setup a new Linux box to use for testing my web development work. The production environment for the site is hosted on a Linux machine, so I wanted to test it in a Linux environment, not a Windows environment (which is where I currently do my development work). So, I decided to setup a Linux box with Samba, map a network drive, and simply work on my site files directly from the Linux server. This way I can just save my changed file, press refresh in my browser, and see the changes. I'll explain more about my actual staging setup in a future post.

I did not find very much, if any, information about how to easily setup Apache 1.3 on a Debian 4.0 (Etch) system. Why do I want Apache 1.3 instead of Apache 2? Because I'd like to replicate the production environment as closely as possible. My web host uses Apache 1.3.37, PHP 4.4.3, and MySQL 4.1.21.

I documented the steps I took to get everything setup here on my Wiki. This is the first time I've used the Wiki to store information that I would normally post here in my blog, and I'm still trying to figure out how I will decide what information goes on the Wiki and what goes on the blog.

The quick answer to getting Apache 1.3 installed on an Etch system is to edit /etc/apt/sources and change etch to sarge. Then run apt-get update and apt-get install apache. You can make sure you’re going to install Apache 1.3.X beforehand by running the following command: apt-cache showpkg apache and checking which version it displays. It should show something like this:

Package: apache
Versions:
1.3.34-4.1(/var/lib/apt/lists/debian.lcs.mit.edu_debian_dists_etch_main_binary-i386_Packages) (/var/lib/dpkg/status)

Apache Error: Permission denied for /images/

I was trying to test a project I'm working on using my local Apache web server. Everything worked fine, except that it wouldn't load any of the images. I dealt with it for awhile, until I couldn't take it anymore. Why the hell weren't the images showing up?

I tried accessing http://localhost/images/ where they are stored and it said permission was denied. So I tried accessing another directory under the root, in this case /notices/, and everything worked fine. I was able to list the contents of the directory and access the files inside. OK, so I should be able to simply change the permissions on the /images/ directory so they match /notices/. But wait... they already match!

[code]
drwxr-xr-x 3 raam raam 4096 Sep 7 13:31 images
drwxr-xr-x 3 raam raam 4096 Sep 7 13:31 notices
[/code]

OK, so maybe the permissions of the files themselves are wrong? Nope, those match too. I dealt with a problem similar to this awhile back and I resolved it by asking for help in #apache on EFNet. So I decided to head over the #apache once again and ask for help. When I entered the channel, the topic of the room was set to "Read your error log and use your own domain". So before I asked anything, I decided to check my error log. Sure enough, here's what I found in /var/log/apache/error.log:

[code]
[email protected]:/var/www$ tail /var/log/apache/error.log
[Tue Oct 17 14:30:42 2006] [error] [client 127.0.0.1] File does not exist: /usr/share/images/logout.png
[Tue Oct 17 14:30:42 2006] [error] [client 127.0.0.1] File does not exist: /usr/share/images/aerchannel.png
[Tue Oct 17 14:30:46 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:30:48 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:32:48 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:32:56 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:33:31 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:40:42 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[Tue Oct 17 14:41:44 2006] [error] [client 127.0.0.1] File does not exist: /usr/share/images/logo.jpg
[Tue Oct 17 14:41:52 2006] [error] [client 127.0.0.1] Directory index forbidden by rule: /usr/share/images/
[/code]

Ah hah! "Directory index forbidden by rule: /usr/share/images/" Thats odd, there's rule preventing it? So I looked over my httpd.conf AGAIN. After a quick search of "images", I found this:

[code]

Alias /icons/ /usr/share/apache/icons/


Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all

Alias /images/ /usr/share/images/


Options MultiViews
AllowOverride None
Order allow,deny
Allow from all


[/code]

Alias /images/ /usr/share/images/!? What the hell? How inconvenient is that? You would think that the Apache developers would assume that people will have a directory called /images/ in the root of their web path. It is after all a very common directory used to store images for the website. As soon as I removed the alias definition for images and restarted apache, everything worked perfectly. I was able to access /images/ and all the pictures showed up on my site.