afurlan's blog

/^random (nerd|geek)? posts$/

Configuring apache's userdir on nginx

Wednesday, May 26, 2010 - Four comments

Today I moved the people.nullable.org from Apache to the Nginx and the migration was easier than I expected.

The configuration is very simple so I'll jump directly to the code. The following lines enables the Apache's Userdir feature with PHP support in a specific domain. As in my last post, I'm assuming you currently have PHP working on Nginx but if you don't, take a look at here to know how to do that using the spawn-fcgi.

server {
    server_name people.nullable.org;
    listen 80;
    listen 443;

    # directory root
    root /srv/people.nullable.org/nginx/www;
    index index.php index.html index.htm;

    # userdir redirection
    location ~ ^/~([^/]+)/(.+\.php)$ {
            if (!-f /home/$1/public_html/$2) {
                    rewrite ^ 404;
            }
            alias /home/$1/public_html/$2;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            include fastcgi_params;
    }
    location ~ ^/~([^/]+)(/.*)?$ {
            alias /home/$1/public_html$2;
            autoindex on;
    }

    # logging
    error_log /srv/people.nullable.org/nginx/log/access.log;
    access_log /srv/people.nullable.org/nginx/log/access.log;
}

There isn't too much to say, this setup is currently running on my server. Suggestions are welcomed! :)

Nginx and PhpLdapAdmin

Monday, May 24, 2010 - Nine comments

I usually run Apache in my web servers, it works pretty well but spends too much memory for that. So I decided to give a try to the Nginx and for now, I'm really impressed about its preformance.

I don't intend to present Nginx at this post, but if you want to know more about it (and IMHO, you should) go to its official documentation. I'm going to show how to configure the PhpLdapAdmin and Nginx but not how to install the PHP itself. So I'll presume you currently have PHP working on Nginx but if you don't, take a look at here to know how to do that using the spawn-fcgi.

Let's start installing the PhpLdapAdmin and the PHP5 module to connect to the LDAP server. If you're using Debian/Ubuntu, all new software are just an "aptitude install" of distance from you, so let's install them:

$ aptitude install phpldapadmin php5-ldap

Now we can start the PhpLdapAdmin on Nginx configuration itself... You can use the PhpLdapAdmin under a specific domain or use it as a standalone application. If you want to install the PhpLdapAdmin under a specific domain, you should create a new virtual host named example.com as follows:

$ vim /etc/nginx/sites-available/example.com
server {
    server_name example.com;
    listen 80;

    # document root
    root /usr/share/phpldapadmin/htdocs;
    index index.php index.html index.htm;

    # application: phpldapadmin
    location ~ \.php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_param HTTPS on;
    }

    # logging
    error_log /srv/example.com/nginx/log/error.log;
    access_log /srv/example.com/nginx/log/access.log;
}

Or if you want to install the PhpLdapAdmin as a standalone application, you should create a new virtual host as follow:

$ vim /etc/nginx/sites-available/example.com
server {
    server_name example.com;
    listen 80;

    # document root
    root /srv/example.com/nginx/www;
    index index.php index.html index.htm;

    # application: phpldapadmin
    location /phpldapadmin {
            alias /usr/share/phpldapadmin/htdocs;
            index index.php index.html index.htm;
    }
    location ~ ^/phpldapadmin/.*\.php$ {
            root /usr/share;
            if ($request_filename !~* htdocs) {
                    rewrite ^/phpldapadmin(/.*)?$ /phpldapadmin/htdocs$1;
            }
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            include fastcgi_params;
    }

    # logging
    error_log /srv/example.com/nginx/log/error.log;
    access_log /srv/example.com/nginx/log/access.log;
}

And now, we can just enable the new virtual host and restart Nginx:

$ cd /etc/nginx/sites-enabled
$ ln -s ../ldap.example.com
$ /etc/init.d/nginx restart

No, this blog isn't running over nginx (yet). It's a Python (Django) application, so I want to migrate it ASAP and test a new setup based on Nginx + Gunicorn following a recomendation of Osvaldo Santana... but for now, that's all. :)

As always: if you found some english bug, warn me and I'll be glad to fix it. :)

Creating the urllist.txt with your sitemaps configuration

Tuesday, December 1, 2009 - Seven comments

In Django, you can configure the sitemap of your website using the sitemaps framework and then use this configuration to generate the sitemap.xml. Notwithstanding, the Yahoo! used to support only the urllist.txt type of sitemap and, because of that, I still use to have both (urllist.txt and sitemap.xml) available on my websites.

But, once you have your sitemap configured, why not use it to generate the urllist.txt? I created a view which generates the urllist.txt based on your sitemap configuration, as follows:

# -*- coding: utf-8 -*-

from django.conf import settings
from django.http import HttpResponse
from django.contrib.sites.models import Site

