Set up 'Power' framework.

Power is a micro framework which wraps Tornado to make it easy to write a web application using Tornado. Power is refined from the common components of which is an open source web site to show a project(eg.Python, Tornado) powered sites.

The source code is coming soon, it will be opened at

Felinx Lee   September 12, 2010

How to setup Nginx

Install(in ubuntu)

sudo apt-get install nginx

Main configuration

# update default configuration
sudo nano /etc/nginx/nginx.conf

# /etc/nginx/nginx.conf

# user and group to run as
user       www-data www-data;

# number of nginx workers
# the same as the core numbers
worker_processes  2;

error_log  /var/log/nginx/error.log;
pid        /var/run/;

worker_rlimit_nofile 8192;
events {
    # Number of worker connections. 2048 is a good default
    worker_connections  2048;
    use epoll;

http {
    upstream frontends {

    server_tokens on;

    # pull in mime-types.
    include  mime.types;

    # set a default type for the rare situation that
    # nothing matches from the mimie-type include
    default_type application/octet-stream;

    access_log  /var/log/nginx/access.log;

    gzip on;
    gzip_min_length  1024;
    gzip_buffers     16 8k;   
    gzip_http_version 1.1; 
    gzip_comp_level  2;
    gzip_types       text/plain text/css application/x-javascript text/xml 
                        application/xml application/xml+rss text/javascript;
    gzip_vary on;

    sendfile     on;
    tcp_nopush   on;
    tcp_nodelay  on;

    keepalive_timeout  60;

    client_max_body_size    10m;
    client_body_buffer_size 256k;

    # proxy settings
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Scheme        $scheme;
    proxy_connect_timeout   90;
    proxy_send_timeout      90;
    proxy_read_timeout      90;
    proxy_buffers           32 8k;

    include /etc/nginx/sites-enabled/*;

A site's configuration(For

sudo nano /etc/nginx/sites-enabled/poweredsites.conf

# /etc/nginx/sites-enabled/poweredsites.conf
server {
    listen   80;
    access_log  /var/log/nginx/poweredsites.static.log;

    location / {
        root /mnt/ebs/sites/poweredsites/poweredsites/static/;
        if ($query_string) {
            expires max;

server {
    listen   80;
    access_log  /var/log/nginx/poweredsites.access.log;

    location / {     
        proxy_pass http://frontends;

server {
    listen   80;
    server_name  *;
    access_log  /var/log/nginx/poweredsites.access.log;

    # permanent redirect to
    if ($host ~* ^www\.(.*)$) {
        set $domain $1;
        rewrite ^(.*)$ http://$domain$1 permanent;

    location / {     
        proxy_pass http://frontends;
Felinx Lee   August 27, 2010

How to setup MongoDB

Download and install

$ curl > mongo.tgz
$ tar xzf mongo.tgz

Create a data directory

# create default data directory
$ mkdir -p /data/db/
# Grant permission for user-xxx which is the user to run mongodb process
$ chown user-xxx /data/db

Run MongoDB

$ ./mongodb-xxxxxxx/bin/mongod

You should run it with --dbpath parameter like below if data directory is not /data/db/

$ ./mongodb-xxxxxxx/bin/mongod --dbpath=/mnt/ebs/data/mongodb

Add database users

$ ./mongodb-xxxxxxx/bin/mongo
# add a admin user 
> use admin
> db.addUser("admin", "adminpassword")
# add user for poweredsites database
> use poweredsites
> db.addUser("felinx", "felinx")

# show users
> db.system.users.find()

For detail information please refer to the official documentation:

Felinx Lee   August 27, 2010

How to setup MySQL

Install(in ubuntu)

apt-get install mysql-server libmysqlclient15-dev

Create user and database

# login as root at first
mysql -u root -p

# create a user and set password
mysql> create user 'your-name'
mysql> upadte user set password=PASSWORD('your-password') where user='your-name';
mysql> flush privileges;

# grant user's privileges for local access
mysql> grant all privileges on *.* to your-name@"localhost" identified by "your-local-password";

# grant user's privileges for remote access(optional)
mysql> grant all privileges on *.* to your-name@"%" identified by "your-remote-passwd";
mysql> flush privileges;

# show users
mysql> select * from user;

# create database
mysql> create database your-database

Charset(UTF-8) and storage engine(INNODB)

# modify default settings
nano /etc/mysql/my.cnf

# add below settings to my.cnf

# The default character set that will be used when a new schema or table is
# created and no character set is defined

# The default storage engine that will be used when create new tables

Change default data path(Optional)

eg. change default data path from /var/lib/mysql to /mnt/ebs/data/mysql

# copy data files,copy with -p to preserve folder's attibutes
cp -r -p /var/lib/mysql/ /mnt/ebs/data

# change mysqld's apparmor, make sure data path correct everywhere.
nano /etc/apparmor.d/usr.sbin.mysqld

# modify old path to new's
#/var/lib/mysql r,
#/var/lib/mysql/** rwk,

/mnt/ebs/data/mysql r,
/mnt/ebs/data/mysql** rwk,


/etc/init.d/apparmor restart
/etc/init.d/mysql restart

Check charset setting

# execute it in mysql console or any mysql client tools
show variables like '%char%';

Remote access(Optional)

nano /etc/mysql/my.cnf
# comment bind-address in my.cnf, and grant privilages for remote access(Refer 
# to create user section)

#bind-address =

Access issue

Some guys may get ERROR 1045 (28000) when they try to login MySQL as root at first time, Error message like "Access denied for user 'root'@'localhost' (using password: YES)". You can use reserved debian-sys-maint user to login in ubuntu or debian:

mysql -u  debian-sys-maint -p
# enter password in /etc/mysql/debian.cnf
# then update root's password
mysql> upadte user set password=PASSWORD('new-password') where user='root';
mysql> flush privileges;
Felinx Lee   August 27, 2010

How to run poweredsites in local

Here is the steps to run poweredsites project in a local ubuntu

Python2.6 ENV

Please run commands in this section to make sure all libs are ready:

# install git to sync tornado source code, and build tools etc
sudo apt-get install git-core gcc make build-essential

# python basic tools
sudo apt-get install python-setuptools python2.6-dev

# third party libs 
sudo apt-get install python-pycurl python-mysqldb

sudo easy_install -U pymongo markdown beautifulsoup
                webhelpers formencode routes decorator

# tornado
git clone git://
# And go to tornado folder run
sudo python install


  • Please refer to How to setup MySQL and How to setup MongoDB to setup MySQL and MongoDB

  • add database poweredsites and user:felinx password:felinx to mysql and mongodb,of course, you can use your username and password, then change the project configuration.

  • import the schema in the repository to your mysql (poweredsites/conf/schema.sql)

Modify local Hosts

Mapping some subdomains to local machine, you can add more for testing:

sudo nano /etc/hosts

# /etc/hosts


Proxy requests to localhost:8888(Apache or Nginx as your wish) Here is a Nginx exmaple, please refer to How to setup Nginx to setup nginx. The default port 80 will be conflict with apache2 if you already install apache2. If so, stop your apache2 or change apache2 listened port to another one.


Yes, I hardcode something :(, I will refine that later.

  • put a symbol link or copy poweredsites/poweredsites/poweredsites.conf to /mnt/ebs/conf/sites/poweredsites.conf

  • Sync project root to /mnt/ebs/sites/poweredsites, then the layout of those files will like below.


Run the app:

# setup mongodb index at the first time
python /mnt/ebs/sites/poweredsites/poweredsites/ --setup_db=1

# Run this one in normal, or run the upper one always.
python /mnt/ebs/sites/poweredsites/poweredsites/

# for short
cd /mnt/ebs/sites/poweredsites/poweredsites/

Then the app will be run at port 8888, type in your browser to play with it. Use CONTROL + C to Quit the app.

Well done, congratulations, Have fun!

Felinx Lee   August 14, 2010

PoweredSites 1.0 release

I am very proud to announce the 1.0 release of after two week's beta online testing.

Thank Bret and Ben for the great Tornado project.

Thank those guys who have given me good feedbacks which help me a lot to improve this site.Thank every one who has submitted sites or projects to PoweredSites.

At last, I need thank James Zhang who help me setup up the Amazon instance and draft site's Terms and Privacy Policy, he also gave me some good suggestions.

Let's cheer the official 1.0 release of PoweredSites.

Felinx Lee   August 13, 2010

Refactoring poweredsites complete.

  1. Remove some features(, wiki) to keep poweredsites simple and easy to use, focus on listing a project or service powered sites.

  2. List latest sites at home page, and move old version home page to project main page. So, it's easy to understand what is this site's main theme.

  3. Add top sites list(order by page view and page rank etc.)

Felinx Lee   August 12, 2010

PoweredSites feeds are available

PowerdSites' site feeds and blog feeds are available now, you can subscribe them with your favorite reader, cheers.

Felinx Lee   August 7, 2010

Powerful in-house caching system is enabled

PoweredSites' in-house caching system has been enabled, generally, the performance is boosted over 50 times in the server side.For example, it will only take 2ms to render the homepage from cache if cache is enabled and is not expired, or it need do more database queries and templates rendering, so it will take about 170ms.

The caching system can be used to cache

  1. A whole web page
  2. An UIModule
  3. A normal functional in handler or UIModule.

There are three cache decorators:

  1., cache a whole web page to MonogoDB. It is just used to decorate SUPPORTED_METHODS (eg. get and post) in a handler.
  2. cache.cache, cache a functional or UIModule(render functional in a UIModule) to MonogoDB.
  3. cache.mem, cache a functional or UIModule to Python dict in memory. It just be used for caching some data which are seldom changed but the data are used frequently.

How to use them, let's see the cache arguments at first.

def cache(expire=7200, condition="", key="", anonymous=False):
    """Decorator which caches the value of a method in a handler or a module.

    expire: Cache will be expired time from now in seconds.
    condition: If the result of sql condition has changed, then cache expired. 
    key: The unique key of the cache identify in the DB, it will auto generate 
         one if it not be set

    cache_pre: A method which is defined in self(handler or module), 
                it always be executed before cache or get from cache.

    cache_condition: A property which is defined in self(handler or module), it
                is used to construct a complex condition.
    def wrapper(func, self, *args, **kwargs):
        # caching

Then let's show the power in some examples:

  • cache a whole page

    class IndexHandler(BaseHandler):
        def get(self):                
  • just cache for anonymous user

    class IndexHandler(BaseHandler):
        def get(self):                
  • cache a functional

    class IndexHandler(BaseHandler):
        def do_complex_query(self):
            # do time cosuming queries and return the values
            self.db.query("complex query 1")
            self.db.query("complex query 2")           
            return "query resluts"
  • cache an ui_module

    class IndexModule(UIModule):
        def render(self):
  • cache to memory

    class TomemModule(UIModule):
        def render(self):
  • cache with condition checking

    class IndexHandler(BaseHandler):
        # The cache will expired immediately if the count(*) has changed, 
        # for example a new blog is posted, so the cache is very dynamic."select count(*) from entries")
        def get(self):               
  • cache with a complex condition and do some cache_pre operations

    class IndexHandler(BaseHandler):
        def cache_condition(self):
            # It will try to use this property as cache condition if no condition
            # argument. You can construct a complex condition here as your wish.
            return str("select updated from entry where id = %s" % self.entry_id)
        def cache_pre(self, entry_id):
            # It always will be executed before `get` or `post` and cache_condition, 
            # it has the same arguments as `get` or `post`.
            # You can do something here before try to get the cache.
            self.entry_id = entry_id
            # Do cache_pre operations
            # eg. update the click count of this entry
        def get(self, entry_id):            

Please refer to the source code for more detail information.

Felinx Lee   August 6, 2010

Now, you can edit your sites information after submitted them.

There is an edit link beside site name in your site detail information page.

Click it, then you can re-edit your site information again, eg. modify site's logo or description.

Besides, I also update chat channel, there is a link for the author of a message, and list the latest messages at chat home page.

Fix textarea display error when submit a site or project failed.

Felinx Lee   August 5, 2010

PoweredSites beta online.

I am very pleased to announce the beta release of

What powered sites?

We are always curious about that when we navigating exciting sites. PoweredSites is a good site to share with others about a project or service powered sites, eg. jQuery powered sites, Torando powered sites. PoweredSites is also a good place to show your project's power if you are a project owner.

PoweredSites source code is opened to the community under Apache License V2, the source code is available at, it's develop by python and tornado. I opened everything except the OpenID API key:), so you can setup a web site using the code easily.

Currently, twitter,facebook,friendfeed openid login are no well tested because those web sites are blocked in China. And some of features are still under developing, eg. re-edit a project or site and wiki for every project.

I hope that you will enjoy the site and the source code. I hope some guys can join me to make the site better.

Please don't hesitate to submit your projects or submit web sites to

And any bug reports are welcome.

Felinx Lee   August 3, 2010