New Hosting / Server OS

Posted by Matt White, Thu Dec 13 20:10:00 UTC 2007

After running nearly two years on a Rimuhosting VPS with Debian Sarge, we decided to switch over to a Rimuhosting Miro4 on CentOS 5 with Plesk 8.2 and do some hosting. Since it seems that since we’re the primary tech support contact for our clients regardless of the fact that most of them have direct relationships with their web hosts, we’ve decided to start hosting client sites ourselves (when appropriate), on our VPS. VPS hosting for Rails sites is usually a better solution anyway, since nearly every shared host I’ve attempted to host a Rails app on until now has either been very slow, or very unreliable.

Overall, it’s been a lot of fun getting things up and running, and it’s been quite painless. Plesk automates a lot of the tasks that I had to do manually on Sarge, a lot of which I really didn’t want to know about anyway. (Such as editing dovecot config files manually… ugh)

I was a bit concerned about how to host Rails apps with Plesk, and I’m pleasantly surprised at how easy it is. CentOS5 ships with Apache 2.2, with it’s awesome mod_proxy_balancer. It’s definitely not the highest-performance solution available, but it’s easy to set up, and it integrates well with the Plesk workflow. This blog is running on two mongrels with mongrel_cluster, and balanced with mod_proxy_balancer. I simply had to set up a vhost.conf file based on the setup provided by Coda Hale for my subdomain, get mongrel_cluster configured to match, and I was done. There’s a couple other steps in there, which I’ll detail in a future post.

IMAP Problems

The only real problem I’ve experienced is Apple Mail’s rebellion against the IMAP namespace structure of Courier IMAP, which is the default mail server with Plesk. Apparently under the IMAP spec mail servers are free to choose a namespace separator as well as a namespace prefix. This can be autodiscovered during the HELO process with the server, but Mail ignores this. Mail DOES allow you to set an IMAP prefix under the Advanced account settings tab, which on Courier servers is INBOX. Setting that is the first step, which will get Mail to correctly pick up the Sent and Trash folders on the server. However, there is still difficulty when you wish to create new “Mailboxes” on the account, which is Mail’s term for subfolders. In this case, if you wish to create a first-tier subfolder under the account (i.e. Account Name/New Folder) you must specify the mailbox name as “INBOX.New Folder” to correctly set it up. However, for subfolders underneath this new folder (i.e. Account Name/New Folder/New Subfolder), you simply add a new Mailbox underneath New Folder as you would expect, with no need to specify any prefix.

0 comments | Filed Under: | Tags:

MediaTemple (gs) Automated Mongrel Restart

Posted by Matt White, Fri Dec 07 10:45:00 UTC 2007

I’ve got a couple of small Rails sites hosted on MediaTemple’s (gs) product, and I’m happy to say that it’s been a positive experience. A lot of people complained about the product early on, but MediaTemple has made a lot of reliability improvements, and I’ve had nothing but a good experience so far with it.

However, the one problem is that the base Rails container, which runs Mongrel, is pretty limited on memory, and it seems that the mongrel process will just get killed if it goes over it’s limit. I’ve had this happen a couple of times where the process gets killed without being restarted, and then the site is down until I call “cap restart” or restart it via SSH. This obviously isn’t an acceptable solution, so I hacked together a little Ruby script that will check your site to see if it’s alive, and if not it will restart it. Schedule it via cron, and you’re ready to go!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#!/usr/bin/ruby
require 'net/http'
require 'uri'

site = "your_site_id"
application = "your_application_name"
friendly_name = "Your Site's Actual Name (used only for notification)"
webpath = "http://www.yourdomainname.com/"
user = "serveradmin%yourdomainname.com"
password = "yourpassword"

url = URI.parse(webpath)
req = Net::HTTP::Head.new(url.path)

res = Net::HTTP.start(url.host, url.port) do |http|
  http.request(req)
end

unless res.is_a? Net::HTTPOK
  puts "Detected Site Down: Restarting #{friendly_name}..."
  `mtr restart #{application} --username #{user} --password #{password}`