def urllist_from_sitemaps(request, sitemaps):
        urllist = []
        protocol = getattr(settings, 'PROTOCOL', 'http')
        baseurl = u'%s://%s' % (protocol, Site.objects.get_current().domain)
        for cls in sitemaps.values():
                instance = object.__new__(cls)
                for item in instance.items():
                        urllist.append(baseurl + item.get_absolute_url())
        return HttpResponse(u'\n'.join(urllist), mimetype='text/plain')

And now, you just need to configure the urls.py and add the urllist.txt entry:

sitemaps = {
    'entries': EntrySitemap,
    'tags': TagSitemap,
    'archive': ArchiveSitemap,
}

urlpatterns = patterns('',
    ...
    (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
    (r'^urllist.txt$', 'myproj.apps.myapp.views.urllist_from_sitemaps', {'sitemaps': sitemaps}),
    ...
)

And I think that is all for now...

Update 1: I submitted a patch to be added into the official Sitemaps framework of the Django. The patch is very different of the code in this post and, if you'd like to see it and its code, here it is.

As always: if you found some english bug, warn me and I'll be glad to fix it. :)

Clearing the screen with IPython

Monday, November 16, 2009 - Two comments

Some time ago I changed my default shell to use IPython instead of Bash. The IPython is a really great shell and IMHO has great advantages but for those who, like me, are completely addicted to the clear command, the IPython's clear is a huge disadvantage.

In IPython, the clear command clear varios data like input, output and directory histories but it doesn't clear the screen! You can take a look at the documentation of default function for the clear command below and see how it works:

afurlan@merlin:~$ from IPython.Extensions.clearcmd import clear_f
afurlan@merlin:~$ print clear_f.__doc__
 Clear various data (e.g. stored history data)

    %clear out - clear output history
    %clear in  - clear input history
    %clear shadow_compress - Compresses shadow history (to speed up ipython)
    %clear shadow_nuke - permanently erase all entries in shadow history
    %clear dhist - clear dir history

afurlan@merlin:~$

So I created a new function to extend the first one adding the option to clear the screen when no args were passed. If you'd like to do the same, add the following lines in your ~/.ipython/ipy_user_conf.py:

def new_clear_f(*args, **kwargs):
    ''' Extend the default clear function adding the option to
    clear the screen when no args were passed.'''
    if not args[1]:
            ip.system('clear')
    else:
            from IPython.Extensions.clearcmd import clear_f
            clear_f(*args, **kwargs)
            ip.expose_magic('clear', new_clear_f)
ip.expose_magic('clear', new_clear_f)

And now it all seems clear again. :)

As always: if you found some english bug, warn me and I'll be glad to fix it. :)

The Google's programming language

Friday, November 13, 2009 - Two comments

Some days ago Google released Go, its own open source programming language. Go is intended to be a simple, fast and safe programming language that promotes the users to write programs through concurrent and communicating lightweight processes. If want to know more about how to install and how to use Go, please take a look at its official site: http://golang.org.

Today I installed Go to play with it a little bit and (as I use to), after the world famous "hello world" code, I wrote a program to generate the fibonacci's sequence. Actually I wrote two versions of the same program, the first one is the most common fibonacci code:

package main

import "os"
import "fmt"
import "strconv"

func fib1(n int) int {
    if n < 0 { return 0; }
    if n < 2 { return n; }
    return fib1(n-2) + fib1(n-1);
}

func main() {
    if len(os.Args) < 2 {
            fmt.Printf("Usage: %s NUM\n", os.Args[0]);
            os.Exit(1);
    }
    n, _ := strconv.Atoi(os.Args[1]);
    fmt.Printf("%d\n", fib1(n));
}

And the second version is basically the same code but keeping a history of the known results:

package main

import "os"
import "fmt"
import "strconv"

func fib2(n int, hist *map[int]int) int {
    if n < 0 { return 0; }
    if n < 2 { return n; }
    _, found := (*hist)[n];
    if !found {
            (*hist)[n] = fib2(n-2, hist) + fib2(n-1, hist)
    }
    return (*hist)[n];
}

func main() {
    if len(os.Args) < 2 {
            fmt.Printf("Usage: %s NUM\n", os.Args[0]);
            os.Exit(1);
    }
    n, _ := strconv.Atoi(os.Args[1]);
    hist := make(map[int]int);
    fmt.Printf("%d\n", fib2(n, &hist));
}

Once you have finished these codes, it's always nice to see how different their execution time are:

afurlan@merlin:~$ time ./fib1 45
1134903170

real    0m43.979s
user    0m43.887s
sys     0m0.008s
afurlan@merlin:~$ time ./fib2 45
1134903170

real    0m0.004s
user    0m0.004s
sys     0m0.000s

Go is a very nice language, let's go to Go. :)

As always: if you found some english bug, warn me and I'll be glad to fix it. :)