A (Complete) Guide to Running Django on Joyent Shared Accelerators using Virtualenv, pip, git, and NginX
By · PostedIn this guide we'll go over the process of deploying a Django application on a Joyent Shared Accelerator (now called SmartMachines).
We'll be using the following tools:
- Virtualenv - to isolate our Python environment and manage software versions.
- pip - to install packages.
- git - for version control
- NginX - to serve our Django site through FastCGI.
Getting started: setting up your development environment
Let's setup our development environment on our local machine using Virtualenv and pip.
$ virtualenv --no-site-packages mysite $ cd mysite/ $ . bin/activate $ pip --version pip 0.8.2 from /home/evan/mysite/lib/python2.6/site-packages (python 2.6)
Inside your virtualenv upgrade pip.
pip install --upgrade pip
Install Django inside a virtualenv
Note: If your application is already inside a virtualenv with packages installed by pip you can skip down to the Deploying section below.
Let's install the latest stable release of Django (1.2.4 as of today) using pip.
$ pip install Django Downloading/unpacking Django Downloading Django-1.2.4.tar.gz (6.4Mb): 6.4Mb downloaded Running setup.py egg_info for package Django Installing collected packages: Django Running setup.py install for Django changing mode of build/scripts-2.6/django-admin.py from 644 to 755 changing mode of /home/evan/mysite/bin/django-admin.py to 755 Successfully installed Django Cleaning up...
Create a new project, myproject, here. It should be in the same directory as bin, include, and lib that were created by virtualenv.
$ django-admin.py startproject myproject $ cd myproject/ $ django-admin.py runserver Error: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
Oops! We're getting an error because Django cannot find and import our settings.py file. Let's fix that by putting our project directory into the virtualenv's site-packages directory with a symbolic link:
$ ln -s `pwd` ../lib/python2.6/site-packages/`basename \`pwd\``
If you are using a different version of Python change python2.6
to reflect that version.
And then defining the DJANGO_SETTINGS_MODULE
environment variable. Also, let's make it so this environment variable is set every time we activate the virtualenv.
$ export DJANGO_SETTINGS_MODULE=myproject.settings $ echo "!!" >> ../bin/activate
Now let's try the runserver
command again.
$ django-admin.py runserver Validating models... 0 errors found Django version 1.2.4, using settings 'myproject.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
Great! Everything is working.
Create a git repository
We want to create our git repository inside the myproject directory to track our Django application.
$ git init . Initialized empty Git repository in /home/evan/mysite/myproject/.git/ $ echo "My Django app for Joyent" > README $ git add README $ git commit -m "Initialzed repository and added README" [master (root-commit) 7d09bd1] Initialzed repository and added README 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 README
Here you should create your application. I'll just use the Django Tutorial for now.
Use requirements and pip freeze
We want to create a list of all the necessary packages for our project. The pip freeze
command can help us with this, but we can't just use every package from the list because some packages like fabric and paramiko won't successfully install on the Share Accelerator.
My REQUIREMENTS file is very short:
$ cat REQUIREMENTS Django==1.2.4 django-debug-toolbar==0.8.4 wsgiref==0.1.2
Great. Let's get this app running on Joyent.
Deploying: getting your app on the server
First off, login to your virtualmin page (my server, harbor, is at https://virtualmin.joyent.us/harbor/ )and create a virtual server for your new site if you haven't yet.
Now you should create a database. I'd recommend creating a PostgreSQL database. If you'd like you can also create a separate user to access the database with. For simplicity, I'll just use my main user account for now.
Install virtualenv on Joyent
To use virtualenv
on your server you need to first get it on your server. We'll download it from PyPi.
ssh
in to your server and:
$ mkdir -p local/ $ cd local/ $ wget -O virtualenv-1.5.1.tar.gz http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.5.1.tar.gz $ tar xzvf virtualenv-1.5.1.tar.gz
Let's now create our virtualenv on our server. This is the same as on our local machine.
$ python virtualenv.py --no-site-packages ~/django_projects/mysite $ cd ~/django_projects/mysite/ $ . bin/activate
Upload your application to the server
Now, get your project directory inside this newly created virtualenv. It really doesn't matter how. If you're using github you might want to create a deploy key These days, this seems to be the preferred way to deploy.
If you're using github, clone your project with:
$ git clone [email protected]:carmi/mysite.git Initialized empty Git repository in /users/home/carmi/django_projects/mysite/mysite/.git/
Great! Now we should have our project directory myproject inside our virtualenv on the same level as bin
, lib
and include
. Make sure you've modified your settings file for production and updated the database settings to use your PostgreSQL database instead of sqlite3. My databases looks like:
DATABASES = { 'default': { 'ENGINE': 'postgresql_psycopg2', 'NAME': 'carmi_django_mysite_database', 'USER': 'carmi', 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '5432', } }
Try running django-admin.py syncdb
. If it works then your database is configured correctly.
Setup the server's virtualenv.:
$ cd ~/django_projects/mysite/myproject/ $ ln -s `pwd` ../lib/python2.6/site-packages/`basename \`pwd\`` span class="nv">$ export DJANGO_SETTINGS_MODULE=myproject.settings $ echo "!!" >> ../bin/activate
Install packages on the server with pip
Let's install the packages in our REQUIREMENTS file.
$ pip install -r REQUIREMENTS
We will need flup and psycopg2 (for PostgreSQL). Let's install those:
$ pip install flup psycopg2
Setup static media
Let's assume you have some static media for your project in ~/django_projects/mysite/myproject/media/
For security reasons (but don't trust me on this) we don't want to serve static media (CSS, Javacsript) from inside our project directory. Instead, let's create some other directories to serve static media from:
$ mkdir -p ~/django_projects/mysite/web/public
And then create a symbolic link from there to our media directory.
$ ln -s ~/django_projects/mysite/myproject/media/ ~/django_projects/mysite/web/public/media
Now let's link Django's contrib.admin
media to this location:
$ ln -s ~/django_projects/mysite/lib/python2.6/site-packages/django/contrib/admin/media/ ~/django_projects/mysite/myproject/media/admin
And lastly let's configure our settings.py
to use these locations:
MEDIA_URL = '/media/' ADMIN_MEDIA_PREFIX = '/media/admin/'
Setup NginX and FastCGI
Now let's get NginX running.
Create a nginx.conf
file inside your site directory:
$ mkdir -p ~/django_projects/mysite/etc/ $ vim ~/django_projects/mysite/etc/nginx.conf
Edit your nginx.conf
file to look like the following but with your own port number, domain, and username. In the example my port is 10071
, my domain is django.joyeurs.com
, and my username is carmi
:
events { worker_connections 24; } http { include /opt/local/etc/mime.types; default_type application/octet-stream; server { listen 10071; server_name django.joyeurs.com; location /media { root /users/home/carmi/django_projects/mysite/web/public; } location / { fastcgi_pass unix:/users/home/carmi/django_projects/mysite/myproject/myproject.socket; # fastcgi parameters fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param SERVER_NAME $server_name; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; } } }
Create an init.sh
script in your project directory to start the Django FastCGI process that should look like:
#!/usr/local/bin/bash #Activate the virtualenv source /users/home/carmi/django_projects/mysite/bin/activate PROJECT_NAME="myproject" PROJECT_DIR="/users/home/carmi/django_projects/mysite/myproject" PID_FILE="/users/home/carmi/django_projects/mysite/myproject/myproject.pid" SOCKET_FILE="/users/home/carmi/django_projects/mysite/myproject/myproject.socket" BIN_PYTHON="/users/home/carmi/django_projects/mysite/bin/python" DJANGO_ADMIN="/users/home/carmi/django_projects/mysite/bin/django-admin.py" OPTIONS="maxchildren=2 maxspare=2 minspare=1" METHOD="prefork" case "$1" in start) # Starts the Django process echo "Starting Django project" $BIN_PYTHON $DJANGO_ADMIN runfcgi $OPTIONS method=$METHOD socket=$SOCKET_FILE pidfile=$PID_FILE ;; stop) # stops the daemon by cating the pidfile echo "Stopping Django project" kill `/bin/cat $PID_FILE` ;; restart) ## Stop the service regardless of whether it was ## running or not, start it again. echo "Restarting process" $0 stop $0 start ;; *) echo "Usage: init.sh (start|stop|restart)" exit 1 ;; esac
You'll need to make this init.sh
file executable:
$ chmod +x ~/django_projects/mysite/myproject/init.sh
Startup the Django FastCGI instance with:
$ ~/django_projects/mysite/myproject/init.sh start
This script also takes start
, stop
, and restart
as parameters.
Now launch NginX with your configuration file:
$ /usr/local/sbin/nginx -p /users/home/carmi/ -c /users/home/carmi/django_projects/mysite/etc/nginx.conf
We should now having our Django application running. Go to http://domain.com:PORTNUBMER/ to see it. For my app, we can login to the admin interface by going to: http://django.joyeurs.com:10071/admin/
Now, in virtualmin create bootup actions to start the Django FastCGI process and NginX on server reboots.
Great! We've just covered setting up a Django application on a Joyent Shared Accelerator using virtualenv, pip, NginX, and git.
Please let me know if something is not working, or if you'd just like to leave some feedback.
Coming Soon
Wait a second! This is a long guide. Are we really all going to repeat the same steps over and over? Coming soon is a python script to automate this entire install process. Stay posted.
blog comments powered by Disqus