Deploy Django app on AWS
Deploy and host a django application on AWS EC2 instance using Nginx as the webserver and Gunicorn as WSGI
Nginx is an open-source web server that, since its success as a web server, is now also used as a reverse proxy , HTTP cache, and load balancer.
WSGI used to forward request from a web server to a python backend.
Please Refer: HTTP request-response lifecycle
1. Initial setup
Create EC2 instance
Create/Launch EC2 instance: /tags/ec2/
- Enable ssh to server - to connect to EC2 server
EC2 > security group > Edit inbound rules > Allow SSH
Connect to EC2 instance
# Connect
ssh -i "name.pem" ubuntu@host
Install the latest patch of python 3.6
Python and PIP installation: /tags/python-setup/
Update and install python-pip and virtualenv
sudo apt-get update && sudo apt-get -y upgrade && sudo apt install python3-pip
2. Install git and configure user and email and clone repo
# Install
sudo apt-get install git-core
# Configure
git config --global user.name "Amrit"
git config --global user.email "[email protected]"
# Clone Repo
git clone -b aws-django https://github.com/amrit94/deployment-demo.git
- Fix clone/update issue
sudo apt install gh
gh auth login
gh repo clone amrit94/deployment-demo
3. Make virtual-env and install requirements.txt
# Install
pip install virtualenv
sudo apt install python3.8-venv
# Make Venv
mkdir ~/.virtualenvs/
cd ~/.virtualenvs/
python3.6 -m venv testvenv
# Activate venv
source ~/.virtualenvs/testvenv/bin/activate
# Install all requirements.txt
cd ~/deployment-demo/
pip install -r requirements.txt
Issue
# psycopg2 --> installation issue
pip install psycopg2-binary
sudo apt install libpq-dev
# Python.h issue
sudo apt install libpython3.6-dev
4. Setup Database
4.1 Install Postgresql and configure new role and grant all permissions
sudo apt-get install postgresql
sudo /etc/init.d/postgresql start
sudo -u postgres psql
postgres=# CREATE DATABASE testdb;
postgres=# CREATE ROLE testuser WITH LOGIN PASSWORD 'password';
postgres=# GRANT ALL PRIVILEGES ON DATABASE testdb TO testuser;
4.2 OR Install Mysql and add new user with all the privileges
sudo apt-get update
sudo apt-get install mysql-server (Remember the password entered for root user)
mysql_secure_installation
mysql -u root -p
mysql> CREATE DATABASE testdb;
mysql> CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON * . * TO 'testuser'@'localhost';
mysql> \q
sudo apt-get install python-mysqldb
mysql -u testuser -p (Now you are logged in as testuser user)
4.3
python manage.py migrate
5. Test your server
Django has inbuilt webserver, it is used in development server but not in production, because
- Single-threaded server`
- Can serve only one request at a time
Test - Is the application working properly
- Update Security group -
For test allow all traffic- EC2 > security group > Edit inbound rules > Map: All traffic to Anywhere
python manage.py runserver 0.0.0.0:8000
- Visit
- http://public_ip:8000/
- http://public_ip:8000/admin
By using inbuilt webserver there will be no issue to access static file
5. Setup Gunicorn
pip install gunicorn
5.1 Testing Gunicorn’s Ability to Serve the Project
gunicorn --bind 0.0.0.0:8000 kharchapani.wsgi
Visit:
http://public_ip:8000/
Static files are directly not accessible for --bind 0.0.0.0:8000.
To Enable add below line to access
# seting.py
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# urls.py
from django.conf.urls.static import static
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
5.2 Setup gunicorn to run as a service
5.2.1 Create a Gunicorn systemd Service File
# sudo vim /etc/systemd/system/growthqr.service
# Add below line in 'growthqr.service' file
[Unit]
Description=growthqr daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/growthqr
ExecStart=/home/ubuntu/.venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 growthqr.wsgi:application
[Install]
WantedBy=multi-user.target
5.2.2 Start the server
- Start the server and check the status
sudo systemctl start gunicorn
sudo service gunicorn status
- Enable the server to automatically start at boot
sudo systemctl enable gunicorn
5.2.3 Restart gunicorn
If you make changes to the /etc/systemd/system/gunicorn.service file, reload the daemon to reread the service definition
and restart the Gunicorn process by typing
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
- Check
gunicorn process logsby typing
# from start
sudo journalctl -u gunicorn
# live logs
sudo journalctl -f -u gunicorn
- Try
Visit:
http://public_ip:8000/
6. Setup Nginx
sudo apt-get install nginx
Update ExecStart of gunicorn.service
# sudo vim /etc/systemd/system/gunicorn.service
ExecStart=/home/ubuntu/.virtualenvs/testvenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Deployment-demo/myproject.sock myproject.wsgi:application
Configure Nginx to Proxy Pass to Gunicorn
# sudo vim /etc/nginx/sites-available/kharchapani
server {
listen 80;
server_name public_ip_address;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/ubuntu/kharchapani;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/kharchapani/kharchapani.sock;
}
}
Enable the file by linking it to the sites-enabled directory:
sudo ln -s /etc/nginx/sites-available/kharchapani /etc/nginx/sites-enabled
- Visit:
- http://public_ip
sudo nginx -t
sudo systemctl restart nginx
sudo tail -F /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
7. Troubleshooting Nginx and Gunicorn
connect() to unix:/home/sammy/myproject/myproject.sock failed (2: No such file or directory)
Turn DEBUG=True - this may show you actual error
connect() to unix:/home/sammy/myproject/myproject.sock failed (13: Permission denied)
This indicates that Nginx was unable to connect to the Gunicorn socket because of permissions problems.
8. Domain Mapping
A domain_name ip_address
Update nginx setting
# sudo vim /etc/nginx/sites-available/kharchapani
server_name replace_this_with_domain_name;
Production Security group
- Update Security group -
Only HTTP, HTTPS and SSH traffic- EC2 > security group > Edit inbound rules > Map: All traffic to Anywhere
9. Initial Server Setup with Ubuntu
- Will ignore this for now
Reference
- https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04
- https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04
- https://medium.com/analytics-vidhya/deploying-django-apps-e2f4d4f355a1
- https://medium.com/saarthi-ai/ec2apachedjango-838e3f6014ab
- https://www.freecodecamp.org/news/django-uwsgi-nginx-postgresql-setup-on-aws-ec2-ubuntu16-04-with-python-3-6-6c58698ae9d3/