Compute Engine Google Cloud

How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04 in Google Cloud

Django is an open source web application framework that can help you get your Python application or website off the ground.

In this guide, we will demonstrate how to install and configure Django, Gunicorn and Nginx on Ubuntu 18.04 to support and serve Django applications. We will be setting up a PostgreSQL database in Cloud SQL instead of using the default SQLite database.

Choose Best Hosting for your Business

Kinsta – Google Cloud★★★★★$30


  1. Your Compute Engine Instance running, see the Setting up Compute Engine Instance.
  2. Domain name is pointed to your virtual machine.
  3. For setting up Cloud DNS, see the Setting up Google Cloud DNS for your domain.

Install required packages

SSH to your Compute Engine instance and begin typing the following commands to start installing Django

sudo apt update
sudo apt install python3-pip python3-dev libpq-dev postgresql-contrib nginx curl

Creating Cloud SQL Instance with PostgreSQL

Go to your Google Cloud Console and navigate to Storage >> Cloud SQL

Click Create Instance

Choose PostgreSQL

Click Next

Enter Instance ID

Set a password for the postgres user

Choose the region and zone same as your Compute Engine Instance

Configure machine type and storage

Click Create

Once your Cloud SQL Instance is created go to the Connections tab inside your instance and under Authorized Networks click Add network

In Network enter the IP address of your Compute Engine

Cloud SQL Allow Connections

Click Save

Now your Compute Engine is authorized to connect to your Cloud SQL Instance

Creating the PostgreSQL Database and User

Go back to your Compute Engine Instance and create a database and user.

Make sure to replace the CLOUD_SQL_IP_ADDRESS with your Cloud SQL IP Address and PASSWORD with the password you set up while creating the Cloud SQL Instance.

Cloud SQL IP Address
psql -h CLOUD_SQL_IP_ADDRESS -U postgres
ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

Cloud SQL is now set up so that Django can connect to and manage its database information.

Creating a Python Virtual Environment for your Project

sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv
mkdir ~/myprojectdir
cd ~/myprojectdir
virtualenv myprojectenv

Activate the virtual environment by typing

source myprojectenv/bin/activate

Your prompt should change to indicate that you are now operating within a Python virtual environment. It will look something like this: (myprojectenv)[email protected]:~/myprojectdir$

With your virtual environment active, install Django, Gunicorn, and the psycopg2 PostgreSQL adaptor with the local instance of pip

pip install django gunicorn psycopg2-binary

You should now have all of the software needed to start a Django project.

Creating the Django Project startproject myproject ~/myprojectdir

Configure the project settings

Update the for allowed hosts and connect to Cloud SQL database

sudo nano ~/myprojectdir/myproject/

Be sure to include localhost as one of the options since we will be proxying connections through a local Nginx instance

