⬆️ ⬇️

Deploying the site to Django using FastCGI

From translator



I read this article on Django Advent, Django 1.2, timed to coincide with the imminent release, and it seemed so interesting to me that I decided to translate it. Further, the text of the article.



When you develop a site on Django, it is so easy to just open the console and type:



python manage.py runserver



With this simple command to manage your media files, admin site is supported correctly, PYTHONPATH is properly configured and includes the root folder of our project, and an automatically restarting web server is running on the port we specified (from the translator: port 8000 by default). So simple!

')

It is not surprising that people are so disappointed when it comes time to put their website on the battle server: there are so many steps in this process and therefore it’s difficult to learn all of them and make everything right. Not surprisingly, all this complexity leads to the fact that many articles have been written about the deployment of the Django website. But almost all of these articles focus on deploying the site using Apache and mod_wsgi or mod_python .



However, sometimes Apache is not the perfect solution. Maybe your VPS has only 256 MB of memory, and maybe you want to avoid the complexity of configuring Apache during installation. Or maybe you just do not like Apache. For any of these reasons, we can turn our attention to FastCGI .





First of all



Before we begin our deployment, we need to make sure that the foundation of our system is established. First, we need a server on which we deploy our application. It can be any server and operating system, but for the sake of simplicity, we assume that it is Ubuntu Linux.

Let's install the base system, including some compilers, python header files and setuptools



sudo apt-get install build-essential python-dev python-setuptools



We also put Nginx as our web server. This can be done like this:



sudo apt-get install nginx



You should also put daemontools - a collection of tools for managing services. We will use them to make sure that our services will remain running (or at least come back to life) even in the event of an error or a restart of the server. To install daemontools type:



sudo apt-get install daemontools



Unfortunately, the daemontools package requires our little extra work to automatically restart on reboot. First, create the file /etc/event.d/svscanboot with the following contents:



start on runlevel 2

start on runlevel 3

start on runlevel 4

start on runlevel 5

stop on runlevel 0

stop on runlevel 1

stop on runlevel 6

respawn

exec /usr/bin/svscanboot




Then create the /etc/service folder by running the following command:



sudo mkdir /etc/service



daemontools , run daemontools by running this command:



sudo initctl start svscanboot



Let's create a new user for our site:



adduser mysite



If we want to use the sudo command with our user, then we also need to edit /etc/sudoers . Find the root ALL=(ALL) ALL line root ALL=(ALL) ALL in this file and add below it:



mysite ALL=(ALL) ALL



Now we can switch to our user:



su - mysite



So, the basis of our system is ready. We deliberately do not talk about the database, mail servers, version control systems, memcached and other various services, because they can vary greatly depending on personal preferences.



Setting up our virtual environment for Python



Now that the foundation of our system is established, we can focus on interesting things. First, we are going to put virtualenv - a tool for creating an isolated environment for Python. We will use virtualenv to create an isolated environment for our application.



sudo easy_install virtualenv



With our fresh copy of virtualdev, we can go ahead and set up a new virtual environment:



mkdir ~/virtualenvs

virtualenv ~/virtualenvs/mysite




We created a virtualenvs directory in our home folder and inside it we created a virtual environment called mysite. Now let's start using it and install pip to easily install Python packages:



source ~/virtualenvs/mysite/bin/activate

easy_install pip




Now we need to make sure that we have the Flup package installed . This is a set of useful tools for working with WCGI applications, including an adapter to turn a WSGI application into FastCGI (both SCGI and AJP ... but this is beyond the scope of this article). Django requires Flup to be installed before you can use the runfcg control command. Using pip we can easily install it:



pip install flup



If we want to use database adapters, graphic libraries or xml parsers installed along the Python system path, we need to make sure that they are accessible from our virtual environment. To do this, we add the .pth file to the site-packages virtual environment directory:



echo "/usr/lib/python2.6/dist-packages/" > ~/virtualenvs/mysite/lib/python2.6/site-packages/fix.pth



The next step is to clone the Django code on our server (obviously, git can be replaced with mercurial, svn or even rsync ):



git clone github.com/myusername/mysite.git



If your project has a pip requirements file, you can now use it:



pip install -U -r mysite/requirements.txt



Or, if you do not have the requirements file , you can install the dependencies manually. For example:



pip install -U Django simplejson python-memcached



Choosing options for our FastCGI server



Wow We have come a long way in setting up our system and have not even told us about the FastCGI part yet. Do not worry, we are ready to do it now. Let's decide what options we want when we run our FastCGI server.



The first choice that needs to be made is which parallelization method we want to use:



Let's assume that we are interested in FastCGI, because we have a server with a small memory size. Since the prefork method will use more memory, we will therefore choose the threaded method.



Now we will select several options that tell the server how to act under load:



Our server runs on a small VPS with 265 MB of memory, so we will choose very modest settings: 2 for

minspare , 4 for maxspare , 6 for maxchildren and 500 for maxrequests .



At the end we choose our last few settings:



After we have made our choices, we can start the server by running the runfcgi command:



python manage.py runfcgi method=threaded host=127.0.0.1 port=8080 pidfile=mysite.pid minspare=4 maxspare=30 daemonize=false



