<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Yin</title>
    <description>The latest articles on DEV Community by Michael Yin (@michaelyin).</description>
    <link>https://dev.to/michaelyin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F230602%2F7d4566ab-9066-4def-a59e-b962b2a6c194.jpeg</url>
      <title>DEV Community: Michael Yin</title>
      <link>https://dev.to/michaelyin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michaelyin"/>
    <language>en</language>
    <item>
      <title>How to deploy Django project to Dokku</title>
      <dc:creator>Michael Yin</dc:creator>
      <pubDate>Tue, 29 Oct 2019 12:11:42 +0000</pubDate>
      <link>https://dev.to/michaelyin/how-to-deploy-django-project-to-dokku-lph</link>
      <guid>https://dev.to/michaelyin/how-to-deploy-django-project-to-dokku-lph</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Dokku is a PaaS implementation built on docker, it can give you a &lt;code&gt;Heroku-like environment&lt;/code&gt; which is also open source and free.&lt;/p&gt;

&lt;p&gt;You can use it on AWS EC2 or VPS such as Digital Ocean to save your time on many DevOps work.&lt;/p&gt;

&lt;p&gt;In this Dokku tutorial, I will talk about how to deploy Django project with Dokku, it would use Postgres db and Amazon S3 to store data and media files.&lt;/p&gt;

&lt;p&gt;After reaading this tutorial, you will get:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;How to install Dokku, config Dokku server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to deploy Django project to Dokku&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to install, config Dokku app and plugin&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The source code of this post can be found on &lt;a href="https://github.com/AccordBox/django_dokku_example" rel="noopener noreferrer"&gt;Django Dokku example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dokku
&lt;/h2&gt;

&lt;p&gt;First, you can check Dokku doc for the latest system requirment. (you can ignore this step if you choose the Ubuntu LTS version)&lt;/p&gt;

&lt;p&gt;Then you can get the install script in the &lt;a href="https://github.com/dokku/dokku/releases" rel="noopener noreferrer"&gt;Dokku release&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, below is the script I use to install Dokku. &lt;strong&gt;Please make sure run this command on your server&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Please use ssh to login to your server
root@ubuntu:# wget https://raw.githubusercontent.com/dokku/dokku/v0.18.3/bootstrap.sh
root@ubuntu:# sudo DOKKU_TAG=v0.18.3 bash bootstrap.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script would also instal Docker and other stuff on your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config Dokku Server
&lt;/h2&gt;

&lt;p&gt;After Dokku is installed on your server, now you need config SSH public key for Dokku service.&lt;/p&gt;

&lt;p&gt;Let's say the IP of your server is 165.22.153.24, then you need to visit &lt;a href="http://165.22.153.24" rel="noopener noreferrer"&gt;http://165.22.153.24&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;p&gt;You need paste the ssh public key. (you can skip the hostname config here because we would do it in a bit)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fdokku-setup.original.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fdokku-setup.original.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you are done, please check on your server to make sure the relevant service is not running (because this is risky)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ubuntu:# ps auxf | grep dokku-installer
root     14776  0.0  0.0  12944   920 pts/0    S+   07:34   0:00          \_ grep --color=auto dokku-installer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The install service would be terminated after you config in web browser, as you can see in the output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup ssh server in local
&lt;/h3&gt;

&lt;p&gt;It is annoying to type the ip address to login each time, so we can config our ssh client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please do this in local env&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can add the server to your local &lt;code&gt;~/.ssh/config&lt;/code&gt; to help you ssh in more easy way.&lt;/p&gt;

&lt;p&gt;Please add code below to your &lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host dokku_server
    ForwardAgent yes
    Hostname 165.22.153.24
    Port 22
    ServerAliveInterval 60
    ServerAliveCountMax 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use &lt;code&gt;ssh root@dokku_server&lt;/code&gt; instead of &lt;code&gt;ssh root@165.22.153.24&lt;/code&gt; to login to your server&lt;/p&gt;

&lt;h2&gt;
  
  
  Config Dokku App
&lt;/h2&gt;

&lt;p&gt;Now we start to create and config our Dokku app.&lt;/p&gt;

&lt;p&gt;Please note that, the dokku project has name &lt;code&gt;django_dokku_example&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create app
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ubuntu:# dokku apps:create django_dokku_example
-----&amp;gt; Creating django_dokku_example... done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Postgres DB
&lt;/h3&gt;

&lt;p&gt;Here we put the Postgres db on our server, but you can also use 3-party DB server like Amazon RDS if you like.&lt;/p&gt;

&lt;p&gt;Dokku has many plugins and here we use &lt;code&gt;postgres plugin&lt;/code&gt; to help us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install the plugin
root@ubuntu:# sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git

# we can also specify the Postgres db version, if you do not specify here, the latest version would be used.
root@ubuntu:# export POSTGRES_IMAGE="postgres"
root@ubuntu:# export POSTGRES_IMAGE_VERSION="10.7"

# let's create db, I add suffix '_db'
root@ubuntu:# sudo dokku postgres:create django_dokku_example_db

Status: Downloaded newer image for postgres:10.7
docker.io/library/postgres:10.7
       Waiting for container to be ready
       Creating container database
       Securing connection to database