end

One More Thing

To actually call the script, you have to initialize your PATH variables, since cron doesn’t run your .bash_profile script before it runs your job. I created a .sh file to call my ruby script that sets the correct paths before calling the script:

1
2
3
4
5
6

#!/bin/sh
export PATH=$PATH:/usr/local/bin/

cd $HOME/data/
./babysitter.rb

I called the sh file babysitter.sh, and the ruby script babysitter.rb, chmod +x on both of them, added babysitter.sh as a 5 minute cron job, and forgot about it. Periodically I’ll get a cron email letting me know that it’s restarted the app, though it doesn’t happen very often.

Hopefully this will help someone!

0 comments | Filed Under: | Tags:

Thoughts on Content Management

Posted by Matt White, Wed Dec 05 21:51:00 UTC 2007

After developing a few custom CMS apps in Rails, and not being entirely happy with the result, I decided to try Drupal out as a base for a content management app. Now, don’t get me wrong, I love Rails. I wish I could only ever develop in rails. But the economic reality is that most of the work we get calls for flexible content management, and the ‘bespoke’ CMS’s that I’ve built in Rails/PHP/ASP.Net over the years leave a lot to be desired… Also, as the Rails community seems to be focused more around app development, few actual dedicated content management apps have surfaced. Radiant CMS is one, but I’m going to give it a bit more time before I try it on a client project. However, reinventing the wheel every time just isn’t efficient enough to justify building the ‘perfect CMS for the situation’, so I decided to try out some of the open-source heavy-hitters.

Joomla

I built a restricted-access membership site for a client that integrated the user database with their internal enterprise system, and I based that site on Joomla 1.5. Naively, I thought that it was better to base the site on the latest and greatest version of the Joomla framework for forward compatibility. This was indeed a benefit during development, though the documentation on custom module development for version 1.5 was very sparse. Joomla 1.5 uses the MVC pattern, which is really quite nice since I’ve done most recent work in Rails with it’s similar MVC pattern. However, I found the development of modules to be a painful process that required lots and lots of poking around in the core modules to see how it ‘should’ be done, due to the lack of proper documentation.

The Joomla community has had quite a bit of drama lately over licensing issues, which has largely halted creation of modules for Joomla 1.5. This has proved to be a major problem for us, since we had recommended Joomla to the client based on it’s large base of available modules. I’m hoping that this issue will burn itself out soon, but so far it’s just another strike against Joomla.

Finally, after using the Joomla admin I’m just not convinced that it’s nearly powerful and flexible enough to do much more than manage a basic website. The permissions system is quite static, and additional modules seem poorly integrated into the interface. Unlike Drupal, where a module can actually modify the behavior of other modules, each module very much stands alone in Joomla. If you don’t like the behavior of the core framework, it’s time to start hacking.

Drupal

So… after building a membership site in Joomla and being very much underwhelmed by the experience, I decided to give Drupal a whirl. The main features that attracted me to Drupal are the (surprise!) development features, as there is a lot of power to be found in the framework.

The default module set is pretty basic. However, when you add Views, CCK, ImageCache, and Services, you have the ability to build feature-rich sites very quickly. I built a site that allows for full content management by the client with integrated flash interface elements pulling data from Drupal via the AMFPHP remoting gateway, all in a very few days, most of which were spent writing the Flash elements and building the theme. Very little time was spent on actual module development, since the flexibility provided by the above modules saved me from coding custom modules.

The most critical thing with Drupal is to learn which modules are essential. Drupal core is functional, but you really need to add modules to make it useful. The CCK (Content Construction Kit) allows you to build nodes (types of content) with arbitrary column types. This allows you to construct node types that match all of your content. The Views module lets you create custom views for your content, including RSS feeds. ImageCache is absolutely fantastic… It allows you to define resizing presets for images that you can then reference in your templates. When an image is called for, it’s resized based on the selected template and cached to disk for subsequent use. Should you change the template, just flush the cache and the process starts again! Finally, though I didn’t use it here, the Services/AMFPHP module is an excellent way to connect Drupal with Flash Remoting. We’ve got another job coming online that I’ll mention here once it’s done that makes use of this.

