Ora

How do I deploy a Django app on EC2?

Published in Django Deployment on AWS 9 mins read

Deploying a Django application on an Amazon EC2 instance involves setting up your server environment, transferring your code, configuring dependencies, and establishing a production-ready web server setup. This guide will walk you through the essential steps to get your Django project live on AWS.

1. AWS Account and EC2 Instance Setup

The first crucial step is to prepare your Amazon Web Services (AWS) environment.

Create AWS Account and Log In

If you don't already have one, visit the AWS Console to create a new account. Once registered, log in to access the AWS Management Console.

Launch an EC2 Instance

  1. Navigate to EC2 Dashboard: From the AWS Console, search for "EC2" and click on it to go to the EC2 dashboard.
  2. Launch Instance: Click the "Launch instance" button.
  3. Choose an Amazon Machine Image (AMI): Select a suitable Linux distribution. Ubuntu Server LTS (e.g., Ubuntu Server 22.04 LTS) is a popular and well-supported choice for Python/Django applications.
  4. Choose an Instance Type: Select an instance type based on your application's resource needs. For small projects or testing, t2.micro (eligible for Free Tier) is often sufficient.
  5. Configure Instance Details:
    • Key Pair: Create a new key pair or choose an existing one. This .pem file is essential for securely connecting to your instance via SSH. Download it and keep it secure.
    • Network Settings (Security Group): Configure a security group to allow inbound traffic. At a minimum, you'll need:
      • SSH (Port 22): To connect to your instance. Restrict this to your IP address for enhanced security.
      • HTTP (Port 80): For web traffic.
      • HTTPS (Port 443): For secure web traffic (highly recommended for production).
  6. Launch Instance: Review your configurations and launch the instance.

Connect to Your EC2 Instance

Once your instance is running, you can connect to it using SSH. Ensure your key pair file has the correct permissions (chmod 400 /path/to/your-key-pair.pem).

ssh -i /path/to/your-key-pair.pem ubuntu@YOUR_EC2_PUBLIC_IP

Replace /path/to/your-key-pair.pem with the actual path to your key file and YOUR_EC2_PUBLIC_IP with your instance's public IPv4 address.

2. Prepare EC2 Instance for Django Deployment

After connecting to your EC2 instance, you need to set up the necessary software and dependencies for your Django project.

Update System Packages

It's always a good practice to update your package lists and upgrade existing packages.

sudo apt update
sudo apt upgrade -y

Install Python, Pip, and Virtualenv

Django applications require Python, pip for package management, and virtualenv for isolating project dependencies.

sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools -y
sudo pip install virtualenv

If your Django project uses PostgreSQL, you'll also need to install the development headers for psycopg2, which is a common database adapter.

sudo apt install libpq-dev -y

Install Git

To clone your Django project from a version control repository (like GitHub or GitLab):

sudo apt install git -y

3. Deploy Your Django Project on AWS EC2 Instance

With your EC2 instance configured, it's time to get your Django project onto the server.

Clone Your Project

Navigate to a suitable directory (e.g., /var/www/) and clone your Django project from your Git repository.

cd /var/www/
sudo git clone YOUR_PROJECT_REPOSITORY_URL your_project_name
sudo chown -R ubuntu:ubuntu your_project_name # Adjust ownership for your user
cd your_project_name

Replace YOUR_PROJECT_REPOSITORY_URL and your_project_name accordingly.

Set Up Python Virtual Environment

It's best practice to install project dependencies in a virtual environment to avoid conflicts with system-wide Python packages.

virtualenv venv
source venv/bin/activate

Install Django Project Dependencies

Install all packages listed in your requirements.txt file, which should specify all your project's dependencies.

pip install -r requirements.txt

Configure Django Settings

Edit your Django project's settings.py file to adapt to the production environment:

  • DEBUG = False: Crucially, set this to False in production.
  • ALLOWED_HOSTS: Add your EC2 instance's public IP address, public DNS name, and any domain names your application will use.
    ALLOWED_HOSTS = ['YOUR_EC2_PUBLIC_IP', 'YOUR_EC2_PUBLIC_DNS', 'yourdomain.com', 'www.yourdomain.com']
  • Database Configuration: Update DATABASES settings if you're using an external database like AWS RDS PostgreSQL.
  • Static Files: Configure STATIC_ROOT and MEDIA_ROOT. These settings define where Django will collect static files and where user-uploaded media will be stored.
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles')
  • Secret Key: Ensure your SECRET_KEY is not hardcoded directly in settings.py. Use environment variables or a configuration management tool for sensitive data.

Run Migrations and Collect Static Files

Apply any database schema changes and collect all static files into the STATIC_ROOT directory.

python manage.py makemigrations # If you have new models
python manage.py migrate
python manage.py collectstatic --noinput