=====&amp;gt; Postgres container created: django_dokku_example_db
=====&amp;gt; Container Information
       Config dir:          /var/lib/dokku/services/postgres/django_dokku_example_db/config
       Data dir:            /var/lib/dokku/services/postgres/django_dokku_example_db/data
       Dsn:                 postgres://postgres:dc7f4aa4f2d4856068c88b4187afadbf@dokku-postgres-django-dokku-example-db:5432/django_dokku_example_db
       Exposed ports:       -
       Id:                  a92fff08e4e36f60bb250bccc5816f576bc8a97b4398a0c6e228c24749ef1397
       Internal ip:         172.17.0.2
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/django_dokku_example_db
       Status:              running
       Version:             postgres:10.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;code&gt;POSTGRES_IMAGE&lt;/code&gt; and &lt;code&gt;POSTGRES_IMAGE_VERSION&lt;/code&gt; is used to download the docker image. So you can use them to specify the Postgres db version you want to use.&lt;/p&gt;

&lt;p&gt;Now link the db to your dokku app, and it would add a new env varialbe &lt;code&gt;DATABASE_URL&lt;/code&gt; to the dokku app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ubuntu:~# dokku postgres:link django_dokku_example_db django_dokku_example
-----&amp;gt; Setting config vars
       DATABASE_URL:  postgres://postgres:dc7f4aa4f2d4856068c88b4187afadbf@dokku-postgres-django-dokku-example-db:5432/django_dokku_example_db
-----&amp;gt; Restarting app django_dokku_example
 !     App django_dokku_example has not been deployed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's print out the env of our Dokku app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ubuntu:~# dokku config django_dokku_example
=====&amp;gt; django_dokku_example env vars
DATABASE_URL:  postgres://postgres:dc7f4aa4f2d4856068c88b4187afadbf@dokku-postgres-django-dokku-example-db:5432/django_dokku_example_db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Config Amazon s3
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;dokku support store media files in local disk, you can check Dokku Persistent Storage for more detail&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If you have no Amazon service account,  please go to &lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;Amazon S3&lt;/a&gt; and click the &lt;code&gt;Get started with Amazon S3&lt;/code&gt; to signup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Login &lt;a href="https://console.aws.amazon.com/console/home" rel="noopener noreferrer"&gt;AWS Management Console&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the top right, click your company name and then click &lt;code&gt;My Security Credentials&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the &lt;code&gt;Access Keys&lt;/code&gt; section&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Create New Access Key&lt;/code&gt;, please copy the &lt;code&gt;AMAZON_S3_KEY&lt;/code&gt; and &lt;code&gt;AMAZON_S3_SECRET&lt;/code&gt; to notebook.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are new to Amazon and have no idea what is &lt;code&gt;IAM&lt;/code&gt; user, you can skip it and set permissions later.&lt;/p&gt;

&lt;p&gt;Next, we start to create Amazon bucket on &lt;a href="https://console.aws.amazon.com/s3/home" rel="noopener noreferrer"&gt;S3 Management Console&lt;/a&gt;, please copy &lt;code&gt;Bucket name&lt;/code&gt; to notebook.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Bucket&lt;/code&gt; in Amazon S3 is like top-level container, every site should have its own &lt;code&gt;bucket&lt;/code&gt;, and the bucket name are unique across all Amazon s3, and the url of the media files have domain like &lt;code&gt;{bucket_name}.s3.amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we add &lt;code&gt;AWS_STORAGE_BUCKET_NAME&lt;/code&gt;, &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; env variable to our Dokku app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dokku config:set &lt;span class="nt"&gt;--no-restart&lt;/span&gt; django_dokku_example &lt;span class="nv"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'django-dokku-example'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;dokku config:set &lt;span class="nt"&gt;--no-restart&lt;/span&gt; django_dokku_example &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;dokku config:set &lt;span class="nt"&gt;--no-restart&lt;/span&gt; django_dokku_example &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Dokku would restart the app if you changed env variable, here we use &lt;code&gt;--no-restart&lt;/code&gt; to tell Dokku not restart it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Config other env variable
&lt;/h3&gt;

&lt;p&gt;There are still some env variables we need to config, please use &lt;code&gt;dokku config:set --no-restart django_dokku_example&lt;/code&gt; to add them to Dokku app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DJANGO_ALLOWED_HOSTS:  *
DJANGO_SECRET_KEY:     {please generate new one}
DJANGO_SETTINGS_MODULE:   config.settings.production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we set &lt;code&gt;DJANGO_ALLOWED_HOSTS&lt;/code&gt; to &lt;code&gt;*&lt;/code&gt; and later we would config nginx to make domain work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Config domain
&lt;/h3&gt;

&lt;p&gt;Next, we start to config domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ubuntu:~# dokku domains:add django_dokku_example dokku.accordbox.com
-----&amp;gt; Added dokku.accordbox.com to django_dokku_example
 !     No web listeners specified for django_dokku_example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we add to &lt;code&gt;dokku.accordbox.com&lt;/code&gt; to our Dokku app &lt;code&gt;django_dokku_example&lt;/code&gt;, we can add more than one domain to Dokku app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config our Django project
&lt;/h2&gt;

&lt;p&gt;Now the Dokku app env is ready, before pushing code to Dokku server, let's config our Django project.&lt;/p&gt;