All of this said, Drupal is not for the faint of heart. You need to approach it with a bit of a hacker mentality to really get the most out of it. I’ve read many comparisons between different CMS options, and one of the most common complaints about Drupal is the varying quality of the modules, the steep learning curve with development, and the less than desirable quality of the Drupal template engine. Many people who complain about these shortfalls find ExpressionEngine an easier CMS to use, due to it’s ease of skinning. However, I’m convinced that if you’re into development and aren’t too concerned with the skinning issues, Drupal offers a very powerful and flexible base with which to start. Drupal is one of the most extensible platforms I’ve seen, and offers many ways to plug into nearly every bit of the system to insert your own custom functionality. This alone is it’s most redeeming feature.

Conclusion

I’m definitely going to keep using Drupal for heavy content-management sites. However, whenever I’m presented with the opportunity to develop an actual web application, I’ll certainly be going back to Rails.

0 comments | Filed Under: | Tags:

It's ALIVE...

Posted by Matt White, Wed Dec 05 21:38:00 UTC 2007

Thermal has launched our new website! Well, to be completely honest, it’s our FIRST website. Up to this point we’ve been surviving on a first-round logo draft and no business cards, which I suppose is a testament to the strength of the economy and the demand for people like us.

However, we had some time this fall, and decided to get all professional-like and make an actual website.

The site is based on Drupal, with a lot of help from Views, CCK, and ImageCache. My biggest frustration (as mentioned in the previous post) is the difficulty in building themes and customizing the appearance of modules. Shamefully, I did end up hacking the core contact form, after all of my wrangling with hook_form didn’t produce the desired results. Since Drupal modules often end up outputting HTML (though they should do a minimum of this if they use the theme functions), it seems that some hacking is always required to get the job done.

Also included were Javascript support from ThickBox and JCarousel. This was also my first experience with JQuery, and it’s not bad at all. A lot of similarities to Prototype, though I still like the Prototype coding style a bit better.

We’re still planning for more features in the future for the site, but for now it’s back to the “real” work!

0 comments | Filed Under: | Tags:

XML.load and Content-Encoding

Posted by Matt White, Tue Mar 06 09:22:00 UTC 2007

I was having a rather perplexing problem with Flash in IE6 the other day, and I found very little to help me until I stumbled upon this gem. We have some flash elements on a site that we built that make use of XML loaded out of a Rails app via ActiveRecord::Base.to_xml. I was using the basic Nginx config file put together by Ezra for proxying to a mongrel_cluster, which works great overall. However, as mentioned in that blog entry, IE6 doesn’t like compression or no-cache headers on XML data.

Fortunately Nginx allows you to set the header types that will have gzip compression applied, using the “gzip_types” directive in the config file. So, just make sure that your actions that generate xml have the “Content-Type: text/xml” header applied, and then remove the “text/xml” directive from the list of gzip_types in your Nginx config file.

Unfortunately you can’t use the handy-dandy Rails respond_to function, because Flash fails to correctly set the Request-Type header to text/xml. So, my only solution was to come up with xml actions to parallel with my view actions so that any request to that action would receive xml regardless of the Request-Type.

So, make sure that any actions that emit xml for Flash consumption set the following:

1
2

@headers['Content-Type'] = "text/xml"

And you should be good to go!

1 comment | Filed Under: | Tags:

Rails AJAX_OPTIONS :with

Posted by Matt White, Wed Feb 21 15:05:00 UTC 2007

The Problem

I’m writing an admin backend for a client, and I wanted to trigger an AJAX call based on the value of a SELECT field. The problem this presents compared to the normal Rails AJAX usage is that the value you want to send via AJAX isn’t specified at the time the page is rendered, and I didn’t want to serialize the entire form to get the correct value of one field.

