Hosting a Django website on EC2
Tags: aws, cloud, django, apache
Published: 2023-02-12 14:16:43

## Introduction

I have always wanted to deploy a website on my own web server. However, owning a small PC or a laptop just to use as a Linux server was quite bothersome. To assist my laziness, Amazon provides a very smooth service as to what we refer as the 'cloud'. I am pretty sure that almost everyone has at least heard of the word 'cloud' in today's world. In this post, I will be using the Amazon cloud elsewise called the AWS (Amazon Web Services) to host my django website on its EC2 instance. 

## EC2 Instance

Well according to Amazon themselves, Amazon Elastic Compute Cloud (Amazon EC2) provides scalable computing capacity in the Amazon Web Services (AWS) Cloud.

EC2 instances are virtual machines that run on the Amazon Web Services (AWS) infrastructure. So yeah now you don't need to physically have a web server in your room to host your own website! 

Another attractive trait is that EC2 instances are created from Amazon Machine Images (AMIs), which are pre-configured virtual machine images. This means that you don't even need to install a Linux or maybe Windows server yourself! Enough talk, I will now go straight into how to actually do this 😉

> If you don't have an account with the AWS cloud, I would recommend you to create one. You can check this article and follow the steps if you are pretty new with the cloud: https://k21academy.com/amazon-web-services/aws-solutions-architect/create-aws-free-tier-account/

## Creating an EC2 Instance

Yes, we need to create the server first. But no worries, it is quite simple and will take few clicks. 

Once you are logged in to your AWS console, you will be able to see countless services under "services" bar.


![Services](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwfpfnce40ywyufd8lic.png)

No need to panic as we are only looking at one and that is the EC2 instance service. 

Once you click on the "EC2", you will redirected to the EC2 dashboard which should look like this


![EC2 Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wjhdfvtr8h0dtkgz2vu.png)
*👉 Just a note that I already have a web server running so that is why it is showing 1 against "Instances(running)"*

Right under this table, you should be able to see "Launch instance"


![Launch instance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/06pzk6w20v53kmeb43j8.png)

Once you are in, there will be an option to name your instance, choose an AMI, the operating system image that you want to run on your instance. 


![Name and AMI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93h8b99id7yqdwtgbwvw.png)
You can choose whatever but just be careful as some images cost you


![free](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dathw3cao4rgdnselch5.png)
*✔free tier eligible*

![Paid](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1husgra8df5smg2s1lv2.png)
*❌Not free!*

Once you have chosen your OS image you will be greeted to choose an instance type. The default option would probably be the Free tier compatible `t2.micro` instance

![t2.micro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yy75isb9szb1b4t9tx88.png)

Now, we need a key pair. This is used for SSH-ing to your EC2 instance. Proceeding without a key pair isn't recommended but it is possible to select none. 


![Key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lc7pq1qfl0ot30pwzj75.png)

Next comes the network settings from where you can choose your VPC (Virtual Private Cloud)

![VPC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qt4yydov660i3l3xkh3u.png)

Inside this network setting, there is very important thing you need to set up, the firewall


![Firewall](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nhsiecnr5hiqi6kzdop0.png)
In the AWS world, these are called 'security groups'. As you can see that the name and description along with SSH port 22 inbound rule is set by default.

I will add a Custom TCP port 8000 and a HTTP port 80 allowed from anywhere rule so that we can actually test our django website running


![Security](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11l3x4v76pjmz4jo67yt.png)

*You can always limit the IP address to whatever range or specific IP addresses as you like*

And this is it. You can just click on "Launch Instance". 

You can see that your instance is running


![running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hehdae3m1z1i32t3zhf.png)

You can now access your instance using SSH or directly via AWS console.

## Deploying your django website

This is the interesting part now. Once you are in your instance it is time to install the apache server and related tools

```bash
sudo apt-get update
```

```bash
sudo apt-get install python3-pip apache2 libapache2-mod-wsgi-py3
```

The first command is to update apt package manager in Ubuntu. The second command installs apache2, pip3, and mod-wsgi(module used in Apache, for running Django server, and will be enabled automatically upon installation)

We will also need the virtual env to help with dependencies

```bash
sudo pip3 install virtualenv
```

Creating an empty directory

```bash
mkdir django
```

Now inside this directory I will be setting up the virtualenv as well as cloning my website from Github

```bash
cd django
```

```bash
virtualenv myprojectenv
git clone "https://github.com/<username>/<repository name>.git" 
```

Activating the virtualenv

```bash
source myprojectenv/bin/activate
```

Once the virtualenv is activated, we have to collect static files. For this, we need to use the vim editor

```bash
sudo vi config/settings.py
```
*👉`config` is the project name that contains the `settings.py`*

Once we are inside the `settings.py`, we just need to add this line at the end

```python
import os

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATICFILES = [STATIC_ROOT]
```
Also, we need to allow the instance's public IP address as well

```python
ALLOWED_HOSTS=['EC2 Public IP address']
```

Finally, as we are deploying in the production environment, we need to set debug to false

```bash
DEBUG = False
```
This is it for the `settings.py` file

Installing the required modules with the pip command
```bash
pip install -r requirements.txt
```
*👉 if your repository doesn't have a `requirements.txt` file, please ensure that you have all of the dependencies installed*

Migrating the database and collecting static file with the following 
```bash
python manage.py makemigrations

python manage.py migrate

python manage.py collectstatic
```
This will allow you to actually see your django website running if your run your django local server with the port 8000. However, this is not the optimal way as you don't want to use that. Instead, we want our website to run on the Apache server

## Apache Server Configuration

We just need to tweak the configuration file that's all 😉. To access the config file for apache,

```bash
sudo vi /etc/apache2/sites-available/000-default.conf
``` 
Just need to replace the file contents with this
```bash
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
Alias /static /home/ubuntu/django/Test/static
<Directory /home/ubuntu/django/Test/static>
Require all granted
</Directory>
<Directory /home/ubuntu/django/Test/config>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIPassAuthorization On
WSGIDaemonProcess Test python-path=/home/ubuntu/django/Test/  python-home=/home/ubuntu/django/myprojectenv
WSGIProcessGroup Test
WSGIScriptAlias / /home/ubuntu/django/Test/config/wsgi.py
</VirtualHost>
```
*👉 As mentioned before, the `config` is the project name and `Test` is repository name that I cloned. You will have to make sure the paths are correct and according to naming of directories and files in the Django project*

And the configuration is done! But not so fast, there are some final touches. 

Changing some permissions and ownership of the directory
```bash
chmod 664 ~/django/Test/db.sqlite3

sudo chown :www-data ~/django/Test/db.sqlite3
sudo chown :www-data ~/django/Test
sudo chown :www-data ~/django/Test/config
```
And this is it! You just need to restart the apache service and you are good to go 😉

Access your website over the internet using the EC2 instance's public IP address ✔

```bash
sudo service apache2 restart
```

👉 If for some reason the above gives a permission error, you can try giving 755 permissions to the ~ directory
```bash
sudo chmod 755 /home/ubuntu
```

## Conclusion

This was only an illustration of how to set up Apache and Django on AWS

When installing a production server, a number of additional variables are involved

**Security** is one of the most crucial aspects to pay attention to

We can restrict access to the server to a small number of IP addresses, which is great for testing and development

AWS technologies like **Security Groups** and **IAM** users can be useful for all of these uses

Final note that Django programs may be more easily deployed by using the **AWS Beanstalk service**