Deploying Django Project to DigitalOcean

This chapter provides step by step guide to deploy Django projects to the DigitalOcean server.

DigitalOcean is one of the leaders VPS provider and their plans are very inexpensive – starting at just $5 per month.

If you don’t have a DigitalOcean account, use this link to sign up and you will get $10 free credit.

The git repository of the Django project used in this chapter is available here. But you can also follow along with your own project if you want to.

Creating Droplet

Login to your DigitalOcean account and you will be taken to the dashboard page.

Click the “Create” button at the top of the page and select Droplets.

In the Create Droplets page, under the Choose an image section select Ubuntu 16.04.

Select size of droplet:

Choose the region where the server will be located:

Additional options and SSH keys are optional.

Give a name to your droplet and hit the Create button.

Once the droplet is created you will receive an email containing the credentials required to login to the server.

Connecting to the Server

To connect to the server start the terminal and type the following command:

Note: Windows user can use PuTTY SSH client to connect to the server.

If you are logging in for the first time, you will be prompted for a password change.

Creating a User with limited access

You should never run applications as root user because if an attacker broke into your application then he instantly gains access to the whole system as a root user.

Further, a root user is very powerful full and thus can perform any action, even if it leads to a broken system. Do you want to format disks? or delete the /usr directory, just execute the command and it’s done. When you are root the system assumes you know what are doing.

For this reason, most applications in Linux is run as system users with restricted access.

To add an additional security layer some distributions ship with root access disabled. To perform the administrative action you will have to elevate privileges using the sudo command.

To create a new user enter the following command:

You will be asked for a password and some optional details.

Next, add the user to the sudo group by executing the following command:

Now, this user has the ability to execute administrative commands.

To login with your newly created user type su followed by the username:

Change your current working directory to the user’s home directory using the cd command:

In the next step, we will update our system and install some necessary packages.

Installing PIP, PostgreSQL and Nginx

To begin with, update the system using the following command:

Ubuntu 16.04 comes preinstalled with Python 3.5 so we don’t need to install Python. However, you do need to install pip.


To install PIP type the following:


Just like we did in the development, we will use virtualenv to create a virtual environment. Install virtualenv by typing:


PostgreSQL is the preferred database in the Django community. To install it type:

After the installation database server will start automatically. To test the status of the server type:

The output will be like this:


Nginx is a high-performance web server with very low footprint. We will use Nginx as a proxy server and to serve static files. To install it by type:

Once installed, Nginx will start automatically. We can check the status of the Nginx server by typing:

The output will be something like this:

We can also test whether Nginx is running or not by directly requesting a page from it. Open your browser and visit (replace with your IP). You should get a page like this:


Install RabbitMQ:

Creating Database and User

When you install PostgreSQL, it automatically creates a user named postgres to perform administrative tasks.

Before we do anything, let’s login with this account via psql and create a new database.

The output will be like this:

Create a new database by typing:

Next, create a new user by typing:

Finally, grant all privileges on database djangobin to db_user:

Creating Virtual Environment and Setting up Project

To clone the repository type the following command:

This will create a directory named djangobin inside your current working directory. Change the current working directory to djangobin using the cd command and create a new virtual environment:

Once done, activate the virtual environment and cd into the django_project directory (the same place where is located).

Next, install the dependencies from the requirements file.

Since we are using PostgreSQL database in production, we need to install PostgreSQL database adapter for Python, called psycopg2.

Create a JSON file to store sensitive configuration.

And add the following code to it:


Make sure to replace database credentials and API keys appropriately.

At this point, if you try to execute ./ file you will get an error because Django doesn’t know where your setting file is located:

Specify the settings file location temporarily using the export command:

With this command, we have put our application in production mode.

To create all the necessary tables in the djangobin database run migrate command:

Create a superuser for the project by typing:

Next, create a guest user and set its is_active attribute to False, so that the account can’t be used to login.

As said before, we will serve static files via Nginx server. To collect all the static files of the project in the static directory type the following command:


Nginx will face the outside world and will serve static files. However, it can’t communicate to Django application; it needs something that will run the application, feed it requests from the web, and return responses. This is where Gunicorn comes into the play.

Install Gunicorn by typing:

To server our application via Gunicorn type the following command:

This command starts Gunicorn with three worker processes and binds the socket to address. By default, Gunicorn only listens on the local interface (i.e, which means you can’t access your work from other computers on the network. To tell Gunicorn to listen on all interfaces bind the socket to

Open your browser and navigate to You should see a page like this:

Our application appears to be broken. That’s expected because we are not serving static files yet.

Setting up Nginx

Gunicorn is up and running, now we need to configure Nginx to pass the requests to it.

Start by creating a server configuration file in the /etc/nginx/sites-available/ directory:

Next, add the following configuration to the file:


Replace with your IP and path to the static directory to match your own file system.

To enable this configuration create a symbolic link in the sites-enabled folder.

Test the configuration file syntax:

Finally, restart the server for the changes to take effect.

Now, we are ready to test whether everything is working or not.

First off, start the celery worker along with celery beat by typing:

Hit Ctrl+Z, followed by bg to put the process into the background. Then, start the Gunicorn by typing:

Note that this time we are binding the socket to listen on the local interface (i.e because this time Nginx will face the outside world instead of Gunicorn.

Open your browser and visit You should see the index page of DjangoBin like this:

If you try to visit About or EULA flatpage you will get 404 error because these pages do not yet exist in the database. To create these pages login to Django admin site by visiting

Enter user and password we created earlier in this chapter.

Click on the “Add” link in front of “Flat pages” and add About and EULA page as follows:

While we are at it, let’s update the domain name in sites framework (django.contrib.sites), so that the sitemap framework can generate correct links.

Visit site list page at http://<your_ip_address>/admin/sites/site/. Click the domain name to edit and enter your server IP address in the Domain name and Display name fields, as follows:

Hit the save button to update the changes.

At last, visit the Contact page and submit a message. All the admins listed in ADMINS setting will receive an email as follows:

Things are working as expected but what would happen if the gunicorn or celery gets killed for some reason or DigitalOcean restarts your droplet after performing some maintenance?

In that case, users will see 502 Bad Gateway error:

We can prevent such errors by using a process monitoring tool called Supervisor.

Monitoring Process with Supervisor

Supervisor is a tool which allows us to monitor processes. Its job is to make sure certain processes keep running. If the process dies or gets killed for some reason, the Supervisor will start it automatically.

Install Supervisor by typing the following command:

Supervisor will start automatically after the installation. We can check it’s status by typing:

With Supervisor installed, we now have access to echo_supervisord_conf command to create configuration files.

The configuration file is a Windows-INI-style file, which defines the program to run, how to handle output, environment variables to pass to programs and so on.

When Supervisor starts, it automatically reads configurations from /etc/supervisor/conf.d/ directory.

Create a new configuration file by typing:

And then move it to /etc/supervisor/conf.d/ directory using the mv command:

If you open djangobin.conf file, you will find that it contains lots of sections and comments (lines starting with ;). Delete all the sections except the supervisor section at the top of the file. At this point, the file should look like this:


The next step is to add one or more [program:x] section in order for the Supervisor to know which programs to start and monitor. The x in the program section refers to the arbitrary unique label given to every section. This label will be used to manage the program.

The following table lists some common options we can define inside the [program] section.

Option Description Required
command This option specifies the path of the program to run. Yes
directory It specifies the directory where Supervisor will cd into before running the program No
autostart If set to true tells Supervisor to start the program when the system boots. No
autorestart If set to true tells Supervisor to start the program if it dies or gets killed. No
stdout_logfile The file to store the standard output of the process. No
stderr_logfile The file to store the standard error of the process. No

Open djangobin.conf file and add the following three [program] section towards the end of the file:


We also want Supervisor to pass DJANGO_SETTINGS_MODULE environment variable to all the three process. To do so, add environment option at the end of [supervisord] section as follows:


Tell Supervisor to load this new configuration type the following two commands:

You will have to execute these two commands every time you modify the configuration file.

Now, all our programs are up and running. At any time, you can check the status of programs by typing:

If we start supervisorctl program without passing any argument, it will start an interactive shell which allows us to control processes currently managed by Supervisor.

As you can see, in interactive mode supervisorctl starts by printing the status of currently managed programs.

Once you are inside the interactive shell, to see the available commands, type help:

Now, we can stop, start and restart process using the corresponding command followed by the program label.

To get the status of all the running processes type status:

We get also read the contents of the log file using the tail command:

By default, the tail command reads from stdout. Here is how we can read from stderr.

Finally, we can stop, start and restart all the processes at once as follows:

Once you are done hit Ctrl+C or type quit to exit the supervisorctl shell.

Supervisor is now monitoring all our processes. If any process dies or gets killed for some reason supervisor will start the process automatically.

As a test, try rebooting the droplet using the sudo reboot command. You will find that all the processes will start automatically on boot.

Congratulations, you have successfully deployed the DjangoBin project.

1 thought on “Deploying Django Project to DigitalOcean

Leave a Comment