The obvious candidate for a link to fire an AJAX call is link_to_remote, but it’s not entirely obvious how you can specify a request parameter that will be evaluated at the time of the click. Most of the time you set the parameters you wish to send back to the server in the URL, but that won’t work in this case because I don’t want to use a static URL.

.h2 The solution: ”:with” So, there’s a handy option to most of the PrototypeHelper functions that’s a bit poorly documented (in my opinion, anyway). :with allows you to specify the parameters part of the Ajax.Request call. This will be evaluated on the fly when the onclick is fired, and is submitted via POST. (Unless you are setting the postBody parameter as well.) The best part is that Prototype will serialize standard JavaScript object notation (read: JSON) into a URL-encoded POST body. Not too clear? Try this:


link_to_remote("Set Position", 
           :url => {:action => "load_map", :id => @listing},
           :with => "{map_id:$F('listing_map_id')}")

This will yield the following HTML/JavaScript:


<a href="#" onclick="new Ajax.Request('/property/show_map/1', 
           {asynchronous:true, evalScripts:true, 
           parameters:{map_id:$F('listing_map_id')}}); 
           return false;">Set Position</a>

Which will, when clicked, generate an AJAX call with the following POST body:

map_id=1

(assuming the value of my dropdown is 1.) Also, note that $F is a Prototype shortcut that allows you to grab the value of a form field based on the ID you pass in. An extremely handy function…

So, this is a really great way to add an arbitrary number of parameters to an AJAX call using any Javascript variable, which could be the position of an element, value of a form field, the list goes on!

0 comments | Filed Under: | Tags:

Adventures in Mac Ownership...

Posted by Matt White, Sat Feb 10 12:16:00 UTC 2007

Well, I just learned my biggest lesson about Mac Ownership… Buy AppleCare.

I’ve had my MacBookPro (MBP) for almost a year now, and I’ve been giddy about it most of the time. It’s my first Mac, and I couldn’t be happier for switching. (My name is Matt White, and I’m a switcher !)

This summer I participated in the MBP battery recall, and congratulated myself for purchasing a computer from a company so addicted to quality that they sent me a new battery because the original didn’t “live up to expectations”. Take THAT, Dell!

However, while I was based out of New Zealand last fall (about a month after getting my new battery), my computer started having hardware problems. When used on battery, it would randomly lose power without warning. No shutdown, just dead. The problem started getting worse and worse, to the point where I couldn’t even use the machine without being on AC power. Needless to say, this is ultra lame when you’re talking about a laptop. (Or “portable”, as Apple likes to call the ultra-hot MBP)

I was in New Zealand, which meant that I had to live with it. However, when I got back to the US I was looking forward to exercising my 1-year hardware warranty to fix an obvious hardware problem. I didn’t need tech support or troubleshooting, I just wanted it FIXED.

Well, lo and behold, there is NO WAY to get service under your hardware warranty without calling Apple, where you will have to speak to a tech who will explain to you that even though you have a 1-year hardware warranty, he can’t actually talk to you about your problem unless you buy AppleCare, or pay a single-time service fee of $49. Excuse me, but how else am I supposed to get service?!

After shouting at two techs, I finally got one who would help me. Though the problem began suspiciously close to my battery replacement, they still wanted me to send in my whole computer. If you’re a tech guy, you realize that sending in your computer is like being a truck driver and having to send in your truck for two weeks while your customers wait for you to get back on the road. Not good when you have deadlines. (And when do I NOT have deadlines?)

Meanwhile, in addition to the battery problem, my MagSafe power connector began having problems. I had a difficult time getting a good connection between it and the computer, and it would randomly lose connection while I was working. This coupled with the fact that my battery was now not working at all meant that when it disconnected on it’s own, everything went black. How’s that for enticing you to “save often”?

Apple sent me a box to send my machine back, and I debated and debated about doing it. Should I buy another Mac to use while waiting for this one to be fixed? No, definitely not. Local service wasn’t an option, so I opted to buy AppleCare and hope that the service level would increase enough from Apple Tech Support to actually allow me to get it fixed without taking a two-week “vacation”.

