Guide to deploy Django application with SSL and Nginx in GCP (google cloud platform) Ubuntu VM

Hope you read my other article to deploy Django in GCP, here is the LINK if you have missed. In this new article, I am trying to explain the steps to install nginx, enable ssl and control the Django application using supervisor to ease the process.
Install NGINX
As you know nginx (http://nginx.org/) is a HTTP server which will be listening to port 80 and can redirect to your application. We can also configure SSL certificate and related configurations in nginx.
sudo apt-get install nginx
you can check the status of nginx by running below command,
sudo systemctl status nginx.service
Create SSL certificate
We have different authorities who providing SSL certificates — godaddy, comodo, digicert etc, but here, we are going to use let’s encrypt (https://letsencrypt.org/) — an org who providing free SSL certificate. (Let’s Encrypt is a free, automated, and open certificate authority brought to you by the non-profit Internet Security Research Group (ISRG). source: https://letsencrypt.org/)
I have used zerossl (https://zerossl.com/) which intern using let’s encrypt, but made process simple and we can create, verify and download from zerossl online tool. Once certificate generated, you may scp the certificate to your GCP VM where you have your Django application running.
Changes in Django settings
For production environment, you have to change “debug= true” to false
debug=false
You may also add below security parameters in django settings,
SECURE_PROXY_SSL_HEADER = (‘HTTP_X_FORWARDED_PROTO’, ‘https’)
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Install and configure Supervisor
As I said in the intro section, supervisor (https://pypi.org/project/supervisor/) helps us to automate the start and stop the django process in production.
sudo apt-get install supervisor
configure django app for supervisor in /etc/supervisor/config.d/<<your project name>> file,
sample content below,
[program:your_project_name]
command = /usr/bin/python3 /path/to/project/manage.py runserver 0.0.0.0:8000 ; Command to start app
user = vm_user_name ; User to run as
stdout_logfile = /path/log_file_name ; Where to write log messages
redirect_stderr = true ; Save stderr in the same log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ; Set UTF-8 as default encoding
Above config file tells supervisor what to run and where to write logs etc.
You have to run below commands to make supervisor understand the configuration for our application,
sudo supervisorctl reread
sudo supervisorctl update
Below commands for start, stop and restart application,
sudo supervisorctl start project_name
sudo supervisorctl stop project_name
sudo supervisorctl restart project_name
sudo supervisorctl status # to check status and make sure app is running
Nginx configurations
We have our application running in port 8000 which we triggered from supervisor, now, its time to configure http server and redirect port 80 requests to 8000 and also, configure SSL for our app. Make your nginx is running by checking below command,
sudo systemctl status nginx.service
You can configure your app for nginx in below file,
/etc/nginx/sites-available/project_name_here
Here is the sample configuration:
upstream app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
# for UNIX domain socket setups
# server unix:/tmp/gunicorn.sock fail_timeout=0;
# for a TCP configuration
server VM_IP:8000 fail_timeout=0;
# above statement will forward request to django application which running on port 8000
}
# below section is to forward default request (to http port 80) to SSL port 443
server {
listen 80;
server_name host_name_or_IP_or_domain_name www.host_name_or_IP_or_domain_name;
return 301 https://$server_name$request_uri;
}
server {
# use ‘listen 80 deferred;’ for Linux
# use ‘listen 80 accept_filter=httpready;’ for FreeBSD
listen 443 ssl; # <-
ssl on; # <-
ssl_certificate /path/to/ssl/certificate; # <-
ssl_certificate_key /path/to/ssl/certificate_key; # <-
client_max_body_size 4G;
# set the correct host(s) for your site
server_name host_name_or_IP_or_domain_name www.host_name_or_IP_or_domain_name;
keepalive_timeout 5;
# path for static files
root /path/to/static/files;
location /static/ {
alias /path/to/static/files;
}
location /media/ {
alias /path/to/static/media/files/;
}
location / {
# checks for static file, if not found proxy to app
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
}
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
# we don’t want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /path/to/app/current/public;
}
}
Link the site to site enabled list,
sudo ln -s /etc/nginx/sites-available/project_name /etc/nginx/sites-enabled/project_name
sudo service nginx restart
sudo systemctl status nginx.service
Now, you can access the application by its https url and also, the http request will be forwarding to https per nginx configuration.