4. Configure a Production Web Server

For production deployment, you'll use a Gunicorn (WSGI HTTP Server) to serve your Django application and Nginx (reverse proxy) to handle client requests, serve static files, and forward dynamic requests to Gunicorn.

Install and Configure Gunicorn

Gunicorn is a Python WSGI HTTP Server that interfaces with Django, allowing it to serve HTTP requests.

pip install gunicorn

Test Gunicorn to ensure it runs your Django project (replace your_project_name.wsgi with your actual WSGI file path, typically your_project_name.wsgi within your main Django project directory).

gunicorn --bind 0.0.0.0:8000 your_project_name.wsgi

You can access your app at http://YOUR_EC2_PUBLIC_IP:8000 for a brief test. Press Ctrl+C to stop it.

For persistent operation, create a Systemd service for Gunicorn to manage its lifecycle.

sudo nano /etc/systemd/system/gunicorn.service

Paste the following (adjust User, WorkingDirectory, and ExecStart paths to match your setup):

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/var/www/your_project_name
ExecStart=/var/www/your_project_name/venv/bin/gunicorn --workers 3 --bind unix:/var/www/your_project_name/your_project_name.sock your_project_name.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
TimeoutStopSec=5s

[Install]
WantedBy=multi-user.target

Enable and start the Gunicorn service:

sudo systemctl daemon-reload
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicorn # Check if it's running correctly

Install and Configure Nginx

Nginx will act as a high-performance reverse proxy, handling requests from clients and passing them to Gunicorn for Django-specific responses. It also efficiently serves your static and media files directly.

sudo apt install nginx -y

Create a new Nginx configuration file for your Django project:

sudo nano /etc/nginx/sites-available/your_project_name

Paste the following (adjust server_name, root, and proxy_pass):

server {
    listen 80;
    server_name YOUR_EC2_PUBLIC_IP yourdomain.com www.yourdomain.com; # Add your EC2 IP and domain names

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /var/www/your_project_name; # Path to your Django project root where staticfiles are collected
    }

    location /media/ {
        root /var/www/your_project_name; # Path to your Django project root where mediafiles are stored
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/var/www/your_project_name/your_project_name.sock; # Gunicorn socket path
    }
}

Create a symbolic link to enable the Nginx configuration and remove the default Nginx config to avoid conflicts:

sudo ln -s /etc/nginx/sites-available/your_project_name /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default

Test the Nginx configuration for syntax errors and restart Nginx to apply changes:

sudo nginx -t
sudo systemctl restart nginx
sudo systemctl enable nginx # Ensure it starts on boot

5. Database Setup (Optional but Recommended)

For production, it's often better to use a managed database service like AWS RDS (Relational Database Service) for PostgreSQL or MySQL, rather than running a database directly on your EC2 instance. RDS handles backups, scaling, and maintenance, significantly improving reliability and ease of management.

  • AWS RDS: Create a PostgreSQL or MySQL instance in the AWS RDS console.
  • Security Group: Ensure your RDS instance's security group allows inbound connections from your EC2 instance's security group on the appropriate database port (e.g., 5432 for PostgreSQL, 3306 for MySQL).
  • Django Settings: Update your settings.py with the RDS endpoint, port, database name, user, and password.

6. Accessing Your Application

Once Nginx and Gunicorn are properly configured and running, your Django application should be accessible via your EC2 instance's public IP address or associated domain name (if you configured DNS) directly on port 80 (HTTP). If you've also configured HTTPS, it will be accessible on port 443.

7. Enhance Security and Maintainability

Component Description Best Practice
HTTPS Secure communication between client and server. Use Certbot with Let's Encrypt for free SSL certificates and automatic renewal.
Environment Variables Store sensitive data (e.g., SECRET_KEY, database credentials). Use a library like python-decouple or directly set variables in the Gunicorn service file to keep secrets out of your codebase.
Logging Monitor application health and troubleshoot issues. Configure Django's logging and regularly monitor Nginx and Gunicorn logs for errors and performance.
Firewall Restrict inbound and outbound traffic. Leverage AWS Security Groups to allow only necessary traffic (e.g., ports 22, 80, 443).
Backup Ensure data recovery in case of failure. Implement regular backups of your database (e.g., RDS automated backups) and application code.
Monitoring Track application performance and resource usage. Use AWS CloudWatch or third-party tools (e.g., Datadog, New Relic) to monitor CPU, memory, and network usage.
CI/CD Automate code deployment. Implement a Continuous Integration/Continuous Deployment (CI/CD) pipeline (e.g., AWS CodePipeline, GitHub Actions) to streamline updates.

Deploying a Django application on EC2 provides fine-grained control over your server environment, allowing you to tailor it precisely to your project's needs.