&lt;p&gt;You would also see we need to add some config files, which are very similar with Heroku's config file, Dokku would scan and read them to decide some deployment workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Store media in Amazon s3
&lt;/h3&gt;

&lt;p&gt;Now let's config Django project to let it use Amazon s3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# please remember to update requirements.txt or Pipfile&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;boto3
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;django-storages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;storages&lt;/code&gt; to &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in &lt;code&gt;settings/base.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add config below to &lt;code&gt;settings/production.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AWS_S3_CUSTOM_DOMAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%s.s3.amazonaws.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt;
&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AWS_S3_FILE_OVERWRITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;MEDIA_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://%s/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;AWS_S3_CUSTOM_DOMAIN&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_FILE_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;storages.backends.s3boto3.S3Boto3Storage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Static files
&lt;/h3&gt;

&lt;p&gt;We use &lt;code&gt;whitenoise&lt;/code&gt; to help us serve static files on server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# please remember to update requirements.txt or Pipfile&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;whitenoise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;MIDDLEWARE&lt;/code&gt; in &lt;code&gt;settings/base.py&lt;/code&gt;, put &lt;code&gt;WhiteNoiseMiddleware&lt;/code&gt; above all other middleware apart from Django’s &lt;code&gt;SecurityMiddleware&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;django.middleware.security.SecurityMiddleware&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;whitenoise.middleware.WhiteNoiseMiddleware&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set in &lt;code&gt;settings/production.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;STATICFILES_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;whitenoise.storage.CompressedManifestStaticFilesStorage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Postgres DB
&lt;/h3&gt;

&lt;p&gt;Now we add code to &lt;code&gt;settings/production.py&lt;/code&gt; to make it can understand &lt;code&gt;DATABASE_URL&lt;/code&gt; value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# please remember to update requirements.txt or Pipfile&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;django-environ
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;psycopg2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;DATABASES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# noqa F405
&lt;/span&gt;    &lt;span class="n"&gt;DATABASES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ATOMIC_REQUESTS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# noqa F405
&lt;/span&gt;    &lt;span class="n"&gt;DATABASES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONN_MAX_AGE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONN_MAX_AGE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# noqa F405
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Procfile
&lt;/h3&gt;

&lt;p&gt;This file exists in root directory of our project. It contains entry command of our service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gunicorn config.wsgi:application&lt;/span&gt;

&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python manage.py migrate --noinput&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;web&lt;/code&gt; means the web service, Dokku would use the command to run for our web service.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;release&lt;/code&gt; is the command which would be run in release stage, here we use the command to migrate our databae in release stage.&lt;/p&gt;

&lt;p&gt;If you used Celery worker in your project, you can add &lt;code&gt;worker: ...&lt;/code&gt; to do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  DOKKU_SCALE
&lt;/h3&gt;

&lt;p&gt;This file exists in root directory of our project, it defines &lt;code&gt;container number&lt;/code&gt; of our services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;web&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we set &lt;code&gt;web=1&lt;/code&gt; so there would be one web container&lt;/p&gt;

&lt;h3&gt;
  
  
  requirements.txt or Pipfile
&lt;/h3&gt;

&lt;p&gt;Please make sure your project has &lt;code&gt;requirements.txt&lt;/code&gt; or &lt;code&gt;Pipfile&lt;/code&gt; so Dokku can check if it is Python project and would install dependencies when deploying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy project
&lt;/h2&gt;

&lt;p&gt;Please commit code first and then keep reading.&lt;/p&gt;

&lt;p&gt;First we add a remote branch &lt;code&gt;dokku&lt;/code&gt; to our Git repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git remote add dokku dokku@dokku_server:django_dokku_example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dokku_server&lt;/code&gt; here can also be the ip address of the server (dokku_server is the hostname we config in &lt;code&gt;~/.ssh/config&lt;/code&gt;), &lt;code&gt;django_dokku_example&lt;/code&gt; is the dokku app we just created on our server.&lt;/p&gt;

&lt;p&gt;Then we push our code to remote branch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git push dokku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the output, Dokku would check language we use and download relevant Heroku buildpack to deploy the project. Which is very cool!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git push dokku master
Counting objects: 177, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (162/162), done.
Writing objects: 100% (177/177), 49.38 KiB | 3.53 MiB/s, done.
Total 177 (delta 45), reused 0 (delta 0)
-----&amp;gt; Cleaning up...
-----&amp;gt; Building django_dokku_example from herokuish...
-----&amp;gt; Adding BUILD_ENV to build environment...
-----&amp;gt; Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
       Detected buildpacks: multi python
