Deploying a Django application on Ubuntu
Tags: python, django, devops, ubuntu
Published: 2023-05-12 16:29:28

*This article was originally written by [Muhammed Ali](https://www.honeybadger.io/blog/authors/muhammedali/) on the [Honeybadger Developer Blog](https://www.honeybadger.io/blog/deploy-django-ubuntu/).*

Using a [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_service) like Heroku or Netlify is cool, but using tools like these comes at the cost of flexibility. You can’t choose the firewall you want, and all your data will be stored in the PaaS provider’s database. Additionally, the PaaS provider may not provide support for a particular tool.

There is a way to have flexibility, security, and increased compatibility and integration with other tools: deploy your application to a server.

In this tutorial, I will show you how to get a Linux server from Linode, set it up with the security configuration, and then deploy the Django application. You will be building a lead management application for this tutorial, but if you already have an application, you can skip this step.

You can find the final product on [GitHub](https://github.com/khabdrick/django-linode-ubuntu).

## Prerequisites

- An understanding of basic Linux commands.
- A basic understanding of Django.

## Build a Django Application

We will primarily use the Django admin, so the lead management application will only have a model. For authentication, we will use the inbuilt Django authentication system.

Create a folder for your project and enter it using `cd` to get going. To begin a project and a Django app, enter the following command:

```bash
django-admin startproject lead . && python3 manage.py startapp app
```

Now, update the `INSTALLED_APPS` in the `settings.py` file to include the app you just created.

```python
INSTALLED_APPS = [
     …
    'app',
]
```

The `Lead` model will have the name, email, lead_owner and some other fields that you will see in the following code. The lead_owner file will have a foreign key to the Django user authentication model. Therefore, if we create a superuser, we will be able to use it to create new leads and test the application. Open the file `app/models.py` and paste the following code:

```python
from django.db import models
from django.contrib.auth.models import User

class Lead(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(max_length=100, unique=True)
    details = models.CharField(max_length=500, blank=False)
    lead_owner = models.ForeignKey(
        User, related_name="lead", on_delete=models.CASCADE, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
```

Next, you’ll need to update the `admin.py` file so that you can access the models you just created in the admin panel. You can do this by pasting the following code into the `app/admin.py`:

```python
from django.contrib import admin
from .models import Lead

admin.site.register(Lead)
```

## Get an Ubuntu 20.04 Server from Linode

[Linode](https://www.linode.com/) is one of the most popular providers of Linux cloud solutions and services. We will get the Ubuntu 20.04 server we need for this tutorial from them. If you don’t have an account, go ahead and create one, and you will be given a $50 credit to get started with their services.

After authentication, click the “**Create Linode**" button.

Now, select server configurations based on requirements, but make sure the “Distribution” is Ubuntu 20.04. Vultr has a tutorial on how to [generate SSH keys](https://www.vultr.com/docs/how-do-i-generate-ssh-keys/?_gl=1*163ipso*_ga*MTAxNjc2Nzc5My4xNjUzMDc2NjY3*_ga_K6536FHN4D*MTY1MzA3NjY2MC4xLjEuMTY1MzA3NzYyMi4w). Then, click the “**Create Linode**" button.

Your server will run in a minute, and you will be provided with the details of how to access it.

![Linux server running](https://www.honeybadger.io/images/blog/posts/deploy-django-ubuntu/server.png)

We will connect to the server we just created using Secure Shell (SSH). The SSH protocol provides a secure way to connect to other servers over a network.

To access your remote server, run the following command. Replace `root@178.79.130.101` with the IP address you were given by Linode.

```bash
ssh root@178.79.130.101
```

When asked, “Are you sure you want to continue connecting (yes/no/[fingerprint])?”, type "yes” and press the “**Enter**” key.

## Deploy a Django App to a Remote Server

Deployment, in this case, just means we will copy our Django application folder to a folder on the remote server. We will use the `scp` (secure copy) command to securely copy the content of the folder that houses the whole application (`django-linode-ubuntu`). On your local machine, run the command below to copy the application to the remote server. Don’t forget to change `178.79.130.101` in the command below to the IP address of your remote server.

```bash
scp -r django-linode-ubuntu root@178.79.130.101:project
```

The command above first creates a new directory named `project` in the remote server and then pastes the contents of `django-linode-ubuntu`.

## Set Up a Deployed Application on a Ubuntu Server

In this section, you will do everything necessary to make your application work properly on the remote server. Then, you will be able to access the application on your browser. You will first set up the firewall for network security, use NGINX to reverse host to the IP address of your remote server, and then run your application on the server.

### Set Up a Firewall for Network Security

Setting up a firewall on your server provides protection for your server network and sets rules for incoming and outgoing requests to your server. We will use [Uncomplicated Firewall](https://help.ubuntu.com/community/UFW) (UFW) in this tutorial; it’s easy to set up, and you don't need to install anything new on your server.

UFW comes with Ubuntu by default, but its activity is disabled. You can enable UFW on your server by running the following command:

*Note: Make sure that you have SSH into your remote server.*

```bash
ufw enable
```

Allow all outgoing ports by running the command below. You can allow all outgoing requests because it doesn’t pose a threat from external sources.

```bash
ufw default allow outgoing
```

Run the command below to prevent access to your server from the outside world.

```bash
ufw default deny incoming
```

When you ran the command above, you also blocked SSH requests. To continue using SSH to access our server, you must enable SSH. To do this, run the following command:

```bash
ufw allow ssh
```

Allow `http/tcp` traffic on the firewall so that your browser can access your app.

```bash
sudo ufw allow http/tcp
```

### Set Up NGINX as a Reverse Proxy

In this section, you will need [NGINX](https://www.nginx.com/) for reverse proxy, which allows your server to listen for the application running and then redirect requests to your remote IP address.

To do this, install NGINX by running the following command:

```bash
apt-get install nginx
```

Remove the default configuration file provided by the NGINX installation so that we can create our own.

```bash
rm /etc/nginx/sites-enabled/default
```

Run `nano /etc/nginx/sites-enabled/project` to create and open a new NGINX configuration file and paste the NGINX script below; then, save the file. The code below will send requests to your IP address at [http://localhost:8000](http://localhost:8000/) because it is the host where your application will run. If you have a domain name, you can replace the IP address in the script.

```text
    server{
        listen 80;
        server_name 178.79.130.101;

        location / {
                proxy_pass http://localhost:8000;
                include /etc/nginx/proxy_params;
                proxy_redirect off;
            }
    }

```

Now, restart NGINX to set the new configurations you just created.

```bash
sudo systemctl restart nginx
```

## Running the Application

Next, you’ll need to add your IP address to the `ALLOWED_HOSTS` in the `settings.py` file so that Django can recognize it. We will do this in the server by running the command below to open the `settngs.py` file, edit `ALLOWED_HOSTS`, and then save.

```bash
nano project/lead/settings.py
```

![Editing settings.py file](https://www.honeybadger.io/images/blog/posts/deploy-django-ubuntu/settings.png)

Django is not installed on the server yet, but you can install it by running the following command:

```bash
pip install django==3.2
```

Now, run the migration commands so that you can create a superuser and start working with the models you created for the application. Make sure that you have inserted `cd` into the root of your project (`/project`).

```bash
python3 manage.py makemigrations && python3 manage.py migrate
```

Create a superuser by running the command below and filling in the prompt:

```bash
python3 manage.py createsuperuser
```

Now, you can use the credentials inputted above to access the admin of your application ([http://178.79.130.101](http://178.79.130.101/)[/admin/](http://127.0.0.1:8000/admin/)). Once that is done, you can run your application by running this command:

```bash
python3 manage.py runserver
```

You will now be able to access your application with the IP address of your server.

![Django application running](https://www.honeybadger.io/images/blog/posts/deploy-django-ubuntu/running-app.png)

## Conclusion

In this tutorial, you built a lead management application. Then, you learned how to get a Linux server from Linode, set up the security configuration, set reverse proxy with NGINX, and run your Django application on a server.

You can build on what you’ve learned in this tutorial by going through the [Django deployment checklist](https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/) and trying to find solutions to each of the items.