If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!


This is a guide on how to set deploy web2py on a fresh ubuntu linux VPS from slicehost.com (however will work with most Ubuntu VPS setups).

We will be setting up and configuring apache, mod_wsgi, and postgresql.

This slice is going to be more like a quickstart guide, rather than an explanation on how everything works.

Links to the related articles are provided at the bottom, in order of how to set up your slice.

You can just follow these links in order and end up with the same result.

Do refer to these articles for more information and in-depth explanation on the commands and theory behind them.

Remember, refer to the web2py book, chapter 11 for VirtualHost setup.

I also have a couple of scripts I wrote to help with this process, we will be using these during the last parts of the setup.

Links to other setups

If you want to run clustered servers with Pound:

High Availability Cluster with Pound

For web2py setup using mod_proxy

Web2py on Ubuntu with mod_proxy

A script that automates most of what is covered in this article. Minus the finer details.

Setup web2py+apache+ssl+mod_wsgi+postgresql in few seconds

For web2py on lighttpd

Low memory fooprint using Lighttpd

For web2py with Cherokee

Cherokee and Web2py


The discussion of what makes a good web2py server has been discussed, and every person has different requirements. However, the recommended way to deploy web2py is as follows. This is how we will set up our slice, using Ubuntu 9.04 Jaunty.

  • Ubuntu
  • Python 2.6
  • Apache w/ mod_wsgi
  • PostgreSQL with only local connections.

Here is a simple layout of how we will procede

  • Claim your slice
  • Secure the fort
  • Upgrade the OS
  • Install PostgreSQL
  • Create a PostgreSQL user
  • Create a database
  • Allow local database connections
  • Install mod_wsgi
  • Configure Apache
  • Install web2py
  • Configure site's VirtualHost
  • Enjoy :)


This article will use a fake IP address of 123.456.789.012 for the slices public IP and for its private slice-to-slice IP. The slice's hostname is sliceserve. Our main admin user will be called myself, and our database will be named mydata. Be sure to replace these with your actual information as it retains to your slice. $ means your local machine, @$ means your slicehost server.

Claim your slice

So first this first, if you have not already claimed your slice, go get one now!

Secure the fort

# use the password provided by slicehost. change it.
$ ssh root@123.456.789.012 
root@$ passwd 
root@$ adduser myself
root@$ export EDITOR=nano
root@$ visudo
# add this to the end of the file
# myself   ALL=(ALL) ALL
root@$ exit
$ ssh-keygen -t rsa
# fill everything out correctly
$ scp ~/.ssh/id_rsa.pub myself@123.456.789.012:/home/myself/
$ ssh root@123.456.789.012
root@$ mkdir /home/myself/.ssh
root@$ mv /home/myself/id_rsa.pub /home/myself/.ssh/authorized_keys
root@$ chown -R myself:myself /home/myself/.ssh
root@$ chmod 700 /home/myself/.ssh/
root@$ chmod 600 /home/myself/.ssh/authorized_keys
root@$ nano /etc/ssh/sshd_config

Be sure to check the following options.

Port 30000                           <--- change to a port of your choosing
Protocol 2
PermitRootLogin no
PasswordAuthentication no
X11Forwarding no
UsePAM no
UseDNS no
AllowUsers demo

Now we set up iptables.

root@$ iptables -L
# Yuck, we're allowing everything
root@$ wget wget http://articles.slicehost.com/assets/2007/9/4/iptables.txt
root@$ nano iptables.txt
# Make sure to change the port for ssh!!!!
root@$ mv iptables.txt /etc/iptables.up.rules
root@$ iptables-restore < /etc/iptables.up.rules
root@$ iptables -L
# much better, now make it permanent
root@$ nano /etc/network/interfaces

Add the line below

auto lo
iface lo inet loopback
pre-up iptables-restore < /etc/iptables.up.rules

# The primary network interface

Good, reload ssh

root@$ /etc/init.d/ssh reload

go test your connection on another terminal

ssh -p 30000 myself@123.456.789.012

if you get in, your good.

