Deploy Django on Debian server - a1k89/Blog GitHub Wiki
Deploy Django on Debian server
- Connect to server via root and create new user
- Setup SSH
- Install must have packages
- Install python
- Clone the project
- Install and configure PostgreSQL
- Install packages from requirements.txt
- Configure nginx, gunicorn, supervisor
- Configre static and media
- (optional) SSL for domain
Simplifications:
- Remote server host: example.com
- Remote user: a1
- Core directory (inside home): backend (/home/a1/backend)
- Virtualenv directory: /home/a1/backend/ienv/
- Main project directory: /home/a1/backend/project/
Step 1. After connecting through SSH we add new user and add user to sudo group.
sudo adduser a1
sudo usermod -aG sudo a1
sudo apt-get update
sudo apt-get upgrade
On a local machine we copy ssh-key to server and create ssh alias
ssh-copy-id [email protected]
sudo mcedit /ssh/ssh_config
Host example
HostName example.com
User a1
Port 2022
Step 2. Return to server and edit sshd_config and change port.
sudo mcedit /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
Port 2022
sudo mcedit /etc/sudoers
a1 ALL=(ALL) NOPASSWD:ALL
sudo service ssh restart
Finally:
Now we can connect through ssh example. Go to the next step. Works with packages.
Step 3. Install packages. This is a wide list of all packages.
sudo apt-get install -y zsh tree redis-server nginx libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-dev python3-lxml libxslt-dev python-libxml2 python-libxslt1 libffi-dev libssl-dev python-dev gnumeric libsqlite3-dev libpq-dev libxml2-dev libxslt1-dev libjpeg-dev libfreetype6-dev libcurl4-openssl-dev supervisor gcc python3-setuptools git
I like oh-my-zsh. Set of plugins for zsh.
oh-my-zsh:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
Step 4. Install python from source
**Note1. **I create .python folder inside a home directory. This is a good practic install python to one directory.
In a future if you wish to delete it python version - you simple delete folder .python.
Note2. prefix - directory for installation\
wget https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz
tar xvf Python-3.8.5.gz
cd Python-3.8.5
mkdir ~/.python
./configure --enable-optimizations --prefix=/home/a1/.python
make -j8
sudo make altinstall
Add python to path:
sudo mcedit ~/.zshrc
export PATH=$PATH:/home/a1/.python/bin
Step 5. Cloning project from repo
Step 6. Install and configure postgreSQL
Note1: Install latest version of postgreSQL
Note2: If you have database dump, you may download all data to your new database.\
Prepare:
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt-get update
Installation:
sudo apt-get install postgresql-12 postgresql-client-12
Create user for project:
sudo -u postgres psql
create user a1dbuser with password 'password';
create database a1db with owner a1dbuser;
\q;
Step 7. Install packages
Create virtual environment:
python3.8 -m venv ienv
source ienv/bin/activate
Finally:
pip install -r requirements.txt
Step 8. Nginx, Gunicorn, Supervisor
Nginx:
/etc/nginx/sites-enabled/site.conf\
upstream main {
server unix:///var/tmp/main.sock;
}
server {
listen 80;
server_name {domain_or_ip};
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /static/ {
alias /var/www/static/;
}
location /media/ {
alias /var/www/media/;
}
location ~ /.well-known {
allow all;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://main;
break;
}
}
}
sudo ln -s /etc/nginx/sites-available/site.conf /etc/nginx/sites-enabled/site.conf
sudo service nginx restart
Gunicorn:
Note1. I collect all gunicorn commands in one bash script.
Note2. Plese add +x rules for file.\
/home/a1/backend/bin/gunicorn_script.bash\
#!/bin/bash
NAME="gunicorn_app"
DJANGODIR="/home/a1/backend/"
SOCKFILE="/var/tmp/main.sock"
USER="www-data"
GROUP="www-data"
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE="project.settings"
DJANGO_WSGI_MODULE="project.wsgi"
cd $DJANGODIR
source ienv/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR
exec ienv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--threads=2\
--user=$USER \
--group=$GROUP \
--bind=unix:$SOCKFILE \
--log-level=debug \
--log-file=-
Supervisor:
/etc/supervisor/conf/main.conf
[program:core-gunicorn]
command = /home/a1/backend/bin/gunicorn_script.bash
user = www-data
stdout_logfile = /home/a1/backend/logs/gunicorn.log
redirect_stderr = true
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart all
Step 9. Media and Static
I have many problems with static and media files on production.
For example, 403 Forbidden error.
Finally, I found solution:
sudo groupadd varwwwusers
sudo adduser www-data varwwwusers
sudo chgrp -R varwwwusers /var/www/
sudo chmod 770 -R /var/www/
sudo chmod g+s /var/www/
sudo service nginx restart
relogin
Now we don't have any problems with permissions with media/static/.
Go to the project directory and:
python manage.py collectstatic
Step 10 (optional). SSL
Note 1. Use letsencrypt - free and great open source solution
Go to the letsencrypt and see simple steps:\
sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx - example.com
sudo service nginx restart
sudo certbot renew --dry-run # Check renew
Finally, check: https://example.com/
And this is all about SSL. Simple. Stable. Free.