Running Plone with Nginx

Spend few hours to get Plone running behind Nginx through proxy_pass. It supposed to be as simple as:-

server {
    listen      80;
    server_name cvt.int-prokab.com;
    root html;

    rewrite ^/(.*)$ /cvt last;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

The plone site are running on port 8080 at 127.0.0.1:8080/cvt. I want it to be exposed to the outside as http://cvt.int-prokab.com/ but it turn out that Plone generate all url on the site as 127.0.0.1:8080/cvt - the address behind and not the exposed public url. Reading explanation on ZMI Virtual Hosting interface:-

The VHM doesn’t do anything unless it sees one of the following special path elements in a URL: VirtualHostBase sets the protocol and host, while VirtualHostRoot sets the path root. If the URL path of a request begins with ”/VirtualHostBase/http/www.buystuff.com”, for instance, then URLs generated by Zope will start with http://www.buystuff.com. Since the port number was not specified, it is left unchanged. If your Zope is running on port 8080, and you want generated URLs not to include this port number, you must use ”/VirtualHostBase/http/www.buystuff.com:80”. If the URL contains VirtualHostRoot, then all path elements up to that point are removed from generated URLs. For instance, a request with path ”/a/b/c/VirtualHostRoot/d” will traverse “a/b/c/d” and then generate a URL with path /d.

Took me sometimes and hair pulling before I could understand how it would work. The rewrite supposed to be like this:-

rewrite ^/(.*)$ /VirtualHostBase/http/cvt.int-prokab.com:80/cvt/VirtualHostRoot/$1 last;

Blog @ localhost

It's fun, really fun. Now I can write anything that I want, jot everything that came to my mind just instantly. No need to think, no need to worry about grammar... and no latency ! As a side note, I used Dokuwiki and it rocks too ;)

Drupal Form API 'value' element

It’s common to use hidden value in a form to specify certain variable that was meant to logic which would handle the form processing rather than the user facing the form, hence the name ‘hidden’. Drupal Form API provide special element ‘value’ that can be used for the same task except that the value would not be sent together with the form. Let say you need to main a refference to customer_id when user entering their order in order form, the typical way is to used hidden element like this:-

$form['customer_id'] = array('#type' => 'hidden', '#value' => $customer_id);

This would put the value as a hidden form element and sent along other form value when user submit the form. The alternative is to use the ‘value’ element:-

$form['customer_id'] = array('#type' => 'value', '#value' => $customer_id);

No value would be sent to the browser but it’s still available to the form submit handler just like any other element. Neat idea, I think.

Drupal Form API Gotcha

Doing an upgrade of my app from Drupal 4.7.x to Drupal 5.x. The big difference in Form API in Drupal 5.x vs 4.7.x is on how drupal_get_form (the way form is build) work. In 4.7.x, drupal_get_form work through a push model where we supply the array of form definition to the function call:-

function customer_edit($customer) {
  $form = array();
  $form['customer_name'] = array(
    '#type' => 'textfield',
    '#title' => 'Name',
    '#default_value' => $customer->name
  );
  return drupal_get_form($form, 'customer_edit');
}

The second argument is the form_id. In 5.x however, this has changed to pull model where the form definition need to be build in a dedicated builder function.

function customer_build_form() {
  $form = array();
  $form['customer_name'] = array(
    '#type' => 'textfield',
    '#title' => 'Name',
    '#default_value' => $customer->name
  );
  return $form;
}

function customer_edit($customer) {
  return drupal_get_form('customer_build_form');
}

Now the first argument to drupal_get_form function call is the name of the form builder function. Another way is to implement the new hook introduced hook_forms to do some complex mapping of form_id to builder function.

function customer_forms() {
  $forms = array();
  $forms['customer_edit'] = array(
    'callback' => 'customer_build_form'
  );
  $forms['customer_add'] = array(
    'callback' => 'customer_build_form'
  );
}

function customer_edit($customer) {
  return drupal_get_form('customer_edit');
}

I got some problems when using the hook_forms approach. No errors from PHP process and Nginx just gave an ‘500 server error’. Further checking revealed that the problem was with the form_id which is similar to already defined function name. My guess was some recursive calling occured when drupal_get_form first try to call a function named customer_edit as being used in the form_id. Unfortunately, the calling function was also a customer_edit. So the fix is, never used form_id that is similar to already defined function since drupal_get_form will first look for it instead of relying on the hook_forms if it is implemented.

Mercurial ignore empty directory

This is one thing that I should really remember. Mercurial will just ignore empty directory so beware of doing something like this:-

$ mkdir myproject
$ cd myproject
$ hg init
$ vi index.php
(editing ....)
$ hg add index.php
$ hg commit
(commit message ...)
$ hg branch exp
marked working directory as branch exp
$ mkdir modules
$ hg add modules
$ hg commit
(commit message)
$ cd modules
$ vi exp.php
(editing ...)
$ hg add exp.php
$ hg up -C default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg status
abort: No such file or directory
$ cd ..
$ ls
index.php
### wtf !!, this is not on the screen.

My expectation was only exp.php would be gone when I switch ‘cleanly’ to the default branch. In fact, the commit that I did when adding modules directory does record anything though it was logged and the revision increased.

Btw, this blog post illustrated the use of Mercurial better than the official docs.

Mercurial clone through ssh

I want to do some backup of my work on the remote machine. My first try was with hg push but it turn out that hg push require a repository to be exist on the remote end. So I just tarred up the local repo and manually copying the tarball using scp and then did an hg pull to get it back. This way I can just push my changes as a backup in the future. But something is wrong somewhere.

$ hg clone ssh://me@remotehost/home/kamal/hg/repo/
remote: abort: There is no Mercurial repository here (.hg not found)!
abort: no suitable response from remote hg!

It’s weird since doing hg log on the remote repo work just fine. So I try to execute the command with a verbose option, thank god they have it.

$ hg -v clone ssh://me@remotehost/home/kamal/hg/repo/
running ssh me@remotehost "hg -R home/kamal/hg/repo/ serve --stdio"
remote: abort: There is no Mercurial repository here (.hg not found)!
abort: no suitable response from remote hg!

That’s it. A path problem. Add another slash to the path would make it work. Then I checked back the man page and it clearly stated:-

- path is relative to the remote user’s home directory by default. Use an extra slash at the start of a path to specify an absolute path: ssh://example.com//tmp/repository

I use an absolute path because the first try using the common ‘~/’ for my home directory does not work. Next time, carefully read the manual !

Test drive new 'Engine'

Nginx (pronounced: EngineX) is a lightweight http server written by Russian, Igor Sysoev. Initially, most of the documentation and discussions were in Rusian but now there’s an English wiki set up for English speaking users. So, through out the day I took a plunge swapping out lighttpd with nginx and watched how it’s going. It’s quite satisfying. I let the process untouched for hours while the site being hit as usual and I can concluded that no memory-leaking type of problem as in lighttpd seem to appear.

The setup was a non-trivial, especially for the PHP/FastCGI thingy but after properly following the example in the wiki and some scattered blog post on the net I got it working. What can I say, nginx configuration syntax is way much verbose compared to lighttpd or apache. It’s programming langguage like syntax make it easy to follow and even vim autoindent work’s perfectly well to auto indent the configuration file. The structure can be logically divided into http, server and location context. Virtual host is just another server context with different server_name directive and location can be nested within any of the main context.

URL rewriting especially for Drupal clean url was a little bit easier. Nginx does provide conditional rewriting so it’s easy to emulate apache rewrite rules come with the Drupal distribution. This forum post on Drupal.org illustrated it well:-

http://drupal.org/node/110224

Unlike Lighttpd, nginx does not automatically spawn FastCGI process for us so we need to invoke PHP as FastCGI externally and then have nginx proxied the request to the process. As suggested by others, I used the spawn-fcgi program from lighttpd to handle the spawning process. Since nginx does not provide any init scripts, I modified the lighttpd init script to handle nginx and PHP FastCGI spawning during system start up and handy daemon start, restart, stop. Just as a note to myself, on Ubuntu (and Debian) init scripts were handled by update-rc.d program: update-rc.d nginx defaults would created proper symlink from the appropriate run level (/etc/rcN.d) to nginx script in /etc/init.d.

Here are some resources on the net that help me to get nginx running on my system:-

http://wiki.codemongers.com/
http://www.nslu2-linux.org/wiki/HowTo/DeployPHPWebAppUsingFastCGI
http://www.google.com.my/search?q=nginx+php

While the early motivation comes from:-

http://hostingfu.com/article/running-drupal-with-clean-url-on-nginx-or-lighttpd http://forum.slicehost.com/comments.php?DiscussionID=787&page=1#Item_10

Going light

It’s been more than a week already after I switch from Apache to lighttpd. Apache just can’t handled the traffic anymore on this little 256 slice. Lighttpd indeed a very fast and lightweight web server. Even with the default 16 spawned FastCGI process on the initial start, I’d still have 100+ Mb left of my 256 Mb RAM compared to 32 MB left when using Apache with MaxClients set to 10. That’s really a big win for this small vps.

For the first few days, things were doing just fine. Hits to one of the sites spiking up just after I did the switch and it’s such a joy watching the speedy new server. But the joy not lasting for long, lately I’d figured up that lighty process randomly died after a few hours serving a request. Some search on Google confirmed that it has some sort of memory leak and quite a few people experiencing the same problem as mine. So while it fast, it’s not stable. No concrete fix were found and everyone just suggesting and guessing the actual problem.

The temporary fix that I did for now is just adding a cron job that would restart the process hourly. At the same time I would try to look at nginx which look’s quite promising as an alternative to lighttpd and apache.

Transactional DDL in PostgreSQL

It’s quite common for me to issue some DDL statement in my query together with an INSERT, UPDATE or any statement that modified the state of the db and then rolling it back. Mostly for testing purpose of a new change or addition to the schema. It was something that I take for granted ever since I know PostgreSQL. Few days ago, someone mentioned about Transactional DDL which is actually unique to Postgres only. And today, a discussion followed up which explain in detail what is mean by Transactional DDL and a brief comparison with MySQL which doesn’t have it. I just can’t imagine if Postgres doesn’t have this.

Old tracks

Among the old tracks that I never listened before:-

Penawar Hati - Rindu Padamu
Sinaran Azhar - Rencah Hidup Pejuang

And some of the old tracks that I thought only exists in my memory but thanks to the wonderful of Internet, someone has put it online :-

Soutul Jihad - Sedarlah Umat II
Soutul Jihad - Ubat Rindu
Soutul Jihad - Senandung Anak Pejuang

Syndicate content