Slicehost also has the excellent ajax console so if it all goes horribly wrong, you can log into your slice from the Slicehost management area.

For now on we will be using myuser to do everything.

Basic information / Upgrades

See link 2

Upgrade your system, set your locale (setting locale is required for postgresql)

@$sudo apt-get update
@$sudo apt-get upgrade
@$sudo apt-get build-essential  #optional
@$ sudo locale-gen en_US.UTF-8
@$ sudo /usr/sbin/update-locale LANG=en_US.UTF-8

Install PostgreSQL

@$ sudo apt-get install postgresql
@$ sudo apt-get install python-psycopg2

Note, port 5432 is default postgresql port, this should change

Configuring PostgreSQL

@$ sudo nano /etc/postgresql/8.4/main/postgresql.conf

Find and uncomment/change these lines

track_counts = on
autovacuum = on                      # Enable autovacuum subprocess?  'on'

This provide some automatic maintenance of our databases, to help keep them running smoothly

sudo /etc/init.d/postgresql-8.4 restart

sudo su - postgres
postgres@$ createuser -PE myself
#answer no to superuser, create db, and create role.
postgres@$ createdb -O myself -E UTF8 mydata
postgres@$ exit
sudo nano /etc/postgresql/8.4/main/pg_hba.conf

Find this part


# "local" is for Unix domain socket connections only
local   all         all                               ident sameuser

Change the line to read

local   all         all                               md5

Restart and test

sudo /etc/init.d/postgresql-8.4 restart
#test it
psql -U myself -d mydata
#ctrl+d to exit

Securing PostgreSQL

sudo nano /etc/postgresql/8.4/main/postgresql.conf

Find this part

# - Connection Settings -

#listen_addresses = 'localhost'         # what IP address(es) to listen on;
                                        # comma-separated list of addresses;
                                        # defaults to 'localhost', '*' = all
                                        # (change requires restart)
port = 5432                             # (change requires restart)

Uncomment listen_addresses, and change the port number. I will use 40000

sudo /etc/init.d/postgresql-8.4 stop
sudo /etc/init.d/postgresql-8.4 start

If all you are wanting is local connections, this is all you need to do. Refer to link 9 for TCP connections. Also refer to link 9 for connecting from clients with dynamic IP. Refer to link 10 for port change, and tightening up iptables and security.

Installing Apache/mod_wsgi

Install Apache

sudo apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert

sudo nano /etc/apache2/apache2.conf

Append to the end

ServerName myslicename # or FQDN

Restart and test

sudo apache2ctl graceful

Navigate to your slice ip, if you see It Works! everything is good! Yay

Lets make some tweaks to the apache configuration. Refer to link 16 for more info.

sudo nano /etc/apache2/ports.conf

Add NameVirtualHost *:443 under NameVirtualHost *:80

NameVirtualHost *:80
NameVirtualHost *:443
Listen 80

<IfModule mod_ssl.c>
    # SSL name based virtual hosts are not yet supported, the$
    # NameVirtualHost statement here
    Listen 443

Ok, just some simple requests to help web2py run even smoother

sudo /etc/apache2/apache2.conf

Look into changing these

Timeout 300 -> 45
KeepAlive On
MaxKeepAliveRequests 100 -> 200
KeepAliveTimeout 15

Install mod_wsgi

sudo apt-get install libapache2-mod-wsgi
sudo /etc/init.d/apache2 restart

Install web2py and configure your sites <VirtualHost>

Read link 13 to get an overview on apache virtualhost locations.

Basically, VirtualHost configurations live in /etc/apache2/sites-available

Laying out your site directories is another controversial topic.

This is the layout we will be using, you can modify to suit your own needs. I find it very logical.

* /etc/apache2/sites-available -> VHOST config
* /home/myself/sites/ -> Site directory
* /home/myself/sites/domain.com/public -> httpdocs
* /home/myself/sites/domain.com/subdomains -> subdomains for domain
* /home/myself/sites/domain.com/subdomains/blog/{public, sudomains, etc...}
* /home/myself/sites/domain.com/public/web2py -> svn web2py release
* /home/myself/sites/domain.com/public/app -> simlinked to web2py/applications/init