Notice that we added the daemonize=false flag daemonize=false . It should always be installed (according to the author, skipping this option is a miscalculation in the runfcgi command). Also note that the result of running this command will create a mysite.pid file in our project directory, so it's a good idea to make sure that your version control system ignores this file.



Now that we have verified that our FastCGI server is running correctly, let's stop it and proceed to the next step: use daemontools to run this command and keep the server running all the time in the background.



Daemontools runs our fastcgi server



Daemontools will look in all the subdirectories in the / etc / service directory and in each of them it will look for an executable file called run. If he finds such a file, he launches it and restarts it if he dies. So let's create a mysite directory:



sudo mkdir /etc/service/mysite



Now, let's make a small script that runs our fastcgi server. Use your favorite text editor to write this text in /etc/service/mysite/run :



#!/usr/bin/env bash



source /home/mysite/virtualenvs/mysite/bin/activate

cd /home/mysite/mysite

exec envuidgid mysite python manage.py runfcgi method=threaded host=127.0.0.1 port=8080 pidfile=mysite.pid minspare=4 maxspare=30 daemonize=false




There is nothing tricky here. First we check that we are in the right virtual environment (virtualenv), then we change the current directory to mysite and then we run the runfcgi command, which we discussed earlier. envuidgid mysite just makes sure that the following command is executed under the mysite user, instead of root .



The script must be executable for daemontools to recognize it, so let's execute the following command:



sudo chmod +x /etc/service/mysite/run



Now we can verify that it is executed using the svstat command:



sudo svstat /etc/service/mysite/



The result should look something like this:



/etc/service/mysite/: up (pid 3610) 33 seconds



This means that the process is up, it is assigned a process id = 3610 and it worked for 33 seconds. You can use the svc command to stop the process:



sudo svc -d /etc/service/mysite/



Then, if you run svstat again, you will get something like this:



/etc/service/mysite/: down 4 seconds, normally up



To bring the process back, simply run:



sudo svc -u /etc/service/mysite/



A full list of svc commands can be found online - this is a very good source if you are going to dive deeper into daemontools .



Configuring Nginx to work with our server



We are close to the finish line. All we have to do is configure nginx to talk with our FastCGI server, get answers from it and send them to the user.



Ubuntu comes with a useful /etc/nginx/fastcgi_params file. Unfortunately, it is not quite correct. It encodes the SCRIPT_NAME parameter, but what our server really wants is PATH_INFO . You can search and replace or copy the contents below into the /etc/nginx/fastcgi_params file:



fastcgi_param QUERY_STRING $query_string;

fastcgi_param REQUEST_METHOD $request_method;

fastcgi_param CONTENT_TYPE $content_type;

fastcgi_param CONTENT_LENGTH $content_length;



fastcgi_param PATH_INFO $fastcgi_script_name;

fastcgi_param REQUEST_URI $request_uri;

fastcgi_param DOCUMENT_URI $document_uri;

fastcgi_param DOCUMENT_ROOT $document_root;

fastcgi_param SERVER_PROTOCOL $server_protocol;



fastcgi_param GATEWAY_INTERFACE CGI/1.1;

fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;



fastcgi_param REMOTE_ADDR $remote_addr;

fastcgi_param REMOTE_PORT $remote_port;

fastcgi_param SERVER_ADDR $server_addr;

fastcgi_param SERVER_PORT $server_port;

fastcgi_param SERVER_NAME $server_name;




Now we will create a definition for our site. Using a text editor, let's create the file /etc/nginx/sites-available/mysite with the following content:



server {

listen 80;

server_name mysite.com www.mysite.com;

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



location /media {

autoindex on;

index index.html;

root /home/mysite/mysite;

break;

}

location / {

include /etc/nginx/fastcgi_params;

fastcgi_pass 127.0.0.1:8080;

break;

}

}




He says listen to port 80 (standard for HTTP) for mysite.com http://www.mysite.com/ mysite.com http://www.mysite.com/ . Requests for / media should be processed immediately from disk in the /home/mysite/mysite/media directory. And the most important: all other requests will be transmitted via FastCGI to our server.



Now let's connect it via symlink:



sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite



Finally, restart nginx for the new settings to take effect:



sudo /etc/init.d/nginx restart



Conclusion



We set up a minimal server using nginx to serve media files at unbelievable speed and a clean Python FastCGI server to serve dynamic requests without any intermediate layers between them. Using daemontools we have full control over the FastCGI process and can stop it, restart or change its settings at any time.



A really interesting thing - just a few small tweaks are enough , and the same stack could be used for gunicorn , spawning , or paste solutions. Instead of using fastcgi_pass, we could use proxy_pass. We could still use daemontools to keep our process running and in control. Almost every step of this article will remain the same.

This is a very viable alternative to the often imposed stack from Apache / mod_wsgi, and I hope after reading this article more people will see it as a method of deploying your site to django.



About the author of the article



Eric Florenzano is a software developer. He currently lives in San Francisco and works for Mochi Media. At the moment he has been participating in the Django and Pinax community for several years. He is currently co-founder of Django Dose, podcasts about everything related to Django. From time to time he blogs at www.eflorenzano.com about python, non-relational databases and other interesting topics.

Source: https://habr.com/ru/post/85851/



All Articles