-----&amp;gt; Multipack app detected
=====&amp;gt; Downloading Buildpack: https://github.com/heroku/heroku-buildpack-python.git
=====&amp;gt; Detected Framework: Python
-----&amp;gt; Installing python-3.6.9
-----&amp;gt; Installing pip
-----&amp;gt; Installing SQLite3
-----&amp;gt; Installing requirements with pip
       Collecting pytz==2019.2 (from -r /tmp/build/requirements/./base.txt (line 1))
       Downloading https://files.pythonhosted.org/packages/87/76/46d697698a143e05f77bec5a526bf4e56a0be61d63425b68f4ba553b51f2/pytz-2019.2-py2.py3-none-any.whl (508kB)
       Successfully installed MarkupSafe-1.1.1 Pillow-6.1.0 Unidecode-1.1.1 Willow-1.1 argon2-cffi-19.1.0 beautifulsoup4-4.6.0 boto3-1.8.0 botocore-1.11.9 certifi-2019.9.11 cffi-1.12.3 chardet-3.0.4 coreapi-2.3.3 coreschema-0.0.4 defusedxml-0.6.0 django-2.2.5 django-allauth-0.40.0 django-anymail-6.1.0 django-crispy-forms-1.7.2 django-environ-0.4.5 django-model-utils-3.2.0 django-modelcluster-4.4 django-redis-4.10.0 django-storages-1.6.6 django-taggit-0.24.0 django-treebeard-4.3 djangorestframework-3.10.3 docutils-0.15.2 draftjs-exporter-2.1.7 gunicorn-19.9.0 html5lib-1.0.1 idna-2.8 itypes-1.1.0 jinja2-2.10.1 jmespath-0.9.4 oauthlib-3.1.0 psycopg2-2.8.3 pycparser-2.19 python-dateutil-2.8.0 python-slugify-3.0.4 python3-openid-3.1.0 pytz-2019.2 redis-3.3.8 requests-2.22.0 requests-oauthlib-1.2.0 s3transfer-0.1.13 six-1.12.0 sqlparse-0.3.0 text-unidecode-1.3 uritemplate-3.0.0 urllib3-1.25.6 wagtail-2.6.2 webencodings-0.5.1 whitenoise-4.1.3

-----&amp;gt; $ python manage.py collectstatic --noinput
       288 static files copied to '/tmp/build/staticfiles', 840 post-processed.

       Using release configuration from last framework (Python).
-----&amp;gt; Discovering process types
       Procfile declares types -&amp;gt; release, web
-----&amp;gt; Releasing django_dokku_example (dokku/django_dokku_example:latest)...
-----&amp;gt; Deploying django_dokku_example (dokku/django_dokku_example:latest)...
 !     Release command declared: 'python manage.py migrate --noinput'
       Operations to perform:
         Apply all migrations: account, admin, auth, contenttypes, sessions, sites, socialaccount, taggit, users, wagtailadmin, wagtailcore, wagtaildocs, wagtailimages, wagtailsearch, wagtailusers
       Running migrations:
         Applying wagtailusers.0007_userprofile_current_time_zone... OK
         Applying wagtailusers.0008_userprofile_avatar... OK
         Applying wagtailusers.0009_userprofile_verbose_name_plural... OK
-----&amp;gt; App Procfile file found (/home/dokku/django_dokku_example/DOKKU_PROCFILE)
       DOKKU_SCALE declares scale -&amp;gt; web=1
-----&amp;gt; Attempting pre-flight checks
       For more efficient zero downtime deployments, create a file CHECKS.
       See http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/ for examples
       CHECKS file not found in container: Running simple container check...
-----&amp;gt; Waiting for 10 seconds ...
-----&amp;gt; Default container check successful!
-----&amp;gt; Running post-deploy
-----&amp;gt; Overriding default nginx.conf with detected nginx.conf.sigil
-----&amp;gt; Configuring dokku.accordbox.com...(using app-supplied template)
-----&amp;gt; Creating http nginx.conf
-----&amp;gt; Running nginx-pre-reload
       Reloading nginx
-----&amp;gt; Renaming containers
       Renaming container (47bec7f2e474) pensive_hoover to django_dokku_example.web.1
=====&amp;gt; Application deployed:
       http://dokku.accordbox.com

To 165.22.153.24:django_dokku_example
 * [new branch]      master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the push command did not raise error, you should see something like this and now our app is live on &lt;a href="http://dokku.accordbox.com" rel="noopener noreferrer"&gt;http://dokku.accordbox.com&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup SSL
&lt;/h3&gt;

&lt;p&gt;Let's make &lt;code&gt;https&lt;/code&gt; work for our site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
&lt;span class="nv"&gt;$ &lt;/span&gt;dokku config:set &lt;span class="nt"&gt;--no-restart&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nv"&gt;DOKKU_LETSENCRYPT_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;michaelyin@accordbox.com
&lt;span class="nv"&gt;$ &lt;/span&gt;dokku letsencrypt django_dokku_example
&lt;span class="c"&gt;# this would setup cron job to update letsencrypt certificate&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;dokku letsencrypt:cron-job &lt;span class="nt"&gt;--add&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please replace &lt;code&gt;DOKKU_LETSENCRYPT_EMAIL&lt;/code&gt; with your email.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;https&lt;/code&gt; can work on your site, you can setup &lt;code&gt;http-&amp;gt;https&lt;/code&gt; to improve security. Please check &lt;code&gt;SECURITY&lt;/code&gt; section of &lt;code&gt;config/settings/production.py&lt;/code&gt; for more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Advanced issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Troubleshoort
&lt;/h3&gt;

&lt;p&gt;It is common if your Django projects return 500 error page in some cases, so how to troubleshoot?&lt;/p&gt;

&lt;p&gt;I strongly recommend to use &lt;code&gt;Sentry&lt;/code&gt; to help you solve this. And I already wrote post talking abou this &lt;a href="https://www.accordbox.com/blog/heroku-logs-tutorial/#error-log-with-sentry" rel="noopener noreferrer"&gt;Error log with Sentry&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can check the running logs using this command &lt;code&gt;dokku logs django_dokku_example&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize Nginx
&lt;/h3&gt;

