Django Deployment to Ubuntu 18.04
In this guide I will go through all the steps to create a VPS, secure it and deploy a Django application. This is a summarized document from this digital ocean doc
Any commands with "$" at the beginning run on your local machine and any "#" run when logged into the server
Create A Digital Ocean Droplet
Use this link and get $10 free. Just select the $5 plan unless this a production app.
Security & Access
Creating SSH keys (Optional)
You can choose to create SSH keys to login if you want. If not, you will get the password sent to your email to login via SSH
To generate a key on your local machine
ssh-keygenHit enter all the way through and it will create a public and private key at
~/.ssh/id_rsa
~/.ssh/id_rsa.pubYou want to copy the public key (.pub file)
cat ~/.ssh/id_rsa.pubCopy the entire output and add as an SSH key for Digital Ocean
Login To Your Server
If you setup SSH keys correctly the command below will let you right in. If you did not use SSH keys, it will ask for a password. This is the one that was mailed to you
ssh root@YOUR_SERVER_IPCreate a new user
It will ask for a password, use something secure. You can just hit enter through all the fields. I used the user "djangoadmin" but you can use anything
adduser djangoadminGive root privileges
usermod -aG sudo djangoadminSSH keys for the new user
Now we need to setup SSH keys for the new user. You will need to get them from your local machine
Exit the server
You need to copy the key from your local machine so either exit or open a new terminal
exitYou can generate a different key if you want but we will use the same one so lets output it, select it and copy it
cat ~/.ssh/id_rsa.pubLog back into the server
ssh root@YOUR_SERVER_IPAdd SSH key for new user
Navigate to the new users home folder and create a file at '.ssh/authorized_keys' and paste in the key
cd /home/djangoadmin
mkdir .ssh
cd .ssh
nano authorized_keysPaste the key and hit "ctrl-x", hit "y" to save and "enter" to exit
Login as new user
You should now get let in as the new user
ssh djangoadmin@YOUR_SERVER_IPDisable root login
sudo nano /etc/ssh/sshd_configChange the following
PermitRootLogin no
PasswordAuthentication noReload sshd service
sudo systemctl reload sshdSimple Firewall Setup
See which apps are registered with the firewall
sudo ufw app listAllow OpenSSH
sudo ufw allow OpenSSHEnable firewall
sudo ufw enableTo check status
sudo ufw statusWe are now done with access and security and will move on to installing software
Software
Update packages
sudo apt update
sudo apt upgradeInstall Python 3, Postgres & NGINX
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curlPostgres Database & User Setup
sudo -u postgres psqlYou should now be logged into the pg shell
Create a database
CREATE DATABASE <your_database_name>;Create user
CREATE USER <username> WITH PASSWORD 'abc123!';Set default encoding, tansaction isolation scheme (Recommended from Django)
ALTER ROLE <username> SET client_encoding TO 'utf8';
ALTER ROLE <username> SET default_transaction_isolation TO 'read committed';
ALTER ROLE <username> SET timezone TO 'UTC';Give User access to database
GRANT ALL PRIVILEGES ON DATABASE <your_database> TO <username>;Quit out of Postgres
\qVirtual Environment
You need to install the python3-venv package
sudo apt install python3-venvCreate project directory
mkdir pyapps
cd pyappsCreate venv
python3 -m venv ./venvActivate the environment
source venv/bin/activateGit & Upload
Pip dependencies
From your local machine, create a requirements.txt with your app dependencies. Make sure you push this to your repo
pip freeze > requirements.txtCreate a new repo and push to it (you guys know how to do that)
Clone the project into the app folder on your server (Either HTTPS or setup SSH keys)
# git clone https://github.com/yourgithubname/<your_project>.gitInstall pip modules from requirements
You could manually install each one as well
# pip install -r requirements.txtLocal Settings Setup
Add code to your settings.py file and push to server
try:
from .local_settings import *
except ImportError:
passCreate a file called local_settings.py on your server along side of settings.py and add the following
- SECRET_KEY
- ALLOWED_HOSTS
- DATABASES
- DEBUG
- EMAIL\_\*Run Migrations
python manage.py makemigrations
python manage.py migrateCreate super user
python manage.py createsuperuserCreate static files
python manage.py collectstaticCreate exception for port 8000
sudo ufw allow 8000Run Server
python manage.py runserver 0.0.0.0:8000Test the site at YOUR_SERVER_IP:8000
Add some data in the admin area
Gunicorn Setup
Install gunicorn
pip install gunicornAdd to requirements.txt
pip freeze > requirements.txtTest Gunicorn serve
gunicorn --bind 0.0.0.0:8000 <app_name>.wsgiYour images, etc will be gone
Stop server & deactivate virtual env
<ctrl-c>
deactivateOpen gunicorn.socket file
# sudo nano /etc/systemd/system/gunicorn.socket- Copy this code, paste it in and save
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.targetOpen gunicorn.service file
# sudo nano /etc/systemd/system/gunicorn.service- Copy this code, paste it in and save
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=djangoadmin
Group=www-data
WorkingDirectory=/home/djangoadmin/pyapps/<your_project>
ExecStart=/home/djangoadmin/pyapps/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
<your_app_name>.wsgi:application
[Install]
WantedBy=multi-user.targetStart and enable Gunicorn socket
# sudo systemctl start gunicorn.socket
# sudo systemctl enable gunicorn.socketCheck status of gunicorn
# sudo systemctl status gunicorn.socketCheck the existence of gunicorn.sock
# file /run/gunicorn.sockNGINX Setup
Create project folder
# sudo nano /etc/nginx/sites-available/<your_project>Copy this code and paste into the file
server {
listen 80;
server_name YOUR_IP_ADDRESS;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/djangoadmin/pyapps/<your_project>;
}
location /media/ {
root /home/djangoadmin/pyapps/<your_project>;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}Enable the file by linking to the sites-enabled dir
# sudo ln -s /etc/nginx/sites-available/<your_project> /etc/nginx/sites-enabledTest NGINX config
# sudo nginx -tRestart NGINX
# sudo systemctl restart nginxRemove port 8000 from firewall and open up our firewall to allow normal traffic on port 80
# sudo ufw delete allow 8000
# sudo ufw allow 'Nginx Full'You will probably need to up the max upload size to be able to create listings with images
Open up the nginx conf file
# sudo nano /etc/nginx/nginx.confAdd this to the http{} area
client_max_body_size 20M;Reload NGINX
# sudo systemctl restart nginxMedia File Issue
You may have some issues with images not showing up. I would suggest, deleting all data and starting fresh as well as removing the "photos" folder in the "media folder"
# sudo rm -rf media/photosDomain Setup
Go to your domain registrar and create the following a record
@ A Record YOUR_IP_ADDRESS
www CNAME example.comGo to local_settings.py on the server and change "ALLOWED_HOSTS" to include the domain
ALLOWED_HOSTS = ['IP_ADDRESS', 'example.com', 'www.example.com']Edit /etc/nginx/sites-available/<your_project>
server {
listen: 80;
server_name xxx.xxx.xxx.xxx example.com www.example.com;
}Reload NGINX & Gunicorn
sudo systemctl restart nginx
sudo systemctl restart gunicorn