Posted on Fri, 05 Feb 2016


Hosting your web2py application - How and where?


You have just created your first web2py application and now you would like to show it to the world. You want to post it somewhere on the internet where anyone could reach it. Now, if you’ve tried Googling "web2py hosting", you might have noticed that you receive far less results than if you had searched for "php hosting" or something similar. This is because python hosting is still in its infancy and there are still only a dozen hosting providers. I will now show you how to host your web2py application through two of those providers. The first one, pythonanywhere, is a specialized PaaS (platform as a service) python hosting provider with some ready-made solutions for easy deployment. It is very simple to deploy your application through this provider, yet it also comes with a few limitations. The second one is an IaaS (infrastructure as a service) provider called DigitalOcean through which we will purchase a virtual server and install all of the necessary software for hosting your app. It doesn't have all of pythonanywhere's limitations but it will be a little bit more complicated to set up.

 

Putting your app on pythonanywhere

Probably the easiest provider to host your web app to is pythonanywhere.com. It specifically targets python and its related frameworks such as web2py, django and some others. In the official web2py reference manual, in the chapter titled "Deploying Recipes", there is a section on how to deploy your application on pythonanywhere.com. I will reiterate the steps here for reference:

  • Create an account on pythonanywhere and log in (I presume that you would like a "Beginner" account at no monthly charge)
  • Click on "Web"

  • Click on "Add a new web app"
  • Click "Next", then click on "web2py"

  • Enter your admin password and click on "Next"

Your web2py environment is now set up and you can view it at "http://YOUR_USERNAME.pythonanywhere.com/welcome/default/index".

