The reason many people has problems deploying is that they don’t pay enough attention to details. Deploying is easy when you are familiarized with all parts involved. You must know how to authenticate through ssh, be used to command line and Linux, understand how to configure and set up your project, have an idea of what serving static files is, what is Gunicorn… Ok, it’s not that simple. That’s why there is a lot of deploy tools, kits, and tutorials. Currently, with Ansible, Docker and whatever kids are using these days it’s easier to deploy, but what happens under the hood gets more abstract.
Maybe in a couple of years, this post is going to be obsolete if it’s not already with serverless and everything else. Anyway, just a few people want to learn how to deploy Django as I’ll show here, but if it helps at least one person, I’ll be satisfied.
Enjoy this Old-Style guide!
I presume you don’t have a server or AWS account, DigitalOcean, Linode… Nothing! You have to create an account in one of them and launch a server with the distro you want. If it’s your first time, don’t go with AWS because it’s way more complicated than the others.
In this tutorial, I’m using an Ubuntu 16.04, the most common distro you’ll see around. You can also pick a Debian if you like.
Configure server timezone
sudo locale-gen --no-purge --lang pt_BR # I'm using pt_BR, because HUE HUE BR BRsudo dpkg-reconfigure tzdata
Update and upgrade OS Packages:
sudo apt-get updatesudo apt-get -y upgrade
Replace Python 3.5 which is default on our distro with Python 3.6.
sudo apt-get updatesudo add-apt-repository ppa:jonathonf/python-3.6sudo apt-get install python3.6sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2
You can choose which Python version the OS will call when you type python3.
sudo update-alternatives --config python3
Having trouble, take a look here:
How to Install Python 3.6.1 in Ubuntu 16.04 LTS_This quick tutorial is going to show you how to install the latest Python 3.6.1 in Ubuntu 16.04 LTS via PPA. Ubuntu 16…_ubuntuhandbook.org
sudo apt-get install python3-pip nginx supervisor git git-core libpq-dev python-devpython-virtualenv
If your project has more OS requirements, install them as well.
I’m a fan of VirtualEnvWrapper. It’s super easy and creates all my virtual environments in the same place. That’s a personal choice, if you don’t like it, use what you know how to use.
First, you install virtualenvwrapper, and then define where to put your virtualenvs. (WORKON_HOME).
If you need to use it with multiple Python versions, you must define VIRTUALENVWRAPPER_PYTHON. Here I’m using always with python3. It’s not a problem since you can create a virtualenv pointing which Python that env will use.
sudo pip3 install virtualenvwrapperecho 'export WORKON_HOME=~/Envs' >> ~/.bashrcecho ‘export VIRTUALENVWRAPPER_PYTHON=`which python3`’ >> ~/.bashrcecho 'source /usr/local/bin/virtualenvwrapper.sh' >> ~/.bashrcsource ~/.bashrc
Now, create your virtualenv and define what Python is going to use.
mkvirtualenv name_venv --python=python3
VirtualEnvWrapper is really easy to use. If you want to activate a virtual env, you can use workon.
workon name_venv
To deactivate this virtualenv:
deactivate
To remove a virtualenv:
rmvirtualenv name_venv
You don’t want (neither should) write your password to git pull your project on the server.
Generating SSH Keys:
cd ~/.sshssh-keygen -t rsa -b 4096 -C "[email protected]"eval "$(ssh-agent -s)"ssh-add ~/.ssh/id_rsa
See and copy the content of your public key (id_rsa.pub)
cat ~/.ssh/id_rsa.pub
Then sign in your GitHub account and go to Settings > SSH and GPG Keys. Click on New SSH Key, give it a name, like (“test server keys”) and in Key paste the content of your id_rsa.pub
Copy the SSH link from GitHub to clone your project. In this case, I’m using a project that I just have found as an example.
git clone [email protected]:kirpit/django-sample-app.git
In the project folder, install the project requirements.
Remember that you have to be in your virtual environment
cd django-sample-app/pip install -r requirements.txt
Now, make the necessary alterations for your deploy, such as create a settings_local.py file, change database settings or anything specific to your project.
After you’re done, run your migrations and collect your static files (if you’re using it).
python manage.py migratepython manage.py collectstatic
Nginx, like Apache, is an entirely separate world. Right now, you just need the basics.
/etc/nginx/sites-available/ is a directory where you have to put the config files of available sites. There is another directory, /etc/nginx/sites-enabled/ that shows which sites are enabled. They are the same thing, but what is put on enabled will be served by Nginx.
It’s usual to create your config file on sites-available and create just a symlink to sites-enabled.
First of all, I’ll remove the default site from Nginx.
sudo rm /etc/nginx/sites-enabled/default
Now, create the config file for your site. (If you don’t know how to use VIM, use nano instead of vi)
sudo vi /etc/nginx/sites-available/mysite
Past this on your file, changing the necessary paths:
server {listen 80;access_log /home/username/logs/access.log;error_log /home/username/logs/error.log;
server_name nome-site.com.br;
location / {proxy_pass http://127.0.0.1:8000;
proxy_pass_header Server;proxy_set_header X-Forwarded-Host $server_name;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $http_host;
}
location /static {
alias /home/username/project_path/static/;
}
And create a symlink to sites-enabled:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
Restart Nginx:
sudo service nginx restart
Ok, if you made it till here, if you access your website you will see a 502 Bad Gateway from Nginx. That’s because it’s nothing here: http://127.0.0.1:8000
Now, configure the website to run on 8000 port.
Are you guys alive? Don’t give up, we’re almost there.
In your virtualenv (remember workon name_env?) install Gunicorn
pip install gunicorn
In your project’s directory, make a gunicorn_conf file:
bind = "127.0.0.1:8000"logfile = "/home/username/logs/gunicorn.log"workers = 3
Now, if you run Gunicorn you will see your website working!
/home/username/Envs/name_venv/bin/gunicorn project.wsgi:application -c gunicorn_conf
But what are you going to do? Run this command inside a screen and walk away? Of course not! You’ll use Supervisord to control Gunicorn.
Now create a gunicorn.conf:
sudo vi /etc/supervisor/conf.d/gunicorn.conf
That’s the content:
[program:gunicorn]command=/home/username/Envs/name_venv/bin/gunicorn project.wsgi:application -c /home/username/project/project_django/gunicorn_confdirectory=/home/username/project/project-djangouser=usernameautostart=trueautorestart=trueredirect_stderr=true
And now, you just tell Supervisor that there is a new process in town and Supervisord will take care of it:
sudo supervisorctl rereadsudo supervisorctl updatesudo supervisorctl restart gunicorn
And voilá! A new running you will have.
There is a lot of things involved in a deploy process. You have to configure a firewall, probably you’ll have to serve more than one static folder, etc, etc… But you have to start somewhere.
I can’t believe I wrote a whole post without using any GIF. So, just to finish, pay attention to all paths I’ve used here.
Oops..
Originally published at Fernando Alves.