ALLOWED_HOSTS = ['', 'localhost']

    'default': {
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
         'NAME': 'myproject',
         'USER': 'myprojectuser',
         'PASSWORD': 'PASSWORD',
         'PORT': '',

Now add a setting indicating where the static files should be placed. Nginx can handle requests for these items.

STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Save and close the file when you are finished

Completing the Initial Project Setup

~/myprojectdir/ makemigrations
~/myprojectdir/ migrate
~/myprojectdir/ createsuperuser

You will have to select a username, provide an email address, and choose and confirm a password.

We can collect all of the static content into the directory location we configured by typing:

~/myprojectdir/ collectstatic

We’re now finished configuring our Django application. We can back out of our virtual environment by typing


Creating Socket and Service Files for Gunicorn

sudo nano /etc/systemd/system/gunicorn.socket
Description=gunicorn socket


sudo nano /etc/systemd/system/gunicorn.service
Description=gunicorn daemon

ExecStart=/home/username/myprojectdir/myprojectenv/bin/gunicorn \
     --access-logfile - \
     --workers 3 \
     --bind unix:/run/gunicorn.sock \


Start and enable Gunicorn socket

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

Checking for the Gunicorn Socket File

Check the status of the process to find out whether it was able to start:

sudo systemctl status gunicorn.socket

You will get the status as Active: active (listening)

Next, check for the existence of the gunicorn.sock file within the /run directory:

file /run/gunicorn.sock


/run/gunicorn.sock: socket

Testing Socket Activation

sudo systemctl status gunicorn
● gunicorn.service - gunicorn daemon
Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
Active: inactive (dead)

To test the socket activation mechanism, we can send a connection to the socket through curl by typing:

curl --unix-socket /run/gunicorn.sock localhost

You should receive the HTML response

sudo systemctl status 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

NGINX Proxy Pass to Gunicorn and setup HTTPS

Create a new Nginx configuration for your website in the sites-available directory

sudo nano /etc/nginx/sites-available/

Copy and paste the following configuration, ensure that you change the server_name, error_log to match your domain name. Hit CTRL+X followed by Y to save the changes.

server {
    listen 80;
    listen [::]:80;


    location = /favicon.ico {
        access_log off;
        log_not_found off;

    location /static/ {
        root /home/username/myprojectdir;

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;

To enable this newly created website configuration, symlink the file that you just created into the sites-enabled directory.

sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

Check your configuration and restart Nginx for the changes to take effect

sudo nginx -t
sudo service nginx restart

Now visit your domain name in your web browser, you can view the Django congratulations page.

Django Installed Successfully

You can view the admin page with the following url

Django admin

Create SSL certificate and enable HTTP/2

HTTPS is a protocol for secure communication between a server (instance) and a client (web browser). Due to the introduction of Let’s Encrypt, which provides free SSL certificates, HTTPS are adopted by everyone and also provides trust to your audiences.

HTTP/2 is the latest version of the HTTP protocol and can provide a significant improvement to the load time of your sites. There really is no reason not to enable HTTP/2, the only requirement is that the site must use HTTPS.

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

Now we have installed Certbot by Let’s Encrypt for Ubuntu 18.04, run this command to receive your certificates.

sudo certbot --nginx certonly

Enter your email and agree to the terms and conditions, then you will receive the list of domains you need to generate SSL certificate.

To select all domains simply hit Enter

The Certbot client will automatically generate the new certificate for your domain. Now we need to update the Nginx config.

Redirect HTTP Traffic to HTTPS with www in Nginx

Open your site’s Nginx configuration file add replace everything with the following. Replacing the file path with the one you received when obtaining the SSL certificate. The ssl_certificate directive should point to your fullchain.pem file, and the ssl_certificate_key directive should point to your privkey.pem file.

server {
    listen [::]:80;
    listen 80;

    # redirect http to https www
    return 301$request_uri;

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;


    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    root /home/username/myprojectdir;

    # redirect https non-www to https www
    return 301$request_uri;

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;


    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    location = /favicon.ico {
        access_log off;
        log_not_found off;

    location /static/ {
        root /home/username/myprojectdir;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;

        add_header Content-Security-Policy "img-src * 'self' data: blob: https:; default-src 'self' https://* https://* https://* https://* https://* https://* data: 'unsafe-inline' 'unsafe-eval';" always;
add_header X-Xss-Protection "1; mode=block" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Access-Control-Allow-Origin "";
        add_header Referrer-Policy "origin-when-cross-origin" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

The http2 value is all that is needed to enable the HTTP/2 protocol.

Hit CTRL+X followed by Y to save the changes.

Check your configuration and restart Nginx for the changes to take effect.

sudo nginx -t
sudo service nginx restart

Renewing SSL Certificate

Certificates provided by Let’s Encrypt are valid for 90 days only, so you need to renew them often. Now you set up a cronjob to check for the certificate which is due to expire in next 30 days and renew it automatically.

sudo crontab -e

Add this line at the end of the file

0 0,12 * * * certbot renew >/dev/null 2>&1

Hit CTRL+X followed by Y to save the changes.

This cronjob will attempt to check for renewing the certificate twice daily.

Cloudbooklet builds a large collection of Linux based guides and tutorials on Cloud platforms like Google Cloud, AWS, Azure, DigitalOcean and more

Write A Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.