Next, you will need to upload your web app from your computer to pythonanywhere.com as follows:

  1. Go to your web2py dev machine (presumably at http://127.0.0.1:8000/admin/default/site) and select "Manage" and then "Pack all" on your application. Save it somewhere on disk.

  2. In order to upload your app go to https://YOUR_USERNAME.pythonanywhere.com/admin (note the https://), login with your admin password

  3. For "Upload and install packed application", "Application name", type "init".

  4. For "Upload package", select the file that you saved in step 1.

  5. You should now have your application at http://YOUR_USERNAME.pythonanywhere.com/

And that's it. Your application is live and accessible from the internet. If you want to use a database, you will need to enable mysql. Here's how to do it:

 

 

  1. Click on "databases". At this point, you will only be able to choose mysql; for postgresql you will need to upgrade your plan.

  2. Enter your mysql password (this will be the password that your application will use to connect to the database with).

  3. You can now create your database. Enter its name in the field and click on "Create".

  4. You should be able to see how to connect your application to your database in the "Connecting" section. It will show the database host address as well as your username. Once you change your db connection string in your application, it will start using the database. 

Now, if you chose the free (beginner) plan, it will only allow enough processor time and disk space to put your application up mainly for demo purposes and to show it to your teachers and/or a few of your friends. In addition, you will not be able to register a domain name for your app and you will only be able to access it through http://YOUR_USERNAME.pythonanywhere.com/. In order for your app to be accessible through any DNS record that you registered (for example, www.myapplication.com), you will need to purchase—at the minimum—their "hacker" plan for $5/month. Since you’ve reached the point where you’ll have to pay, let's see what other options are available.

 

Running your web2py app on your own server.

As easy it was to set up an app on pythonanywhere, this option still has a few disadvantages. First of all, there’s the issue of disk space. If you choose the $5/month plan, you will only receive 2GB disk space which may be enough for your application, but if you plan to upload pictures using your app, it will soon not be enough. A second (and more important) issue, is the inability to run your application with a postgresql database (which is something I would highly advise to do), which means you're left with mysql only. A better solution (albeit, a little more complicated one) would be to rent your own virtual server from one of the cloud server providers (such as linode or digitalocean) and then install and set up your own web and database server. It may sound a little intimidating at first but this little tutorial will show you how to do it.

Setting up your web2py application on a DigitalOcean server

 

After you sign in and enter your billing details, click "Create Droplet". For "Choose an image", select “CentOS”. For “Choose a size”, select the smallest one. For “Choose a datacenter region”, select the one closest to you and then type in the hostname that you chose.

 

 

 

After you've pressed the "Create" button, you will receive your host's IP address and a root password. This means that your server is up and ready. You will now need to connect to it and set up a few things. If you are using a Windows system, you will need putty (you can download it here). Type in your server's IP address and click on "Open". If you are using Mac or Linux, go to the command line and type "ssh root@YOUR_SERVER_IP" and press “Enter”. For the username, type "root" and for the password, type the password you’ve received by email. The first time you log in, you will be asked to change your password.

Now that you’ve set your new root password, it’s time to bring the system up to date:

yum -y upgrade
pip install --upgrade pip

After that, you should start the firewall service. For now, accept its default parameters and plan on configuring it later.

systemctl enable firewalld
systemctl start firewalld

 

Registering your domain name

 

Before you proceed, you need to give your server a name. Currently, it is reachable only by its IP address which is okay if you are just testing your app, but you will probably want it to be reachable by its domain name. For that, you will need to buy your domain name from any domain name provider (google "domain name registration"). It will cost you around $10 per year. Once you've bought your domain name, be sure to set up domain servers with your provider. They should be set like this:

Name server 1: ns1.digitalocean.com
Name server 2: ns2.digitalocean.com
Name server 3: ns3.digitalocean.com

 

Now that you have your domain name set up, you need to register it on digitalocean's DNS servers. Open up your digitalocean droplets page and click on dns settings.

You should add your domain name and your droplet name like this:

This has registered your domain name with your droplet (ex: mydomain.com). If you would like a domain prefix (for instance, www) to be registered with your droplet, you need to add a cname like this:

 

Now that your domain name is registered, you will probably not be able to see your server by its name immediately. In theory, it can take up to 24 hours for domain name registration to be visible everywhere on the internet. In reality, you will probably be able to access your droplet by its domain name in about half an hour or so.

Now that your domain is registered, you should log in to your server again and continue setting it up.

Setting up swap space

The next thing to do would be to set up swap space. If you’ve bought the smallest droplet (with 512MB of memory), setting up swap space on disk will speed up your server's response times because it acts as a virtual memory that the system can use when it is low on physical memory.

Swap space is, of course, using some of your system's disk space. So let's check how you stand in that regard:

df -h

You should see something like this:

Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        20G  2.0G   17G  11% /
devtmpfs        237M     0  237M   0% /dev
tmpfs           245M     0  245M   0% /dev/shm
tmpfs           245M   29M  217M  12% /run
tmpfs           245M     0  245M   0% /sys/fs/cgroup
tmpfs            49M     0   49M   0% /run/user/0

We can see that the system is using 2.0G or 11% of 20G hard disk and that we still have 17G available. We will use some of this space for our swap drive.

Create a file for the swap drive with the following command:

fallocate -l 2G /swapfile

Change its permissions so that only root can read and write it.

chmod 600 /swapfile

Now, tell the system to use this file as a swap space.

mkswap /swapfile
Setting up swapspace version 1, size = 2097148 KiB
no label, UUID=e64bf76a-2c9e-4fdb-818e-593d99a9195b

The swap file is now ready to be used as a swap space, so activate it:

swapon /swapfile

To verify that the procedure was successful, you can now check whether your system reports swap space:

swapon -s
Filename                                Type            Size    Used    Priority
/swapfile                               file    2097148 0       -1

Next, we want to make that change permanent so we'll edit the /etc/fstab file and add a line to it.

nano /etc/fstab

At the bottom of the file add the following line:

/swapfile   swap    swap    sw  0   0

The swap file is now permanent. It is time to install web2py.

 

Installing web server and web2py framework

The next step is to download the script that will install the web2py framework. Use the script that installs nginx web server:

cd~
wget https://raw.githubusercontent.com/web2py/web2py/master/scripts/setup-web2py-nginx-uwsgi-centos7.sh

Change it to “executable”.

chmod +x setup-web2py-nginx-uwsgi-centos7.sh

And now you can start it.

./setup-web2py-nginx-uwsgi-centos7.sh

You will first be asked a few questions such as where to install it, what will your web2py admin password be and what will your domain name be.

Enter username under which web2py will be installed [web2py]:
Enter path where web2py will be installed [/opt/web2py_apps]:
Web2py subdirectory will be called: [web2py]:
Enter your web2py admin password: YOUR_WEB2PY_ADMIN_PASSWORD
Enter your domain name: YOUR_DOMAIN_NAME

When this script is finished, you will have web2py installed on your server. Before you use it, you’ll need to set up a few other things. First start with taking care of security.

Installing certificates from letsencrypt.org

If you want to access web2py's admin app, you can only do this using encrypted https protocol. In our previous step, web2py's install script has created some self-signed certificates. You may use them but every browser will report a warning because there is no chain of trust that is needed for https protocol's safe use. You will now replace them with proper certificates. For that, you can use the certificate authority named letsencrypt. Their aim is to provide free certificates through an automated process. The only drawback is that it uses port 80 for its work so if you have an http server active, you’ll have to stop it for now. Later, we’ll show how it can be automated without having to stop it.

For this example, I will assume that you do not have your http server active. Also, if your server has more than one cname, you will need to get certificates for each name. You can get certificates for each of your cnames (example.com,  www.example.com) or you can have one certificate for all of your cnames. In this example I have asked for one certificate for multiple cnames; simply substitute “example.com” with your domain name.

cd ~
yum -y install git
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

At this step, it is important that you have port 80 open on your server, so if it is not already open, type the following:

firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload

It is also important to have your DNS properly configured for all of the domains that you will be asking for certificates for. Hopefully, you have configured it during the previous step (registering your domain name).

First, stop the nginx web server.

systemctl stop nginx

And now you can get your certificates (remember to change “example.com” to your real domain name).

./letsencrypt-auto certonly --standalone -d example.com -d www.example.com -d webmail.example.com

This will install additional packages, if needed, first and configure a few things. Follow the instructions on the screen

Our certificates are now stored at /etc/letsencrypt/live/example.com. These certificates are valid for three months only, so before they expire you will have to request new ones periodically.

Now you will tell your web server to use those certificates. Edit /etc/nginx/nginx.conf

nano /etc/nginx/nginx.conf

Find the section named server { listen 443; and change it to look like this (replace “example.com” with your domain name):

 server {
        listen 443;
        server_name www.example.com;

        ssl on;
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

        ssl_prefer_server_ciphers on;

        location / {
            include uwsgi_params;
            uwsgi_pass unix:/run/uwsgi/web2py.sock;
        }

You can now restart your web server:

systemctl start nginx

You should now try to access your server from the browser and if everything’s working so far, you should arrive at web2py's starting page. You should also try to access it with https protocol by typing https:// in front of your domain name. If your certificates are working, you should see a green lock in front of your address like this:

You can also test your certificate's strength here (again, replace “example.com” with your address).

https://www.ssllabs.com/ssltest/analyze.html?d=example.com&latest

With these settings (analyzing them might take a few minutes), you should at least get an A- which is a pretty good result. Your server is now firewalled and secured. But before you set up your web2py application, you should do one more important thing.

Securing your ssl login with ssh keys

If you try to log in to your server again with your root account, you will probably see something like this:

Last failed login: Mon Feb  1 05:14:25 EST 2016 from 135.132.15.226 on ssh:notty
There were 1344 failed login attempts since the last successful login.
Last login: Thu Jan 28 12:06:51 2016 from 75.125.11.153

You can see that there were probably hundreds (if not thousands) of failed login attempts. It means that there are people and automated scripts that are constantly trying to break in to your machine. They are trying to guess your password so in order to stop them you will now generate an SSH key and will tell the server to stop accepting keyless logins. First, generate a public-key, private-key pair. Your public key will be put on the server while your private key should be on your local machine and properly secured. Your private key will also be secured with a password and you will use it to log in to the server. The server will check to see if the provided private key matches the public one and if they match, you will be able to log in once you have provided the password for the keys. You can see that this provides extra security because now a password alone is not enough to log in to the server and if someone somehow manages to obtain your private key, he/she will still not be able to login without a password.

.

Now create a key pair on your local machine and transfer the public key to the server. If you use Linux or Mac, go to the terminal and type the following:

cd~
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
14:b3:80:b4:5b:03:29:18:c6:b6:d4:30:12:5e:bc:47 root@centos-7-x64
The key's randomart image is:
+--[ RSA 2048]----+
|=B+ooo. o        |
|=++ooE . +       |
|o...+ o o        |
| . . + o         |
|    o   S        |
|                 |
|                 |
|                 |
|                 |
+-----------------+

Your private key has been saved as ~/.ssh/id_rsa while your public key has been saved as ~/ssh/id_rsa.pub.

If you have a Windows machine you can generate public/private key pairs using puttygen (which you can download here)

Now that you have your keys, you need to send your public key to the server. If you use Linux or Mac, type the following:

scp ~/.ssh/id_rsa.pub root@YOUR_SERVER_ADDRESS:/root/.ssh/authorized_keys

On a Windows machine, the easiest way to transfer files is to use WinScp. You should copy your public key to the /root/.scp directory (create it if it doesn't already exist), copy the file and rename it “authorized_keys”. 

Now that you have your public key on the server, you need to give it proper permissions and instruct the ssh to not accept password-only logins.

 

Log in to the server and type the following:

cd ~/.ssh
chown 600 authorized_keys

Edit /etc/ssh/sshd_config

nano /etc/ssh/sshd_config

Find the following lines and change them as shown:

PasswordAuthentication no
ChallengeResponseAuthentication no

Restart the ssh server.

systemctl restart sshd

Now, if you try to log in to your server without the key, you should receive the following error:

Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

From now on, if you are logging in from a Mac or Linux, you must supply the public key file as shown:

ssh -i PUBLIC_KEY_FILE root@YOUR_SERVER_ADDRESSS

If you are using Windows, you need to tell putty to use the private key file. You can find it in the options tree on the left side in Connection/SSH/Auth; type in your private key file path as in the following picture:

Preparations are now over and your server is now secured. Now you can install your web2py app.

Setting up your web2py application

Start your local web2py dev server and pack your application by using "Pack All".

Go to https://www.YOUR_DOMAIN.com/admin and login to the web2py admin app (http://YOUR_DOMAIN/admin). You will need to enter the password that you set up when you installed web2py. Next, you will need to upload your packed web2py app. If you want it to be the default app, simply name it "init" like this:

After you press “install”, your web2py app should be ready. Reload your webpage and your application should respond. Remember to delete the "welcome" and "examples" apps that were installed as a part of web2py.

Installing Databases

Your application will probably need to communicate with a database. Configuring and optimizing databases is a completely different topic but for now, here are a few steps explaining how to install a database server.

Before we proceed any further, a word of caution: A database server, as any other program does, needs a certain amount of memory to work. This memory will now be shared between the database server, web server and your web2py application. If you purchased the smallest server (depending on your application), it will probably work for a few dozen hits per minute but for anything more than that you will likely need a stronger server. With that said, begin installing your database of choice.

Installing Postgresql

Type the following to install and initialize the postgresql server:

yum -y install postgresql postgresql-server
postgresql-initdb
systemctl start postgresql
systemctl enable postgresql

Now you will create a “web2py” user and a “web2pydb” database for your application.

su postgres
createuser web2py -P
Enter password for new role: YOUR_DATABASE_PASSWORD
Enter it again: YOUR_DATABASE_PASSWORD
createdb web2pydb -O web2py
exit

Now that a user has been created, you will tell the database how to authenticate it.

cd /var/lib/pgsql/data/

Edit pg_hba.conf and add the following at the end:

host    web2pydb        web2py          127.0.0.1/32            md5

You should now either restart the database to activate your changes like this:

systemctl restart postgresql

…or you can just signal it to re-read the configuration files.

su postgres
pg_ctl reload -D /var/lib/pgsql/data
exit

Either way, you can now connect to the postgresql server from your web2py application with the following command:

db = DAL('postgres://web2py:YOUR_DATABASE_PASSWORD@localhost/web2pydb')

 

Installing MySql

Type the following to install mysql server:

yum -y install mariadb-server
systemctl start mariadb
systemctl enable mariadb

Now you will create a “web2py” user and a “web2pydb” database for your application.

mysql
create database web2pydb
CREATE USER 'web2py' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON web2pydb . * TO 'web2py';
quit

You have now created a username and database for your application. Security should also be reinforced, which includes removing default and sample databases and adding a password for the root user. To do that, type the following and accept the default values:

mysql_secure_installation

You will now be able to connect to your mysql database from your web2py application using the following command:

db = DAL(mysql://web2py:password@localhost/web2pydb)

 

 

 



Log in to leave a comment