February 13, 2009.
It's been more than a year since my first endeavor to setup a healthy environment to deploy Django (as I was rudely reminded by the Ubuntu repositories for my server's version ceasing to function). In that time I've learned a lot, and have also stretched my original setup to its breaking point, but inevitably the day comes for a fresh deployment with better configurations and more flexible folder layouts.
From my last server setup guide,
a number have things have remained the same: still using Ubuntu, Memcached, Postgres and still using
Nginx as a proxy server infront of Apache2. A number of things have changed as well: using mod_wsgi
over mod_python
, cmemcache
over python-memcached
, and a more intentional folder layout
along with virtualenv
to make it straightforward to host multiple projects and domains (including some
serving only static files or PHP scripts).
More than just an update, I've also included a few side-quests like using your server as a remote Git repository over SSH, and installing pluggable Django libraries. Finally, in the vein of my previous tutorial, I tried to include every keystroke required to transform a naked Ubuntu Intrepid server into a full-featured multi-site Django-loving server.
Please let me know if you run into any problems, or have suggestions on improvements!
Somehow get a Ubuntu Intrepid server or VPS. (Perhaps go to your SliceHost console and request a new Slice running Ubuntu Intrepid (8.10). ;)
Write down root password and IP address for your box.
SSH into your server.
ssh root@255.255.255.255
Update your apt-get sources.
apt-get upgrade
Make sure there is an editor that suits your taste available on the system. Vim is pre-installed, but I prefer Emacs...
apt-get install emacs
Setup any non-root accounts you want, and one for Django.
useradd django
mkdir /home/django
chown django:django /home/django
useradd will
mkdir /home/will
chown will:will /home/will
passwd will
Unless you like sh
, change your default shell to
something more humane.
chsh root -s /bin/bash
chsh will -s /bin/bash
chsh django -s /bin/bash
(These changes won't be applied until you log in the next time.)
Give your account (but not Django) root permissions.
visudo
Then use the down arrow for find a line that looks like this:
root ALL=(ALL) ALL
Replicate that with your username:
root ALL=(ALL) ALL
will ALL=(ALL) ALL
Open a second terminal (leave the first one logged in while we keep configuring SSH, incase something goes horribly awry), and SSH in as your non-root user.
ssh will@255.255.255.255
Verify it works, then exit
back to your system.
Now it's time to setup password-less login. Return to your home system,
scp ~/.ssh/id_dsa.pub will@255.255.255.255:~/
ssh will@255.255.255.255
mkdir .ssh
mv id_dsa.pub .ssh/authorized_keys
chmod go-w ~/.ssh/authorized_keys ~/.ssh/
Now exit
and ssh
back in. You should have
been logged in without needing to supply your password.
Now it's time to restrict ssh
a bit.
sudo groupadd sshers
sudo usermod -a -Gsshers will
sudo emacs /etc/ssh/shhd_config
Make these changes:
#X11Forwarding yes
X11Forwarding no
And add these lines to the end of the file:
UseDNS no
AllowGroups sshers
Save the file, and then restart the ssh
service.
sudo /etc/init.d/ssh restart
exit
your VPS, and once again try
logging back in. If that worked,
again open /etc/ssh/sshd_config
.
sudo emacs /etc/ssh/sshd_config
And append this line to the end of the file:
PasswordAuthentication no
And once again restart the ssh
service.
sudo /etc/init.d/ssh restart
Finally, disable password access to the root
account.
sudo passwd -l root
Now your VPS is only accessible through your approved account from machines with the correct SSH key.
Now it's time to start installing some general libraries.
sudo apt-get install subversion git-core gcc curl
sudo apt-get install build-essential python-dev python-setuptools
sudo apt-get install python-egenix-mxdatetime memcached postfix
Now it's time to configure Postgres, first we need to grab some libraries.
sudo apt-get install postgresql-8.3 postgresql-server-dev-8.3
sudo apt-get install postgresql-8.3 postgresql-server-dev-8.3
Rather than a typo, I really did need to run the above command twice for a successful installation.
Next we need to configure the postgres
user.
sudo -u postgres psql template1
ALTER USER postgres WITH PASSWORD 'password';
\q
(Make sure that you used a real password, rather than
'password'
in the above example.)
We also need to modify Postgres' configuration file.
sudo emacs /etc/postgresql/8.3/main/pg_hba.conf
Move to the bottom of the file, and comment out (add
a #
at the beginning of the line) all lines which
begin with host
. (This prevents external access
to your database.)
It should look like this:
# Database administrative login by UNIX sockets
local all postgres ident sameuser
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all password
# IPv4 local connections:
#host all all 127.0.0.1/32 md5
# IPv6 local connections:
#host all all ::1/128 md5
Note that we switched ident sameuser
to password
for the second local
line!
Then restart Postgres to have it reload its settings.
sudo /etc/init.d/postgresql-8.3 restart
And there we have it, Postgres is setup and functioning.
And now it's time to setup memcached.
This is a two part process.
First we need to start memcached
, which is very easy, and second
we need to build cmemcache, which is a bit harder.
sudo memcached -u www-data -p 11211 -m 32 -d
That runs memcached
on the standard port, with the
standard www-data
user (standard for Ubuntu, that is),
with 32 megabytes of ram. You might want to allocate more,
depending on how much data you're expecting to store in memcached,
and the size of your VPS.
Next we need to setup cmemcache
. First grab libmemcache
,
sudo apt-get install libmemcache-dev
Next we actually build cmemcache
.
su django
mkdir ~/libs/
cd ~/libs/
wget http://gijsbert.org/downloads/cmemcache/cmemcache-0.95.tar.bz2
tar -xjvf cmemcache-0.95.tar.bz2
cd cmemcache-0.95
exit
We'll need to actually install the library later when we setup our virtualenv
.
If you are unable to install cmemcache
, follow these instructions.
Alternatively, if you want to use the Python based python-memcached (runs a bit slower, but no C module to build and install), you can do that as follows.
wget ftp://ftp.tummy.com/pub/python-memcached/python-memcached-latest.tar.gz
tar -zxvf python-memcached-latest.tar
cd python-memcached-1.43
# later on use python setup.py install inside virtualenv
The preference for cmemcache
is strictly based on speed.
But python-memcached
is still quite usable, and if the
choice is between python-memcached
and not running memcached
as your caching backend, picking python-memcached
is the
clear winner.
Next it's time to setup Nginx, which is a lightweight server we'll use to serve static content as well as proxy requests to Apache21.
sudo apt-get install nginx
We can quickly verify that it installed correctly.
sudo /etc/init.d/nginx start
curl 127.0.0.1
Should return:
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>
Now we're going to modify the nginx.conf
file a bit
(based on the advice here).
sudo emacs /etc/nginx/nginx.conf
Right now we only need to make two minor changes, first change line 2 to use four worker processes,
worker_processes 4;
And next uncomment line 18,
tcp_nopush on;
We won't need to edit this file again, because of the last line,
include /etc/nginx/sites-enabled/*;
which makes it easy to declare site specific settings in their own
files, and really cuts down on clutter in nginx.conf
.
We also need to create a proxy.conf
file, which is a common
Nginx practice for keeping nginx.conf
clean.
sudo emacs /etc/nginx/proxy.conf
Which should contain these lines:
# proxy.conf
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
Finally, stop and start Nginx (I don't know if this is still the case with the current version of Nginx, but historically I've never gotten it to reload a configuration file with just a reload or restart).
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
Now it's time to setup Apache2. First we grab the necessary libraries.
sudo apt-get install apache2 libapache2-mod-wsgi
Because we already have Nginx bound on port 80 it will throw a bit of a complaint
(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs
...fail!
invoke-rc.d: initscript apache2, action "start" failed.
But no worries, we're going to be alright.
The first thing we need to do is to setup Apache to run on the internal 127.0.0.1:80 instead of on port 80.
sudo emacs /etc/apache2/ports.confg
Then modify these lines:
NameVirtualHost 127.0.0.1:80
Listen 127.0.0.1:80
We also want to make a modification to apache2.conf
:
sudo emacs /etc/apache2/apache2.conf
Search for KeepAlive
(it's around line 77), and change its value
as follows:
# KeepAlive On
KeepAlive Off
We do this because Nginx doesn't yet support the KeepAlive
option.
Now let's try starting Apache, again.
sudo apache2ctl start
Which may complain yet, again.
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
[Thu Feb 12 17:14:46 2009] [warn] NameVirtualHost 127.0.0.1:80 has no VirtualHosts
But once, again, no worries, it's just a phase in the process.
Finally we get to actually grab Django. Switch
over to the /home/django
folder we created earlier,
and it's time for us to create some folders.
su django
mkdir domains
mkdir libs
mkdir .python-eggs
exit
Then let's do some permissions wrangling.
sudo chown django:www-data .python-eggs
sudo chmod g+w .python-eggs/
sudo usermod -a -G www-data django
sudo usermod -a -G www-data will
sudo chgrp -R www-data /home/django/domains
sudo chmod -R 2750 /home/django/domains
Then let's grab the Django source code.
cd libs
svn co http://code.djangoproject.com/svn/django/trunk/ django
Normally this would be a great time to symlink the packages into
/usr/lib/python2.5/site-packages
, but we're going to go a
slightly different route instead and use
virtualenv to encapsulate
each of our projects.
sudo easy_install virtualenv
We'll take care of setting up virtualenv
later, because it is
done on a per-project basis.
Our last step of generic preparation is to remove the default sites for both Apache and Nginx. With properly configured setup files for Nginx/Apache (we'll get to those soon ;) you won't run into many situations where you are accidentally showing the default pages, but they often will be displayed when visiting the page directly via it's IP address.
While that isn't a terribly common event, it's probably undesirable nonetheless.
sudo rm /etc/apache2/sites-enabled/default
sudo rm /etc/apache2/sites-enabled/default
sudo rm /etc/apache2/sites-enabled/000-default
sudo rm /etc/nginx/sites-enabled/default
You'll need to restart the server for the changes to take effect.
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
sudo apache2ctl graceful
Now we're going to actually setup a Django project. You'll be able to follow this same process to setup any number of Django projects later.
First we need to create the folders for each
domain. (I'll walk through this example using
the domain substanceis.com
, which was hosting
an old project long since forgotten.)
cd /home/django/domains
mkdir substanceis.com
sudo mkdir -p substanceis.com/{public,log}
sudo mkdir substanceis.com/public/media
sudo chown -R django:www-data substanceis.com
Some people like to have private
and
backup
directories as well. Feel free
to add your own special spice.
public
directory will be for publicly
accessible files served by Nginx.
log
directory will store the Apache
and Nginx logs for the domain.
substanceis.com
folder itself. (And the mod_wsgi
config file
in the project directory.)
Now we need to setup a virtual environment for the project.
If you haven't experiment with virtualenv
, it makes it easy
to sandbox your projects, so that each project can have different
versions of libraries (Django 0.97pre for one project, Django 1.1
for another, Pygments 0.6 for one project, Pygments 1.1 for another,
etc).
This makes it an essential tool for developing or hosting multiple applications on one server.
Note that we previously downloaded Django from SVN into the folder /home/django/libs/django
.
su django
cd ~/domains/substanceis.com
virtualenv --no-site-packages --unzip-setuptools substanceis.com
cd ~/libs/django
~/domains/substanceis.com/substanceis.com/bin/python setup.py install
cd ~/libs/cmemcache-0.95
~/domains/substanceis.com/substanceis.com/bin/python setup.py install
You will also need to install psycopg2
(Python interface for Postgres).
cd domains/substanceis.com/substanceis.com/bin/
./easy_install egenix-mx-base
./easy_install psycopg2
For packages without easy_install
or setup.py
support,
you can symlink them into the virtual environment's site-packages
folder:
cd ~/libs/
ln -s `pwd`/some_app /home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages/
Now that we've done our installations, go ahead and test it out.
~/domains/substanceis.com/substanceis.com/bin/python
Then try importing it.
>>> import django
>>>
Whereas if you do that with the normal python
:
cd
python
You get a different experience:
>>> import django
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named django
>>>
Now that we're done setting up the virtualenv
go ahead and exit
the django
user.
exit
Next we need to create an Nginx virtual host for the domain.
sudo emacs /etc/nginx/sites-available/substanceis.com
If you wish to strip www
from your domain, you should
begin the file with this server
directive:
You'll need to update 255.255.255.255
to be the IP address of your VPS/server.
server {
listen 255.255.255.255:80;
server_name www.substanceis.com;
rewrite ^/(.*) http://substanceis.com/$1 permanent;
}
Regardless, the remainder of the file should be in this format:
You'll need to update 255.255.255.255
to be the IP address of your VPS/server.
server {
listen 255.255.255.255:80;
server_name www.substanceis.com substanceis.com;
access_log /home/django/domains/substanceis.com/log/access.log;
error_log /home/django/domains/substanceis.com/log/error.log;
location / {
proxy_pass http://127.0.0.1:80/;
include /etc/nginx/proxy.conf;
}
location /media/ {
root /home/django/domains/substanceis.com/public/;
expires 1d;
}
}
Note that if your static media changes frequently, then you'll
want to remove the expires 1d
setting. That adds a header
saying that such content will not change for the next day,
which means that the browser won't try to refetch it for that
period of time.
This means faster page loads for your users, and lower server load
for you. If you want the benefits of
future expires,
but have frequently changing media, then the standard solution is to
add a version number for your media files (me.1.png
, me.2.png
,
etc). django-compress
provides some support for automating the versioning process for JavaScript
and CSS files (and is highly recommended).
Next we need to let Nginx know that the site is enabled, by symlinking
it from sites-available
to sites-enabled
.
sudo ln -s /etc/nginx/sites-available/substanceis.com /etc/nginx/sites-enabled/substanceis.com
Finally you'll need to stop and start Nginx before Nginx knows that this virtual environment exists.
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
And you're done configuring Nginx.
Now let's quickly create a default Django project.
su django
cd ~/domains/substanceis.com/
./substanceis.com/bin/python substanceis.com/bin/django-admin.py startproject hello
exit
Link the Django admin media into the public/media/
folder.
sudo ln -s /home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages/django/contrib/admin/media /home/django/domains/substanceis.com/public/media/admin
Then update the ADMIN_MEDIA_PREFIX
setting in your hello/settings.py
file
sudo emacs /home/django/domains/substanceis.com/hello/settings.py
to look like this
#ADMIN_MEDIA_PREFIX = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
Next let's create a Postgres database for this project to use.
sudo su postgres
createuser -P pg_substanceis
# should not be a superuser
# should not be able to create databases
# should not be able to create more new roles
createdb --encoding=UNICODE db_substanceis -O pg_substanceis
exit
Then we need to update the settings.py
file with the
proper settings.
sudo emacs hello/settings.py
And modify the DATABASE_*
fields to look like this:
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'db_substanceis'
DATABASE_USER = 'pg_substanceis'
DATABASE_PASSWORD = '123456789'
DATABASE_HOST = ''
DATABASE_PORT = ''
Finally let's try to sync the database to verify that we got the settings correct.
~/domains/substanceis.com/substanceis.com/bin/python hello/manage.py syncdb
Assuming you entered your username, database and password correctly you should see something familiar.
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
...
Our next step is to setup the project to memcached
as its caching backend.
sudo emacs hello/settings.py
And add these settings:
CACHE_BACKEND = 'memcached://127.0.0.1:11211'
CACHE_MIDDLEWARE_SECONDS = 60 * 5
CACHE_MIDDLEWARE_KEY_PREFIX = 'sis' # SubstanceIS
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
You'll have to decide what values of CACHE_MIDDLEWARE_SECONDS
and CACHE_MIDDLEWARE_ANONYMOUS_ONLY
are appropriate for the
particular project you're configuring. There is more information
available here.
The value of CACHE_MIDDLEWARE_KEY_PREFIX
should be unique
for each project using memcached
.
After a tremendous journey, we reach the final step:
configuring mod_wsgi
and Apache to serve our project.
sudo emacs /home/django/domains/substanceis.com/hello/hello.wsgi
And add this code to hello.wsgi
:
ALLDIRS = ['/home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages']
# note that the above directory depends on the locale of your virtualenv,
# and will thus be *different for each project!*
import os
import sys
import site
prev_sys_path = list(sys.path)
for directory in ALLDIRS:
site.addsitedir(directory)
new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path
# this will also be different for each project!
sys.path.append('/home/django/domains/substanceis.com/hello/')
os.environ['PYTHON_EGG_CACHE'] = '/home/django/.python-eggs'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Next we need to create a virtual host for our domain.
sudo emacs /etc/apache2/sites-available/substanceis.com
And add this VirtualHost definition.
<VirtualHost 127.0.0.1:80>
ServerName www.substanceis.com
ServerAlias substanceis.com
<Directory /home/django/domains/substanceis.com/hello/>
Order deny,allow
Allow from all
</Directory>
LogLevel warn
ErrorLog /home/django/domains/substanceis.com/log/apache_error.log
CustomLog /home/django/domains/substanceis.com/log/apache_access.log combined
WSGIDaemonProcess substanceis.com user=www-data group=www-data threads=25
WSGIProcessGroup substanceis.com
WSGIScriptAlias / /home/django/domains/substanceis.com/hello/hello.wsgi
</VirtualHost>
And finally enable substanceis.com
.
sudo ln -s /etc/apache2/sites-available/substanceis.com /etc/apache2/sites-enabled/substanceis.com
And restart Apache2 to have it pick up the new site.
sudo apache2ctl graceful
You can repeat these steps to host as many projects as you want.
At this point your mod_wsgi server is setup and fully functional, but here are a couple of suggestions for things you might want to do with your fresh server.
At the moment if you go to your VPS's ip address, then you'll notice that it isn't serving anything at all. For most people that is probably the correct behavior, but you might want to serve a static page when they reach your VPS via its IP address (also, you can do the same thing to serve static content for some of your domains, rather than a full Django project).
First we need to create some folders
sudo mkdir /home/django/domains/default
sudo mkdir -p /home/django/domains/default/{public,logs}
Then create an index page
sudo emacs /home/django/domains/default/public/index.html
with this html
<html>
<head><title>Default</title></head>
<body><p>Hi. Welcome to my default site.</p></body>
</html>
Now we need to configure the Nginx site
sudo emacs /etc/nginx/sites-available/default
with these settings (you'll need to change 255.255.255.255
to
your VPS's ip address):
server {
listen 80;
server_name 255.255.255.255;
access_log /home/django/domains/default/log/access.log;
error_log /home/django/domains/default/log/error.log;
location / {
root /home/django/domains/default/public;
index index.html;
}
Then symlink it into the sites-enabled
folder.
sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
And finally we need to stop-start nginx.
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
Now if you navigate to your VPS's ip address in a browser,
you'll see your static site. (Note that browsers typically
limit the number of concurrent http connections to one domain,
so you can speed up page load for heavy pages by using these
steps to setup a media only subdomain--media.example.com
, etc--for
your Django sites and serving static media from them instead of the
same domain as your site.)
One of the most helpful packages around is PIL, which
supports a wide variety of image manipulation techniques.
It's also used by some pieces of Django. It seems to be
improperly packaged for installation with easy_install
,
but it is still straightforward to install.
su django
cd ~/libs
wget http://effbot.org/downloads/Imaging-1.1.6.tar.gz
tar -xzvf Imaging-*
cd Imaging-1.1.6
/domains/substanceis.com/substanceis.com/bin/python setup.py install
And now the substanceis.com
virtual environment will have
access to the Image
module:
>>> import Image
>>>
The more Django development you do, the more you'll be creating pluggable applications and reusing those made by others, so it's a good process to be familiar with. So let's take a few moments to install a couple common reusable Django applications developed by the Django community.
One of the downsides of using virtualenv
is that
you'll need to install pluggable apps into each of
your environments one at a time. Of course, it also
means that you can freeze a production site to use
a certian version of a pluggable app while another
plunges ahead into the unknown.
It is important to note the benefits of installing with setup.py
or easy_install
in conjunction with virtualenv
.
It means that you'll get a frozen copy of the code, and even if
you update the source code later on, the environments won't be
running different code.
On the other hand, if you're actively developing code, then you
would be better off symlinking the code into the environment's
site-packages
directory so that you don't have to redeploy
the code on changes.
Both approaches have their place, just be careful to use them appropriately.
First let's install django-compress, which I mentioned earlier and helps automating the merging and compression of JavaScript and CSS files.
su django
cd /django/home/libs
sudo svn checkout http://django-compress.googlecode.com/svn/trunk/ django-compress
cd django-compress
~/domains/substanceis.com/substanceis.com/bin/python setup.py install
Now let's make sure it's usable.
~/domains/substanceis.com/substanceis.com/bin/python
Then within Python try
>>> import compress
>>>
As long as you don't get an error, then it installed correctly.
Next let's install django-faq, which is a pluggable application for creating faqs on websites (managable via the Django admin).
Just for fun, let's symlink it in (more convenient for active development)
instead of using setup.py
.
cd /django/home/libs
sudo git clone git://github.com/RockHoward/django-faq.git
cd django-faq
ln -s `pwd`/faq /home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages
Finally let's install django-mailer, which supplements Django with a more robust mailing framework.
cd /django/home/libs
sudo svn checkout http://django-mailer.googlecode.com/svn/trunk/ django-mailer
cd django-mailer
sudo ln -s `pwd`/mailer /home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages
Wait, is it okay to recommend one of my projects? Ok. You should consider taking a look at django-monetize, which supports dynamically serving different kinds of advertisements (and requests for donations, etc) based on a page's context.
cd /django/home/libs
sudo git clone git://github.com/lethain/django-monetize.git
cd django-monetize
sudo ln -s `pwd`/django_monetize /home/django/domains/substanceis.com/substanceis.com/lib/python2.5/site-packages
Moving past these pluggable apps, there are also a number of projects which have expanded to be something akin to mini-frameworks on top of Django. They provide a great amount of functionality, but often at the expense of somewhat non-standard installation patterns.
Two of the more popular are the social framework Pinax ( installation ), and the webshop platform Satchmo ( installation ).
Another thing I like doing is to use my VPS as a Git repository, which is--thanks to the manifold joys of DVCS--unexpectedly simple.
cd
mkdir git
mkdir git/scripts
cd git/scripts
echo "# a test" > test.py
git init --bare
Then exit
your VPS and return to your machine.
From your home machine you can clone that repository
by using SSH.
mkdir my_repo
cd my_repo
git init
mkdir
echo "a test" > test.py
git add test.py
git commit -m "Initial commit."
git remote add origin ssh://67.207.149.179/home/will/git/scripts
git push origin master
Note that using the --bare
keyword means that repository
will keep all its files in its .git
folder, so you won't be able
directly interact with your files in that hosted repository.
If you do want to interact with the files from that git repository
on your machine, you should git clone
from the origin
repository and then push and pull like you normally would.
(If you're wanting to use Git as a mechanism for pushing code for your Django projects, you might want to read up about using something like Fabric.)
Although admittedly not as glamorous as being a Djangonaut, there are a number of situations where you may want Apache to also run some php scripts for you.
sudo apt-get install php5
sudo apache2ctl graceful
Then just place .php
files in a directory served
by Apache (not by Nginx), and they'll be executed.
You'll probably want a combination of the Django
and static Nginx configuration files that we've put
together through the course of this walkthrough.
These articles draw heavily from my previous nginx+apache+mod_python+django and lighttpd+apache+mod_python+django articles from last year, but have taken advantage of new resources as well.
Many thanks to those who created these above resources that made this all possible.
Tom Schreiber mentioned that virtualenv is a great tool for developing multiple projects with differing versions of libraries, and on his recommendation I updated the walkthrough to include it. Thanks Tom!
A helpful Redditor
pointed out some ways for improving. Particularly using chsh
for changing shells (instead of
manually editing the /etc/passwd
file), and having Apache listen only to 127.0.0.1:80
instead of binding to *:8080
, which makes it externally accessible, and having
Nginx listen to external-ip:80
instead of *:80
.
Hey kids, did you know that Nginx is pronounced "engine x". I sure as hell didn't. I actually had a coworker tell me how it was pronounced a while ago, but without seeing "engine x" written it never quite worked for me. Now I get it. Finally.↩