What a difference… Buying AppleCare was like the difference between a rude taxi driver and a limo driver. (I’m just assuming here. I’ve never ridden in a limo, and probably never will.) While I’m still pretty irritated about the manhandling at the hands of AppleCare when I still had a legitimate one-year warranty issue to solve, at least they would help me now… After talking to another tech, we decided to replace the battery instead. I had since tried my machine with my co-worker’s battery, and it worked just fine. When we tried my battery in HIS computer, it wouldn’t even turn on without AC power.

After explaining this to Apple, they overnighted me a new battery, a new MagSafe, and life is now good as gold…

The Moral of the Story

If you’re Apple, please have your techs stop being jackasses with people when they have a legitimate hardware issue. I did NOT appreciate how I was treated.

If you’re a Mac owner, and you don’t have AppleCare but still have your hardware warranty, be very pushy when you call them on the phone. If it’s a legitimate hardware failure, they should fix it without charging you a dime. If you don’t want to be pushy, just buy AppleCare. Then they treat you like royalty… Either way, the peace of mind of knowing that, barring my own stupidity, my machine will last a solid three years because Apple will HAVE to keep it going is still worth at least $349.

0 comments | Filed Under: General Tech | Tags:

Site5 Deployment Problems with Capistrano > 1.2

Posted by Matt White, Fri Feb 09 16:46:00 UTC 2007

So, I’ve dutifully upgraded my copy of Capistrano to the latest version, and then updated one of the apps I have running on Site5. The only one, actually, and it will probably stay that way. After feeling the Mongrel love with a little Nginx/Pound/Pen/mod_proxy_balancer sprinkled on top I don’t think I’ll EVER use FastCGI again. Anyway…

Apparently in the latest versions of Capistrano, all permissions on the new releases are set chmod g+w, something that doesn’t fly on most (if not all) shared hosts. The biggest problem, however, is how this problem is manifested on such hosts as Site 5. In this case, the app would simply refuse to spawn ANY FastCGI processes, and would return a completely empty request. No HTTP status code, nothing. Apache would still serve static files, but anything that fell through to the dispatcher would fail.

Of course, there we NO log messages in either the production.log or the fastcgi.crash.log. Nothing. Nada. Nothing to work with. Not even a 500 response in the browser.

After tearing my hair out, I talked to Site5 support and they suggested permissions as the culprit. However, they suggested that I set 755 on the whole app, which failed to rectify the Capistrano-set permissions. At this point I didn’t realize what Capistrano was doing, so I resumed emptying my follicles.

After reading a post by “Josh on Rails” on the RoR message board about the same problem, I found out what Capistrano was doing. Thankfully, in version 1.4.0 of Capistrano, Jamis added a :set_permissions task, allowing you to override the task in your deploy.rb. So, I just did the following:

1
2
3
4

task :set_permissions, :except => { :no_release => true } do
  # do nothing
end

in my deploy.rb, and voila, no more problem. Simple fix, but since there is really zero diagnostic info available it’s almost impossible to figure out what’s going on. (At least for me with my seemingly never-ending shallow knowledge of the UNIX domain… Curse my days as an ASP.Net user! Curse them!)

Hope this saves someone a few hours… I wasted far too many on it.

1 comment | Filed Under: Rails | Tags:

Migrated to Mephisto

Posted by Matt White, Wed Jan 24 16:38:00 UTC 2007

Well, I’ve migrated the blog to Mephisto... A rather oddly-named blogging package, but it’s definitely the best thing going for Rails blogging apps these days. Sadly Typo has fallen off the map, and Typo was always something of a dog from a performance perspective.

So, thanks to this article, the migration was pretty easy and Mephisto seems MUCH snappier than Typo. It’s also much less memory-intensive, and has an excellent caching implementation that allows you to expire the cache on command.

Finally, as the new Prototype site seems to be using Mephisto as a CMS with little difficulty, I think we’re going to check out using Mephisto as a low-end simple CMS for sites that don’t require a ton of bells and whistles. We shall see…

0 comments | Filed Under: | Tags: