Sunday, August 25, 2013

How to Setup a Tornado Server, with Web Sockets Support, on Production, Behind NGINX


Ubuntu 13.04, Digital Ocean



I am not an expert on servers setup, so if you see anything I could have done better please leave a comment and I'll try it out on my server and improve this tutorial. So far this setup works very nice for me. Ok, let's get this started.

Step 1 - Create User

First things first, let's ssh into the server and because this is the first time, i will do it as a root user:

$ ssh root@<your server ip>


Say yes to continue connecting, enter your password and we are in.

On Digital Ocean, the password that you will receive is a default and therefore, first thing, we need to change that:

$ passwd

Next thing, i will create a user for myself:

$ adduser dev

Define new password for the user and you can leave everything else blank or fill it in, as you wish.
Next step is to give my new user root privileges:

$ visudo

Find the section called 'User privilege specification', it will look something like this:

# User privilege specification
root ALL=(ALL:ALL) ALL

under it add your user, granting all root privileges:

dev ALL=(ALL:ALL) ALL

Enter Cntr x to exit and save the file.

Step 2 - Configure SSH

Although this step is optional, it is very much advisable to do this for security reasons. 
Caution! Misplacing following information can bar your entrance from your own server!
That said, we are all grown people and if you can't keep your login creds secure and in mind(or securely backed up somewhere), then this is no business for you.

Open the configuration file:


$ nano /etc/ssh/sshd_config

Find the following sections and change the information as follows:


Port 5050
Protocol 2
PermitRootLogin no


1. Port -  default is 22. You can change this to anything between 1025 and 65536. Whatever you choose, remember it (!) you will use it to login in the future. 
2.  PermitRootLogin - change this form 'yes' to 'no'. This will disallow root login. From now on, you will be able to login with your user only. I also found out, that on Digital Ocean, you will still be able to login with root user through a terminal on digitalocean.com.

Next, add following lines at the bottom of the config file:


UseDNS no
AllowUsers dev


AllowUsers will allow only this users to login to the server. Don't forget to substitute 'dev' for whatever you called your user.

Finally, reload the ssh to make the changes take effect:


$ reload ssh


To test this, open new terminal and try to login with your user this time:


$ ssh -p 5050 dev@<your server ip>


If something went wrong and your root access terminal was closed and you can't login with your user, you can go back to digitalocean.com and login with root using their terminal and go over the sshd_config file, fixing whatever might have gone wrong.

Step 3 - Setup SSH Login to Server

Creating a new user for yourself, and a new password, both for root and your new user, and preventing root login access, and changing the port, and defining allowed users to login to the server, is all very well and good...BUT! There is always a but ;) Your password can still be very well cracked by brute force attack. Here come into picture SSH keys that are nearly impossible to guess by brute force alone.

Make sure that you have a .ssh/ (chmod 700) folder under /home/dev/ (a.k.a ~ ) on your server and chmod 600 for .ssh/* (for all files inside). And now let's make our server even more secure, and easier to access from your computer, by creating a pair of ssh keys.

On your computer


$ ssh-keygen -t rsa
$ Enter file in which to save the key (/demo/.ssh/id_rsa): ~/.ssh/tornado_server_rsa
$ Enter passphrase (empty for no passphrase): 


I usually leave this empty, so hit enter.
Now let's add this key to the list of known identities:


$ ssh-add ~/.ssh/tornado_server_rsa


Verify that it went ok:


$ ssh-add -l


Should show the new key.
At this point you should have a pair of public/private keys for your server. What is left is to pass the public key to the server. 2 ways to do this.
First:


$ ssh-copy-id dev@<server ip>


Second:


$ cat ~/.ssh/tornado_server_rsa.pub | ssh -p 2012 dev@<server ip> ''cat >> ~/.ssh/authorized_keys''


No matter what you chose, in both cases you should see some communication going on, asking you if you are sure you want to continue connecting and such. The usual ssh stuff.

After this step you should be able to login to your server using ssh keys without the prompt for password. A much more secure and easier way.


Step 4 - Installing Necessary Packages


$ sudo apt-get install python-setuptools libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev build-essential git-core git nginx keychain



$ sudo easy_install pip
$ sudo pip install tornado
$ sudo pip install supervisor


Setting up keychain (optional)

This step is good if you keep the code under your /home folder.
What keychain does for us is help us manage our ssh keys. It drives both ssh-agent and ssh-add, and can maintain a single ssh-agent process across mutliple login sessions. It means that you will have to enter your passphrase only once each time your machine is booted.

Add following to your .bashrc:


#####################################################################################
### The --clear option make sure Intruder cannot use your existing SSH-Agents keys
### i.e. Only allow cron jobs to use password less login
#####################################################################################
/usr/bin/keychain --clear $HOME/.ssh/*_rsa
source $HOME/.keychain/$HOSTNAME-sh




If you didn't create .bash_aliases file yet, now is the time to do so:


$ touch ~/.bash_aliases
$ nano ~/.bash_aliases


Add following lines to the file:


alias ssh='eval $(/usr/bin/keychain --eval --agents ssh -Q --quiet ~/.ssh/*_rsa) && ssh'


This checks to see if keychain is runnig and if not starts it, adding all your rsa keys under .ssh folder.


alias git='eval $(/usr/bin/keychain --eval --agents ssh -Q --quiet ~/.ssh/*_rsa) && git'


Why aliases?
Keychain is tacking itself to every command you might need to use keys. In our case ssh and git. First time you run those command, you will enter the passwords and for afterwards keychain will do this for you.

Step 5 - Get the Code

Pulling the code from Github is much easier done by ssh. So, let's create a pair of keys to use with git. 


$ sudo ssh-keygen -t rsa


Enter a passphrase if you want, otherwise hit enter.
I usually save the keys in named files:


$ Enter file in which to save the key (/demo/.ssh/id_rsa): ~/.ssh/github_rsa


Why sudo ssh-keygen? Because i'm going to save the code under /srv/ folder which is accessible for write only to root users, therefore usual 'git clone' will not work. You can create an ssh key without sudo, but then it won't work with 'sudo git clone' that you will have to use to pull the code.

Now let's create a folder that will hold the code:


$ sudo mkdir /srv/www
$ sudo mkdir /srv/www/myapp


Go to the folder that will hold the code, in my case that is myapp/ :


$ cd /srv/www/myapp
$ sudo ssh-agent /bin/bash
root@server$ git clone git@....

Cntr+d to exit.

Step 6 - Setup NGINX

Create a user for nginx:


$ sudo adduser --system --no-create-home --disabled-login --disabled-password --group nginx
$ sudo nano /etc/nginx/nginx.conf


Configure the file according to this gist.

The server configuration, under http {}, you can alternatively add to 
/etc/nginx/sites-available/myapp (you will have to create it first), then run:


$ sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp


In both cases, delete default server block:


$ sudo rm -r /etc/ngingx/sites-enabled/default


Step 7 - Configure Supervisor

Supervisor will help you keep your tornado server running.


$ sudo mkdir /etc/supervisor/conf.d/tornado.conf
$ sudo nano /etc/supervisor/conf.d/tornado.conf


Inside this file add following lines:


[program:tornado-8001]
command = python /srv/www/myapp/app.py --port=8001
stderr_logfile = /var/log/supervisor/tornado-stderr.log
stdout_logfile = /var/log/supervisor/tornado-stdout.log 
autostart = true
autorestart = true


[program:tornado-8002]
command = python /srv/www/myapp/app.py --port=8002
stderr_logfile = /var/log/supervisor/tornado-stderr.log
stdout_logfile = /var/log/supervisor/tornado-stdout.log 
autostart = true
autorestart = true

[program:tornado-8003]
command = python /srv/www/myapp/app.py --port=8003
stderr_logfile = /var/log/supervisor/tornado-stderr.log
stdout_logfile = /var/log/supervisor/tornado-stdout.log 
autostart = true
autorestart = true

[program:tornado-8004]
command = python /srv/www/myapp/app.py --port=8004
stderr_logfile = /var/log/supervisor/tornado-stderr.log
stdout_logfile = /var/log/supervisor/tornado-stdout.log 
autostart = true
autorestart = true


Cntr+x, save and exit the file.
Make sure that all log file directories exist, if need be create them.

Step 8 - Start NGINX and Supervisor


$ /etc/init.d/nginx start
$ sudo supervisord


To validate that your app is up and running, access your domain. If you only see nginx default template, then something is wrong in your nginx configuration and nginx is not forwarding the requests to your app. In that case, check nginx error log and tornado-stderr.log.



No comments:

Post a Comment