&lt;p&gt;Sometimes, we need to customize our Nginx settings.&lt;/p&gt;

&lt;p&gt;For example, the default Nginx settings has small &lt;code&gt;client_max_body_size&lt;/code&gt;, so I need to change it to make upload feature work in my Django project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dokku&lt;/code&gt; generate nginx config from &lt;code&gt;nginx.conf.sigil&lt;/code&gt;, you can first download it from Dokku repo (better download from specific Git tag instead of master branch).&lt;/p&gt;

&lt;p&gt;And then you can add more modify your settings.&lt;/p&gt;

&lt;p&gt;You can add that file to root directory of your project and Dokku would use it to generate new nginx config.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero Downtime Deploy
&lt;/h3&gt;

&lt;p&gt;When Dokku deploy, it would start container which has latest code and then wait for 10 secs to make sure the service is ok to run.&lt;/p&gt;

&lt;p&gt;To shorten the time, we can add add &lt;code&gt;CHECKS&lt;/code&gt; file and Dokku would use that file to check if our web server is ok to serve.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/                       django_dokku_example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tell Dokku to visit &lt;code&gt;/&lt;/code&gt; url and check if the response contains &lt;code&gt;django_dokku_example&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-----&amp;gt; Attempting pre-flight checks
-----&amp;gt; Attempt 1/5 Waiting for 5 seconds ...
       CHECKS expected result:
       http://localhost/ =&amp;gt; "django_dokku_example"
-----&amp;gt; All checks successful!
=====&amp;gt; django_dokku_example web container output:
       [2019-10-08 04:41:55 +0000] [9] [INFO] Starting gunicorn 19.9.0
       [2019-10-08 04:41:55 +0000] [9] [INFO] Listening at: http://0.0.0.0:5000 (9)
       [2019-10-08 04:41:55 +0000] [9] [INFO] Using worker: sync
       [2019-10-08 04:41:55 +0000] [204] [INFO] Booting worker with pid: 204
       172.17.0.1 - - [08/Oct/2019:04:42:04 +0000] "GET / HTTP/1.1" 200 3590 "-" "curl/7.47.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, Dokku use curl to check and if the check succeed, it would send traffic to the new container immediatly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run Django command
&lt;/h3&gt;

&lt;p&gt;If you want to run some command on web server, for example, run Django shell, you can use command in this way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dokku &lt;span class="nt"&gt;--rm&lt;/span&gt; run django_dokku_example python manage.py shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here Dokku would create a new container for you to use and this can avoid some risky operation. &lt;code&gt;--rm&lt;/code&gt; means the container would be delted after you exit.&lt;/p&gt;

&lt;p&gt;I always use this to run &lt;code&gt;createsuperuser&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Cron job
&lt;/h3&gt;

&lt;p&gt;If you want to setup cron jobs for your project, it is better to do it in host machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# we set crontjob as dokku user&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;crontab &lt;span class="nt"&gt;-u&lt;/span&gt; dokku &lt;span class="nt"&gt;-e&lt;/span&gt;

@daily dokku &lt;span class="nt"&gt;--rm&lt;/span&gt; run django_dokku_example python manage.py clearsessions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we setup &lt;code&gt;clearsessions&lt;/code&gt; job to run each day and it can helps us clean out expired sessions in db.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short reviews from Accordbox
&lt;/h2&gt;

&lt;p&gt;Dokku is a very good option &lt;strong&gt;if you have limited budget but you still like the Heroku experience or you want to use Heroku on AWS EC2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no silver bullet in this world, so I will also talk about limitations of Dokku here.&lt;/p&gt;

&lt;p&gt;Because of the design of Dokku, it is not easy to scale the app. &lt;strong&gt;So if your project needs HA (high availability), Dokku might not be a good choice here&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this Dokku tutorial, I showed you how to deploy Django project to Dokku.&lt;/p&gt;

&lt;p&gt;The source code of this post can be found on &lt;a href="https://github.com/AccordBox/django_dokku_example" rel="noopener noreferrer"&gt;Django Dokku example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What should you go next? There are still some funny things for you to check.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dokku postgres:backup&lt;/code&gt; can be used to uppload db backup to AWS S3.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dokku ps:report&lt;/code&gt; can give you app report and you can stop, scale and restart as you like.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you have any question, please feel free to contact us.&lt;/p&gt;

&lt;p&gt;This blog was originally published on &lt;a href=""&gt;How to deploy Django project to Dokku&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
    </item>
    <item>
      <title>Heroku Logs Tutorial</title>
      <dc:creator>Michael Yin</dc:creator>
      <pubDate>Tue, 08 Oct 2019 12:50:05 +0000</pubDate>
      <link>https://dev.to/michaelyin/heroku-logs-tutorial-1g75</link>
      <guid>https://dev.to/michaelyin/heroku-logs-tutorial-1g75</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Heroku's logging feature is not the same as traditional Linux servers so I'd like to write a post talking about this feature in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic concepts and workflow
&lt;/h2&gt;

