Deploying a website is a pain. Using a "simplified" service, e.g. Heroku, it's still a pain but you don't learn very much. I learned that firsthand when I deployed my first Django project using Heroku. When the process was complete, I felt I had learned vaguely how to use Heroku's tools, and next to nothing about deployment in general.
For my next project, I decided to use a service that could provide me with only a Unix box and force me to do everything else. I went with DigitalOcean, as it offers an inexpensive basic server and met my needs.
DigitalOcean provides some helpful guides for getting started, but I quickly ran into caveats and outdated information that could be very frustrating. After a lot of googling and trial-and-error, I successfully launched that second project; however, I made the mistake of not documenting my process. When it came time to deploy the site containing this blog, I resolved to take detailed notes about the entire process, to ease future deployments and hopefully help others.
My intent with this article is to create "the comprehensive guide I wish I had" when trying to deploy my first site. I've tried to both synthesize the information from other guides, as well as rectify portions found to be incorrect or outdated. So without further ado, here it is.1
1 Resources
Here are some resources that may be helpful over the course of this guide, conveniently gathered to prevent incessant googling. Many of the steps on this page are based largely on the links in the "Tutorials" section. I do not recommend reading the tutorials right away, as there are significant problems with some of them (discussed infra); however, they may be useful to consult as a secondary source.
1.1 Docs
1.2 Tutorials
-
DigitalOcean - Additional Recommended Steps for New Ubuntu 14.04 Servers
-
DigitalOcean - How To Configure SSH Key-Based Authentication on a Linux Server
-
DigitalOcean - How To Create Your First DigitalOcean Droplet Virtual Server
-
DigitalOcean - How To Install and Configure Django with Postgres, Nginx, and Gunicorn
-
DigitalOcean - How to Point to DigitalOcean Nameservers From Common Domain Registrars
-
DigitalOcean - Initial Server Setup with Ubuntu 14.04
-
Django - How to Deploy with WSGI
2 Assumptions
A guide like this is difficult due to the sheer number of options for each component of a website. There's a choice to be made between generalizing for a wider audience but lacking complete detail for any one stack, and writing a tightly focused guide but losing applicable readers. Given the stack used for this site is a common one, this guide as a whole is catered to that particular stack, with all the specifics that entails.
2.1 General
This guide assumes basic familiarity with Linux and working with the terminal. Things like pressing Enter to execute a command, how to navigate to a directory, and how to use an in-terminal text editor go unstated. The commands for anything more complicated than these will be explicitly given.
2.2 Django Project
Naturally, prior to the deployment process, one needs a project. This guide assumes a project that was developed locally, tested, and is ready to go. I find the guides that deploy an empty starter project, while likely more concise, often lack some important concepts.
The project discussed in this article is generally referred to as yourproject
, or yourprojectrepo
at the repository root level.4 This name will frequently appear, e.g. in the nginx configuration file, the virtualenv, ssh key files, etc. When following this guide for your own project, rename any such name in line with your own project name.
The source for this site is available here. Perusing the source may aid in clarifying something about my project that is not properly explained in this guide.2
2.3 Stack
It is assumed that the machine used to develop the site is running a recent Ubuntu release, but naturally any Unix flavor would be applicable with possibly a little tweaking.
The version of Python assumed is 3.4. The version of Django assumed is 1.7.6 (check yours with import Django; django.VERSION
in a Python shell), but anything 1.7/1.8 should be fine.3 The version control system assumed is git.
The desired web stack assumed for this guide is a PostgreSQL database, Nginx to serve static files, and Gunicorn as the WSGI HTTP server. The Django source, database, and static files are assumed to be hosted on a single machine.
2.4 Layout
The general project layout assumed follows that described in Chapter 3 of Two Scoops of Django. An overview of the relevant portions of the layout is seen below:
yourprojectrepo/ # REPOSITORY ROOT requirements.txt staticfiles/ # `collectstatic` will place static files here. [empty] yourproject/ # PROJECT ROOT manage.py static/ # All static files here css/ images/ [etc...] yourproject/ # CONFIGURATION ROOT __init__.py urls.py wsgi.py settings/ # Note settings subpackage, multiple modules __init__.py base.py local.py test.py production.py
I'm not advocating changing an existing project to this layout, merely putting it here for reference.
Note the repository, project, and configuration root directories, which will be referred to throughout this guide.
The other important piece of the layout to note for this guide is the multiple settings files. These are set up as discussed in section 5.2 of the aforementioned Two Scoops.
2.5 Virtualenv and Environment Variables
This guide assumes virtualenv
and virtualenvwrapper
are being used in local development (and will be used in production). If not using virtualenvwrapper
, the primary (only?) differences will be how the virtual environent is created and activated, so it is not particularly essential.
Sensitive data such as the Django secret key, database credentials, etc. are assumed to be kept in environment variables exported and unset, respectively, by the postactivate
and predeactivate
scripts of the project's virtual environment. Assuming virtualenvs are kept in /home/yournamehere/.virtualenvs
, these files are located as such:
.virtualenvs/ yourproject/ bin/ postactivate predeactivate
postactivate
might look like this:
#!/bin/bash # This hook is sourced after this virtualenv is activated. # I mashed the keyboard; this is not a real secret key. export SECRET_KEY='ukh3qfu%3jh@jf(' export DB_USERNAME=yournamehere export DB_PASSWORD=dbpassword
In that case, predeactivate
should contain:
#!/bin/bash # This hook is sourced before this virtualenv is deactivated. unset SECRET_KEY unset DB_USERNAME unset DB_PASSWORD
If this is new to you, note that the Django settings would access these variables like so:
from os import environ SECRET_KEY = environ['SECRET_KEY']
3 Steps
With the assumptions out of the way, here are the steps to deploy.
3.1 Prepare Django Project
Before starting the deployment process, it's a good time to look over your project again with the development server, and do any preparation necessary for deployment. The Deployment Checklist is a helpful reference for this.
This process might entail the following:
-
Minify CSS/JavaScript and ensure all templates are using the minified files.
-
Ensure
requirements.txt
is up to date (pip freeze > requirements.txt
at the repository root is the easiest way).pip
will be used on the remote machine to populate the virtual environment with necessary packages, so this is important. -
Look over the production settings module. Insert the domain you own/intend to purchase in
ALLOWED_HOSTS
if necessary. Make sureDEBUG
is turned off! -
Ensure the default settings module in
yourproject/yourproject/wsgi.py
is the production settings:os.environ.setdefault("DJANGO_SETTINGS_MODULE", "yourproject.settings.production").
-
Probably a
git commit
For reference, here are this site's production settings:5
from .base import * STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR.parent.child('staticfiles') ALLOWED_HOSTS = ['.adambeagle.com'] DEBUG = False TEMPLATE_DEBUG = False
3.2 Create a DigitalOcean Droplet
If you have not used DigitalOcean before, you will need to create an account.
Once you are logged in, click the "Create Droplet" button. This DigitalOcean guide provides a tutorial on creating a droplet.
For reference, my settings were:
- Hostname: portfolio
- Size: Smallest. 512 MB RAM, 20 GB SSD, 1000 GB transfer.
- Region: New York 3
- No extras (IPV6, private networking, etc.)
- Image: Ubuntu 14.10 x32
- Applications: None
- SSH Keys: None (these will be handled later in the guide)
The default image is x64. Note it is recommended to use a 32-bit OS with <1GB ram, as per the guide linked above.
3.3 Purchase Domain (Optional)
This step is technically optional (you could just enter the IP of your droplet in your browser) but my assumption is that most will want a domain. This step also does not need to be done at exactly this time (or perhaps has already been done).
I used namecheap.com to purchase my domain. I used that service on a previous site without incident. Any service that easily permits you to allow a different host to hanldle DNS is fine.
3.3.1 Set Up DNS
If you wish to use a domain name, the next step is to set up a DNS record at DigitalOcean to point your domain to your droplet's IP.
From the dashboard at the DigitalOcean website (log in again if necessary), click the "DNS" button, then "Add Domain" on the upper right. The "name" box should contain your domain, e.g. "adambeagle.com." For "IP Address" either enter your droplet's IP or select it from the "Select a droplet" dropdown menu, then click "Create Domain."
In the domain's record, there should be three "NS" entries. With the URLs in those entries in mind, go on to the next step.
3.3.2 Transfer DNS
A request to your domain needs to be pointed to DigitalOcean's DNS servers. Whichever service you bought your domain with should allow this somehow.
If you used namecheap.com, follow the instructions below.6 If you used a different service, you may find instructions for it at How to Point to DigitalOcean Nameservers From Common Domain Registrars.
-
Log in to namecheap.
-
From your account's Home Page, click "Your Domains/Products"
-
Click your domain name.
-
On the left, click "Transfer DNS to Webhost."
-
In the dropdowns under "Specify Custom DNS Servers," enter the three URLS from DigitalOcean's DNS record. For me, they were
ns1.digitalocean.com
,ns2.digitalocean.com
, andns3.digitalocean.com
-
Click "Save Changes."
3.4 Initial Droplet Connection and Setup
By this point, DigitalOcean should have sent an email with the droplet's IP and root password.
Follow steps one through three in the DigitalOcean guide found here to do some initial setup steps on the droplet.
It is convenient, but not necessary, to make your user name on the droplet machine the same as your local user name.
It's a decent idea at this point to upgrade any packages on the droplet with:
sudo apt-get update sudo apt-get upgrade
3.5 Configure SSH Key Authentication (Optional, but recommended)
The DigitalOcean guide linked in the previous step covers setting up SSH authentication, but I found it to be inadequate. Specifically, because this was my second site with an SSH key pair, there were some extra steps. Even if you are deploying your first/only site, I recommend following these steps because these steps will automate connection to the droplet with a friendly name.
For the sake of brevity, I won't go into the details of SSH key pairs, merely provide the steps.7
3.5.1 Generate a Key Pair
On the local machine, enter ssh-keygen
on the terminal. You will be asked to enter a path for the key file, or use the default. Enter your own path, such as ~/.ssh/yourproject_rsa
, substituting your project's name.
Next you will be prompted to enter a passphrase. Do it if you wish, but this guide will assume the passphrase was left blank.
In the ~/.ssh
directory, there should now be two files: yourproject_rsa
and yourproject_rsa.pub
. The .pub
file contains the public key, and the other file contains the private key.
Copy the entire contents of the public key file to the clipboard.
3.5.2 Copy the Public Key to the Droplet
Back in the terminal connected to the droplet, switch to the user you created in the Initial Droplet Connection step with su - yournamehere
if you haven't already done so. In your user's home directory, create the .ssh directory and restrict its permissions with mkdir .ssh
and chmod 700 .ssh
.
Next, open a file in the .ssh
folder named authorized_keys
, paste the public key from the local machine into it, and save it.
Restrict the permissions of .ssh/authorized_keys
with chmod 600 .ssh/authorized_keys
.
3.5.3 Configure SSH on the Local Machine
Back in a terminal for the local machine, navigate to the .ssh
directory from the previous step (probably cd ~/.ssh
).
Open a file named config
in the .ssh
directory, and use the following format for its contents:
Host [friendly-name] Hostname [ip.of.droplet] Port [####] IdentityFile [~/.ssh/private_key_file]
Replace the placeholders above (anything surrounded by brackets, but omit the brackets in the file) with your own information.
If omitted, the default port is 22. For security purposes, it is recommended to change it to some other port between 1025 and 65536.
For reference, my .ssh/config
file looks like this (the port was changed on account of security):
Host portfolio adambeagle.com Hostname 104.131.190.90 Port 1025 IdentityFile ~/.ssh/portfolio_rsa
Notice multiple Host names can be provided. These are the names by which you can refer to the remote server to ssh, i.e. either ssh yourproject
or ssh yourdomain.com
would use the settings in the config
file to connect to the droplet.
If your username on the local machine and droplet differ, an additional User
field can be added to config
to specify the remote user name, e.g.:
User yourremoteusername
Additional servers may be added to config
using the same format, as seen in this StackOverflow answer.
3.5.4 Configure SSH on the Remote Machine
In the terminal connected to the droplet, open the file /etc/ssh/sshd_config
.
In that file, find the line that contains Port 22
and change the number to match what you put in the Port line of .ssh/config
in the previous step.
In the same file, find the line that says PermitRootLogin yes
and change it to PermitRootLogin no
. This disallows using root
as the username to login as via ssh
, and is a preventative security measure. Save and exit the file.
Restart ssh with:
service ssh restart
3.5.5 Test SSH Connection
SSH should now be properly configured, but this must be verified before moving on.
Open a new terminal on the local machine, and run...
ssh yourproject
...substituting your Host name from the .ssh/config
file.
At this point, I ran into a problem. I received the error "ssh agent admitted failure to sign using the key." If this happens, run...
ssh-add ~/.ssh/yourproject_rsa
...substituting your private key file's name. Now, try connecting to the droplet again.
If successful, you should be logged into the remote machine without having to type a password (unless you provided an SSH passphrase).
3.5.6 Disable Password Authentication (Optional, but recommended)
Now that you can login to your droplet via SSH without your password, you may wish to disable password authentication as an extra layer of security.
Be sure to backup the private SSH key to a safe place if disabling password authentication, as it will always be necessary to access your droplet.
To disable password authentication, follow the steps in this tutorial (only the linked section "Disabling Password Authentication on your Server").
Do not close the terminal connected to the droplet or logout until you have verified, from a separate terminal window, that you can ssh
into your droplet successfully.
3.6 Additional Droplet Setup (Optional, but recommended)
Follow the steps in this DigitalOcean guide.
I ran into no issues following the steps in that guide exactly as given.
3.7 Install Things
Now its time to start installing the things necessary for the web stack.
Python3 is assumed throughout. If using Python2, remove "3" from any package name, i.e. python3-pip
becomes python-pip
.
All of the following should be done in a terminal connected to the droplet.
3.7.1 pip
sudo apt-get install python3-pip
3.7.2 PostgreSQL
sudo apt-get install libpq-dev python3-dev sudo apt-get install postgresql postgresql-contrib
3.7.3 Nginx
sudo apt-get install nginx
3.7.4 git
If you're using a version control system that is not git, skip this step.
sudo apt-get install git
3.7.5 virtualenv
sudo apt-get install python3-virtualenv
3.7.6 virtualenvwrapper
First, run:
sudo pip3 install virtualenvwrapper
Then, open ~/.bashrc
and add the following lines at the end of the file:
export WORKON_HOME=$HOME/.virtualenvs export PROJECT_HOME=$HOME/dev export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 source /usr/local/bin/virtualenvwrapper.sh
You may need to alter the first two lines to point to where you want your virtualenvs and projects located, respectively.
Finally, run:
source ~/.bashrc
virtualenvwrapper should now be available at all times.
3.8 Configure PostgreSQL
It is now time to set up the database. First, in the droplet's terminal, change the current user to the postgres superuser:
sudo su - postgres
Next create a database. Remember to use the database name that is in your DATABASES
Django setting.
createdb yourproject
Now create a new user. Again, this user name should match what is in your DATABASES
setting.
createuser -P yournamehere
Then enter the postgres shell and grant privileges on the new database to the new user:
psql postgres=# GRANT ALL PRIVILEGES ON DATABASE yourproject TO yournamehere; postgres=# \q
Finally, change back to your normal username:
su - yournamehere
3.9 Make virtualenv
Next, still on the droplet's terminal, create the virtualenv for your Django project:
mkvirtualenv --python=/usr/bin/python3 yourproject
The default python3 on the droplet, 3.4.2, was what I used to develop, so that's what I used in the virtualenv. Installing a different version of Python is a topic too far out of scope for this guide, but if you install one, point to its exectuable as in the example above to make it the default python of the virtualenv.
3.10 Set Up Droplet Environment Variables
First, read over Virtualenv and Environment Variables above if you have not already done so.
The virtualenv on the droplet should be set up the same way as the local one. Either copy and paste the contents of the postactivate
and predeactivate
files into the respective files on the remote machine, or use scp
to copy the files over (be aware this will overwrite the files on the remote machine).
To do the latter, use (on the local machine):
scp ~/.virtualenvs/yourproject/bin/postactivate \ yourproject:/home/yournamehere/.virtualenvs/yourproject/bin/ scp ~/.virtualenvs/yourproject/bin/predeactivate \ yourproject:/home/yournamehere/.virtualenvs/yourproject/bin/
3.11 Clone Project
The actual code for the Django project can now be placed on the remote machine. Hopefully, your project is under version control and you can clone it over to the remote. If you're using git and have pushed your repo to Github, that would look something like this:
# On the terminal connected to the droplet cd ~ mkdir dev cd dev/ git clone https://github.com/yournamehere/yourprojectrepo.git
Replace the URL with your own, of course.
In this case, the dev
directory is used to coincide with the path given for $PROJECT_HOME
earlier when setting up virtualenvwrapper. Use whatever name/path you'd like, but make sure the path matches $PROJECT_HOME
.
3.12 Transfer Static Files Not in Version Control (Optional)
I didn't keep some static files (images, fonts, etc.) under version control. If you have done something similar, now is the time to transfer any extra static files from your local environment over to the remote one.
To do this, use scp
with the -r
switch to recursively copy everything in a given directory.
Example:
# On the local machine scp -r ~/dev/yourprojectrepo/yourproject/static/images/ \ yourproject:/home/yournamehere/dev/yourprojectrepo/static/
Note scp
is also using SSH, and the yourproject:
in the second argument is the Host
name from the ~/.ssh/config
file.
3.13 Install Required Project Packages
Next, install the packages required to use your Django project. If you have a requirements.txt
(you should), navigate to the repository root on the remote machine and run:
# Activate the virtualenv workon yourproject # Install required packages pip install -r requirements.txt
Make sure to activate the virtualenv with workon
first.
Things that definitely need to be in requirements.txt
are Django
and psycopg2
(for PostgreSQL).
3.13.1 Install Gunicorn
If Gunicorn wasn't in your requirements.txt
, install it now with:
# With the virtualenv still activated
pip install gunicorn
3.14 Migrate
Now that the database is configured, the project code is on the remote machine, and Django and psycopg2 are installed for the virtualenv, the database can be set up for your project. If using Django 1.7+, doing this should be a simple matter of using migrations.
If you have not yet run makemigrations
, or the migrations aren't under version control for some reason, run this now (with the virtualenv still activated):
# From the project root directory
python manage.py makemigrations
Apply the migrations with:
# From the project root directory
python manage.py migrate
3.15 Create Django Superuser
If you need a superuser in Django (e.g. for the admin site), create one now with:
# From the project root directory
python manage.py createsuperuser
Follow the prompts to create the user.
3.16 collectstatic
Django's collectstatic
will copy all static files into the STATIC_ROOT
directory, as defined in the project's settings.
If your STATIC_ROOT
directory is inside your repository, make sure your version control system is set up to ignore it.9
For example, if your STATIC_ROOT
is yourprojectrepo/staticfiles/
, this line should be added to your .gitignore
file:
staticfiles/*
My manage.py
sets local settings by default (to be used with runserver
in the development environment), and I only define STATIC_ROOT
in my production settings, so when calling collectstatic
I set the settings to be used explicitly:
python manage.py collectstatic --settings=yourproject.settings.production
Answer "yes" to the prompt if the paths look correct.
3.17 Test Site with Development Server (Optional)
With the project source and the database set up on the droplet, it's possible to use the Django development server to test that the site is working properly, even before configuring Nginx and Gunicorn.
This step can be helpful to ensure that your site is in the working state that it was in during development before moving on. However, use the development server only momentarily, as it is inefficient and unsafe to use in actual production.
Prior to this, however, you must temporarily open up a port to allow outside access to the development server:
sudo ufw allow 8000/tcp
Start the development server with runserver
, specifying the IP of your droplet and the port you opened in the previous step.
# At the project root directory python manage.py runserver ip.of.droplet:8000 --settings=yourproject.settings.production
While the development server is running, you should be able to access your site from yourdomain.com:port
. Specifying the port is necessary because Nginx is not yet proxying requests from port 80.
When finished, kill the development server with Ctrl-C
. Then, delete the firewall record that opened port 8000:
sudo ufw delete allow 8000/tcp
3.18 Set Up Nginx
This section assumes the following Django settings for production:
STATIC_URL = '/static/' STATIC_ROOT = `/home/yournamehere/dev/yourprojectrepo/staticfiles/`
To set up Nginx, a server block must be created, and then enabled. The goal of the Nginx configuration in this guide is to serve all static files with Nginx, and proxy any other request to Gunicorn (and Django).
First, start the Nginx service with:
sudo service nginx start
Next, open a new Nginx configuration file with:
sudo nano /etc/nginx/sites-available/yourproject
The name of this file does not matter, but for the sake of consistency it makes sense to name it after your project.
Into this file, place the following:
server { listen 80; server_name yourproject; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /static/ { alias /home/yournamehere/dev/yourprojectrepo/staticfiles/; } }
Make the following substitutions, if necessary:
-
After
server_name
, use your project name or domain name. -
The path in the
alias
line should match yourSTATIC_ROOT
, and should be an absolute path as shown. -
The port on the
proxy_pass
line (8000 in the example) should be the port on which you intend Gunicorn to listen. Do not alter the localhost IP (127.0.0.1). -
The path after
location
should match yourSTATIC_URL
.
To activate the site for Nginx, place a symbolic link to the file you just created in the sites-enabled
directory:
cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/yourproject
Remove the file default
in this directory:
# In /etc/nginx/sites-enabled
sudo rm default
Finally, restart Nginx to activate the new site:
sudo service nginx restart
3.18.1 Test Nginx
Notice Nginx is proxying requests on port 80 to localhost. That makes it simple to test that Nginx is working properly using Django's development server, which by default listens on localhost.
# Navigate to project root cd ~/dev/yourprojectrepo/yourproject # Activate virtualenv, if not activated workon yourproject # Start the development server on port 8000 python manage.py runserver 8000 --settings=yourproject.settings.production
Make sure the port on the final line matches what's in the Nginx configuration file (proxy_pass
) in the previous section.
Now, when accessing your domain (or the IP of your droplet) from a web browser, the site should appear. Do not specify a port this time; just navigate to e.g. yourdomain.com.
Kill the development server with Ctrl-C
.
**Use the development server only momentarily to ensure that Nginx is working. It is inefficient and unsafe to use in actual production.**
3.18.2 If You Have Problems
Configuring Nginx is probably the most complicated step of this process. The configuration file above is about the simplest this file can be, but it's still easy to do something wrong the first time.
If, on trying to reach your site, you receive a 502 (bad gateway) error, that generally means nothing is listening on the port Nginx is trying to proxy to (8000 in the example above). Double check that the ports in the proxy_pass
line and runserver
call are the same.
For other problems, the Nginx error log may be helpful. On my system it is located at /var/log/nginx/error.log
(and requires sudo permission to read).
Finally, you could try calling runserver
with local settings (i.e. with DEBUG turned on) and see if that gives any more information about the problem.
3.19 Start Gunicorn
Once Nginx is working properly, it is time to start Gunicorn, the production HTTP server.
Go back to the terminal connected to your droplet. Make sure the virtualenv is still activated. To test that Gunicorn works, first start it as a normal process, like so:
# Run this at the project root directory gunicorn yourproject.wsgi --bind 127.0.0.1:8000
Note: Using gunicorn [APP_MODULE]
is preferred over gunicorn_django
.8
Again, make sure the port (8000 in the example above) matches what was in your Nginx configuration file.
Go to your domain (or droplet IP) in a browser. Hopefully, your site appears.
If your site is working, congratulations! You're basically done. Kill Gunicorn with Ctrl-C
so you can prepare to run it as a daemon (i.e. in the background).
First make a file for Gunicorn logs to be placed in. I made a logs
directory outside of the repository with a file name that specifies the project, like so:
cd ~/dev mkdir logs touch logs/yourproject_gunicorn.log cd yourprojectrepo/yourproject
Now, start gunicorn as a daemon:
# From the project root directory gunicorn yourproject.wsgi --bind 127.0.0.1:8000 --daemon \ --log-file ~/dev/logs/yourproject_gunicorn.log --workers=3
The Gunicorn docs recommend workers
be "in the 2-4 x $(NUM_CORES) range."
I found it useful to stick the above command in a script for reuse.
4 Maintenance
There are a few useful things to know and remember now that your site is deployed.
4.1 Stopping Gunicorn
Restarting Gunicorn may be necessary after pulling changes to your site's Python code. When you want to stop Gunicorn when it's running as a daemon, the simplest way is:
pkill gunicorn
That kills any running process called gunicorn
.
4.2 collectstatic
Remember that whenever you pull in new static files or changes to existing ones, collectstatic
must be run again to move the files to STATIC_ROOT
where Nginx can find them. This assumes that the STATIC_ROOT
directory is not under version control, which it should not be.9
5 Conclusion
At this point, your site should be fully deployed. Hopefully, this guide took some of the confusion and headache out of deployment.
6 Notes
-
For the inaugural article of this blog, the deployment of the blog itself seems a particularly appropriate topic. ↩
-
For reference, the source for this site at the time of initial deployment is available at this commit. ↩
-
The vast majority of this guide will also work with Django 1.6. The only non-applicable portion would be the Migrate section, where
syncdb
would be used instead. ↩ -
Just to be clear, I'm not advocating ending the names of repositories with "repo." It's just a convention used here so the generic name is unambiguous. ↩
-
The setting of
TEMPLATE_DEBUG
toFalse
is actually redundant. Turning offDEBUG
will automatically also turn offTEMPLATE_DEBUG
. ↩ -
As of March 2015, there is a message on namecheap.com implying the UI described here will change in the near future, so the instructions given may not remain completely accurate. ↩
-
For an overview of how SSH works, and why it is recommended, see the first few sections of this guide. ↩
-
Starting with Django 1.4,
wsgi.py
is added automatically bystartproject
, makinggunicorn_django
unnecessary. As of Gunicorn 18.0,gunicorn_django
is deprecated. The DigitalOcean deployment guide mistakenly advises to usegunicorn_django
. ↩ -
See the warning on this django-staticfiles docs page. ↩↩