We will also be using some scripts that I wrote to help rapidly create web2py sites/configurations.

You can download them, look at them and run the commands yourself for learning.

sudo apt-get install subversion
cd ~
mkdir sites
wget http://static.thadeusb.com/code/makesite.txt
wget http://static.thadeusb.com/code/apache_web2py_virtualhost.txt
mv makesite.txt makesite.sh
mv apache_web2py_virtualhost.txt apache_web2py_virtualhost.py
nano makesite.sh

Make sure to replace {USERNAME} with your usename...

chmod +x makesite.sh
cd sites
~/makesite.sh domain.com web2py

Specifying the web2py will download the latest web2py svn commit and set up a working web2py environment with correct permissions

Now we are ready to upload our web2py application.

Make sure you set your database correctly

db = DAL('postgres://myself:mypass@localhost:40000/mydata')

Upload your web2py application to /home/myself/sites/domain.com/public/app/

Make directories needed by web2py writeable by apache.

cd domain.com/public/
chown -R myself:www-data app
chmod -R 755 app
cd app
chmod -R 775 cache cron databases errors sessions uploads languages

Now that our web2py instance is ready, we need to create a VirtualHost.

First, go make yourself a self-signed SSL certificate, read link 17, you will need this for admin/appadmin access.

sudo make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/ssl/certs/selfsigned.pem

cd ~
nano apache_web2py_virtualhost.py

Edit variables as to your needs. The file is pre-configured for what I used on surrenderthebooty.thadeusb.com.

If everything looks good, create the virtualhost config, enable SSL, enable the site, restart apache (you must stop/start)

sudo python apache_web2py_virtualhost.py
sudo a2enmod ssl
sudo a2ensite {{SITENAME FROM CONFIG}} # sudo a2ensite surrenderthebooty
sudo /etc/init.d/apache2 stop
sudo /etc/init.d/apache2 start

Head over to http://domain.com/ and you should be in business

Admin https://domain.com/admin

Appadmin https://domain.com/init/appadmin

1 Securing your slice

2 Customizing and getting RAM information

3 Install PostgreSQL

4 PostgreSQL Overview

5 Connect to postgres as superuser

6 Create and Delete roles(users)

7 Create and Drop databases

8 Making local connections

9 Allowing TCP connections

10 Tighten PostgreSQL security (listening addresses, ports)

11 Installing Apache

12 Installing mod_wsgi

13 Apache Configuation layout (VirutalHost etc) -> This is where the <VirtualHost> delcarations from the book would go.

14 Apache Configuration #1

15 Apache Configuration #2

16 Django specific article about mod_wsgi, but a good read

17 Creating a self signed SSL certificate

Related slices

Comments (5)

  • Login to post

  • 0
    johannspies 11 years ago
    I have no success trying these links: http://static.thadeusb.com/code/makesite.txt and apache_web2py_virtualhost.txt

  • 0
    thadeusb 11 years ago
    I am really sorry, since my dreamhost account expired I have been having issues with this. Try port 50002 for now. static.thadeusb.com:50002/code/makesite.txt static.thadeusb.com:50002/code/apache_web2py_virtualhost.txt

  • 0
    thadeusb 11 years ago
    As a note, do edit makesite.txt as it uses the old SVN versions of web2py instead of the new Mercurial. I am unable to upload the fixed script until later this evening.

  • 0
    russell 11 years ago
    Hey Thadeus, Thanks for taking the time to list out all the steps. Quite helpful. However, it appears that the links to your scripts (http://thadeusb.com/code/makesite.txt and http://thadeusb.com/code/apache_web2py_virtualhost.txt) are dead. Thanks Russell

  • 0
    thadeusb 11 years ago
    Sorry, the correct links are http://static.thadeusb.com/code/makesite.txt and apache_web2py_virtualhost.txt

Hosting graciously provided by:
Python Anywhere