&lt;p&gt;First, I'd like you to have a basic understanding of how Heroku logging process works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Heroku’s Logplex router is responsible for collating and distributing the log entries generated by your app and other components of the Heroku platform&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ekrdeGHm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devcenter1.assets.heroku.com/article-images/1521584374-logplex-sources-and-drains.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ekrdeGHm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devcenter1.assets.heroku.com/article-images/1521584374-logplex-sources-and-drains.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, if you use Heroku CLI to check the log, then can see logs from many different sources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heroku logs command
&lt;/h2&gt;

&lt;p&gt;Heroku CLI has command to help you quickly check the Heroku logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;USAGE
  &lt;span class="nv"&gt;$ &lt;/span&gt;heroku logs

OPTIONS
  &lt;span class="nt"&gt;-a&lt;/span&gt;, &lt;span class="nt"&gt;--app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app        &lt;span class="o"&gt;(&lt;/span&gt;required&lt;span class="o"&gt;)&lt;/span&gt; app to run &lt;span class="nb"&gt;command &lt;/span&gt;against

  &lt;span class="nt"&gt;-d&lt;/span&gt;, &lt;span class="nt"&gt;--dyno&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dyno      only show output from this dyno &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;such as &lt;span class="s2"&gt;"web"&lt;/span&gt; or
                       &lt;span class="s2"&gt;"worker"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="nt"&gt;-n&lt;/span&gt;, &lt;span class="nt"&gt;--num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;num        number of lines to display

  &lt;span class="nt"&gt;-r&lt;/span&gt;, &lt;span class="nt"&gt;--remote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;remote  git remote of app to use

  &lt;span class="nt"&gt;-s&lt;/span&gt;, &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;source  &lt;/span&gt;only show output from this &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;such as &lt;span class="s2"&gt;"app"&lt;/span&gt; or
                       &lt;span class="s2"&gt;"heroku"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="nt"&gt;-t&lt;/span&gt;, &lt;span class="nt"&gt;--tail&lt;/span&gt;           continually stream logs

  &lt;span class="nt"&gt;--force-colors&lt;/span&gt;       force use of colors &lt;span class="o"&gt;(&lt;/span&gt;even on non-tty output&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since the log come from different sourcee, when using &lt;code&gt;heroku logs&lt;/code&gt; command, you can add some options to filter the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;# display logs for web&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;heroku logs &lt;span class="nt"&gt;-d&lt;/span&gt; web &lt;span class="nt"&gt;-a&lt;/span&gt; heroku-app

&lt;span class="c"&gt;# display logs for redis plugin&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;heroku logs &lt;span class="nt"&gt;-d&lt;/span&gt; heroku-redis &lt;span class="nt"&gt;-a&lt;/span&gt; heroku-app

&lt;span class="c"&gt;# display logs come from app&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;heroku logs &lt;span class="nt"&gt;--source&lt;/span&gt; app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also add &lt;code&gt;-t&lt;/code&gt; to see realtime log just like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;heroku logs &lt;span class="nt"&gt;-a&lt;/span&gt; heroku-app &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Heroku logs look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;DATATIME app[heroku-redis]: blah blah blah
DATATIME app[web.1]: blah blah blah
DATATIME heroku[router] blah blah blah
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So the log format is something like this &lt;code&gt;{datetime} {source}[{dyno}]: blah blah blah&lt;/code&gt;, so &lt;code&gt;-d&lt;/code&gt; and &lt;code&gt;-s&lt;/code&gt; can help you filter logs in good way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error log with Sentry
&lt;/h2&gt;

&lt;p&gt;Since Heroku logs do not to do store job (it works like streaming service), so here I'd like to give you a way to do error logging.&lt;/p&gt;

&lt;p&gt;Heroku has plugin called &lt;code&gt;Sentry&lt;/code&gt; to help you do error logging, it would catch error, save the error trackback data, and send you email notification. The &lt;code&gt;free plan&lt;/code&gt; is good to go for most projects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You need to add the add-on for your Heroku app (you can do that in web page or terminal command &lt;code&gt;heroku addons:create sentry&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After you add the add-on, a new config variable &lt;code&gt;SENTRY_DSN&lt;/code&gt; would be adeed, just check using &lt;code&gt;heroku config&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then you need to add Sentry code to your project. (you can get the code on sentry homepage)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For, example, if you want to use Sentry with Django project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pip install sentry-sdk&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add code below to your Django settings file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sentry_sdk&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sentry_sdk.integrations.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DjangoIntegration&lt;/span&gt;

&lt;span class="n"&gt;sentry_sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;dsn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'SENTRY_DSN'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;integrations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DjangoIntegration&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sentry would help you aggregate the error logging and traceback data, it would also send you email error report. So you might not need to Heroku log to troubleshoot some error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6F5wlI5T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.accordbox.com/upload/images/sentry-sample-error.original.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6F5wlI5T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.accordbox.com/upload/images/sentry-sample-error.original.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging Persistence
&lt;/h2&gt;

&lt;p&gt;Since Heroku log work like stream service and it would not save it for you (you can only get the latest 1500 lines), so if you want to save the log to somewhere, there are some ways to do that.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use some add-on, I would recommend &lt;code&gt;logentries&lt;/code&gt;, which also have free plan for you to get started.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another way is to implement custom &lt;code&gt;log drains&lt;/code&gt;, please check Heroku doc for more details.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this Heorku tutorial, I talked about how to use heroku logs and how to use Sentry to record error log for Heroku app.&lt;/p&gt;

&lt;p&gt;If you have any question, please feel free to contact us.&lt;/p&gt;

</description>
      <category>devops</category>
    </item>
    <item>
      <title>How to use Heroku Pipeline</title>
      <dc:creator>Michael Yin</dc:creator>
      <pubDate>Tue, 24 Sep 2019 08:23:03 +0000</pubDate>
      <link>https://dev.to/michaelyin/how-to-use-heroku-pipeline-60h</link>
      <guid>https://dev.to/michaelyin/how-to-use-heroku-pipeline-60h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This post is #4 of my &lt;a href="https://www.accordbox.com/blog/django-heroku-tutorial/" rel="noopener noreferrer"&gt;Python Heroku Tutorial Series&lt;/a&gt;. In this Heroku tutorial, I will talk about how to setup Heroku pipeline and how to use it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Heroku pipeline is a group of Heroku apps that share the same codebase. Each app in a pipeline represents one of the following stages in a continuous delivery workflow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Development&lt;/li&gt;
&lt;li&gt;Review&lt;/li&gt;
&lt;li&gt;Staging&lt;/li&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Heroku review app now only work with Github and it is not required in most cases (we can use different tests to make sure code work fine)&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow with Gitlab
&lt;/h2&gt;

&lt;p&gt;There are some different ways to use Heroku pipeline, here is my workflow and hope it can inspire you.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When we merge some feature to master branch, we would push the code to Gitlab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gitlab CI would check code style, run unittests, live tests to make sure all feature works fine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If commit pass the CI, the code would be deployed to &lt;code&gt;staging app&lt;/code&gt; of Heroku pipeline&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can do some manual tests and check if the function work fine (this step is not required in some cases)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If we think the commit is good to go, we sould promote the code from &lt;code&gt;staging app&lt;/code&gt; to &lt;code&gt;production app&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;staging app&lt;/code&gt; and &lt;code&gt;production app&lt;/code&gt; share the same code (in some cases, code version in &lt;code&gt;staging app&lt;/code&gt; might be a little newer), but they have different env resources (database, AWS S3 bucket, domain name and other config vars)&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Heroku Pipeline in Heroku dashboard
&lt;/h2&gt;

&lt;p&gt;In heroku dashboard, &lt;strong&gt;make sure you already have Heroku app, then add it to a new Heroku pipeline&lt;/strong&gt; you can do that in app's &lt;code&gt;Deploy&lt;/code&gt; tab&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fheroku-pipeline-create-new-pipeline.original.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fheroku-pipeline-create-new-pipeline.original.png"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;After you are done, you can see the pipeline in your Heroku Dashboard and you can keep adding a new Heroku app to pipeline as &lt;code&gt;production app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fheroku-pipeline-list.original.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.accordbox.com%2Fupload%2Fimages%2Fheroku-pipeline-list.original.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Heroku Pipeline in Heroku CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;heroku pipelines:create &lt;span class="nt"&gt;-a&lt;/span&gt; django-heroku-docker

? Pipeline name django-heroku
? Stage of django-heroku-docker staging
Creating django-heroku pipeline... &lt;span class="k"&gt;done
&lt;/span&gt;Adding ⬢ django-heroku-docker to django-heroku pipeline as staging... &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to add Heroku app to pipeline&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;heroku pipelines:add django-heroku &lt;span class="nt"&gt;-a&lt;/span&gt; django-heroku-docker-production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to promote staging app
&lt;/h2&gt;

&lt;p&gt;When you test the version on your &lt;code&gt;staging app&lt;/code&gt; and seems it is good to deploy to &lt;code&gt;production app&lt;/code&gt;, you can just click &lt;code&gt;Promote to production...&lt;/code&gt; on pipeline page.&lt;/p&gt;

&lt;p&gt;The code would be deployed to &lt;code&gt;production app&lt;/code&gt; automatically.&lt;/p&gt;

&lt;p&gt;Please note that if you are using &lt;code&gt;docker&lt;/code&gt; to deploy your project, the above &lt;code&gt;promote&lt;/code&gt; button might not work in some cases. To solve this problem, you can define the &lt;code&gt;promote&lt;/code&gt; work as manual work in CI. (or let CI auto deploy &lt;code&gt;prod&lt;/code&gt; branch to production app)&lt;/p&gt;

&lt;h2&gt;
  
  
  Some tips
&lt;/h2&gt;

&lt;p&gt;To avoid operation mistake, it is better to make your Heroku app have the right suffix.&lt;/p&gt;

&lt;p&gt;For example, you are developing a project &lt;code&gt;whitewave&lt;/code&gt;, the staging app has name &lt;code&gt;whitewave-staging&lt;/code&gt; and production app has name &lt;code&gt;whitewave-prod&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you should keep in mind
&lt;/h2&gt;

&lt;p&gt;When you start using Heroku pipelines, you should know &lt;strong&gt;two Heroku apps and relevant resources could cost you more money than single Heroku app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But the pipeline can make sure every commit has been tested before deployed to your production site, it reduced the risk, that is why I recommend you to give it a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this Heroku tutorial, I talked about how to use Heroku pipeline in your project and if you still have question, please feel free to contact.&lt;/p&gt;

</description>
      <category>devops</category>
    </item>
    <item>
      <title>How to deploy Python project to Heroku in Gitlab CI</title>
      <dc:creator>Michael Yin</dc:creator>
      <pubDate>Tue, 17 Sep 2019 09:17:30 +0000</pubDate>
      <link>https://dev.to/michaelyin/how-to-deploy-python-project-to-heroku-in-gitlab-ci-47la</link>
      <guid>https://dev.to/michaelyin/how-to-deploy-python-project-to-heroku-in-gitlab-ci-47la</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this Heroku tutorial, I will talk about how to deploy python project to Heroku in Gitlab CI&lt;/p&gt;

&lt;p&gt;After reading, you will get:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;How to create Heroku token to access the Heroku platform API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to deploy the project to Heroku using Heroku CLI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to deploy the project to Heroku using &lt;code&gt;dpl&lt;/code&gt; package.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Register Heroku API token
&lt;/h2&gt;

&lt;p&gt;First, we should create a &lt;code&gt;Heroku token&lt;/code&gt;, and then we can use that token to call some Heroku API for us to deploy Python project.&lt;/p&gt;

&lt;p&gt;There are mainly two ways for us to create Heroku API token.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Please go to &lt;a href="https://dashboard.heroku.com/account"&gt;Heorku account setting&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the bottom, you can see a section &lt;code&gt;API Key&lt;/code&gt; and you can generate API token there.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another way is to create API in Heroku CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USAGE
  $ heroku authorizations:create

OPTIONS
  -S, --short                    only output token
  -d, --description=description  set a custom authorization description

  -e, --expires-in=expires-in    set expiration in seconds (default no
                                 expiration)

  -j, --json                     output in json format

  -s, --scope=scope              set custom OAuth scopes

DESCRIPTION
  This creates an authorization with access to your Heroku account.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;heroku authorizations:create &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"token for Django project"&lt;/span&gt;

&lt;span class="c"&gt;# after you create, you can check existing tokens with this command&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;heroku authorizations
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are some little difference for you to create token in the account settings page and Heroku CLI&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If you have changed your Heroku account password, the token created in account settings page would expire.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can create multiple tokens (one token for one project) and add description using Heroku CLI.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I would recommend to use Heroku CLI to create token for your Heorku API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Heroku API token in Gitlab CI
&lt;/h2&gt;

&lt;p&gt;There are also two ways to do this, you should create &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; at root of your project and Gitlab would scan it automatically.&lt;/p&gt;

&lt;p&gt;One way is to install Heroku CLI and config the git repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;debian:stretch&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;HEROKU_APP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;django&lt;/span&gt;
    &lt;span class="na"&gt;HEROKU_DEPLOYMENT_BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get update -y&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get install -y curl git gnupg&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl https://cli-assets.heroku.com/install-ubuntu.sh | sh&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cat &amp;gt;~/.netrc &amp;lt;&amp;lt;EOF&lt;/span&gt;
      &lt;span class="s"&gt;machine api.heroku.com&lt;/span&gt;
        &lt;span class="s"&gt;login $HEROKU_EMAIL&lt;/span&gt;
        &lt;span class="s"&gt;password $HEROKU_TOKEN&lt;/span&gt;
      &lt;span class="s"&gt;machine git.heroku.com&lt;/span&gt;
        &lt;span class="s"&gt;login $HEROKU_EMAIL&lt;/span&gt;
        &lt;span class="s"&gt;password $HEROKU_TOKEN&lt;/span&gt;
      &lt;span class="s"&gt;EOF&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod 600 ~/.netrc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;heroku git:remote --app $HEROKU_APP&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git checkout master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git push heroku master:$HEROKU_DEPLOYMENT_BRANCH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You need to set &lt;code&gt;$HEROKU_EMAIL&lt;/code&gt; and &lt;code&gt;$HEROKU_TOKEN&lt;/code&gt; in Gitlab CI env variable to make it work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You need to change &lt;code&gt;$HEROKU_APP&lt;/code&gt; to your Heroku app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We installed Heroku CLI and then &lt;code&gt;$HEROKU_TOKEN&lt;/code&gt; in ~/.netrc can make the Heroku CLI can access Heroku API.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another way is to use a package &lt;code&gt;dpl&lt;/code&gt; to do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;HEROKU_APP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;django&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install dpl&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dpl --provider=heroku --app=$HEROKU_APP --api-key=$HEROKU_TOKEN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After you push the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; to master branch of Gitlab repo, new commits to master branch would be deployed to Heroku automatically. So you do not need to deploy in local env.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this Heroku tutorial, I talked about how to deploy project to Heroku in Gitlab CI, you can change the config code to make it work on other CI.&lt;/p&gt;

&lt;p&gt;If you have any question, please feel free to contact us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.heroku.com/PBGP6IDE/how-should-i-generate-an-api-key-that-allows-me-to-use-the-heroku-platform-api"&gt;heroku authorizations:create&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally posted on &lt;a href="https://www.accordbox.com/blog/how-deploy-python-project-heroku-gitlab-ci/"&gt;How to deploy Python project to Heroku in Gitlab CI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>python</category>
    </item>
  </channel>
</rss>
