<?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: kenshuri</title>
    <description>The latest articles on DEV Community by kenshuri (@kenshuri).</description>
    <link>https://dev.to/kenshuri</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%2F917370%2Ffd7d606c-800c-44e4-80ea-a79d123fdc7a.PNG</url>
      <title>DEV Community: kenshuri</title>
      <link>https://dev.to/kenshuri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kenshuri"/>
    <language>en</language>
    <item>
      <title>Move your Django App from Heroku to CapRover</title>
      <dc:creator>kenshuri</dc:creator>
      <pubDate>Sun, 23 Oct 2022 18:09:12 +0000</pubDate>
      <link>https://dev.to/kenshuri/move-your-django-app-from-heroku-to-caprover-11ap</link>
      <guid>https://dev.to/kenshuri/move-your-django-app-from-heroku-to-caprover-11ap</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was initially posted on &lt;a href="https://blog.kenshuri.com/posts/006_from_heroku_to_capRover.md" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you move?
&lt;/h2&gt;

&lt;p&gt;I guess that if you're here, you already know... Quite sadly, starting November 28th, 2022, free Heroku Dynos and free Heroku Postgres will no longer be available.&lt;br&gt;
While many devs happily used Heroku for their hobby projects and spend almost no time worrying about deployment, now is a good time to find another option than Heroku.&lt;/p&gt;

&lt;p&gt;There are several good options out there, but today we'll be talking about &lt;a href="https://caprover.com/" rel="noopener noreferrer"&gt;CapRover&lt;/a&gt;. &lt;br&gt;
I chose &lt;a href="https://caprover.com/" rel="noopener noreferrer"&gt;CapRover&lt;/a&gt; after a quick &lt;em&gt;literature review&lt;/em&gt;, see for instance &lt;a href="https://dev.to/lorenzojkrl/bye-bye-heroku-2npi"&gt;here&lt;/a&gt;, &lt;a href="https://dev.to/timhub/self-host-heroku-alternative-40l4"&gt;there&lt;/a&gt; or &lt;a href="https://github.com/ripienaar/free-for-dev#web-hosting" rel="noopener noreferrer"&gt;there&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;CapRover describes itself as &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;an extremely easy to use app/database deployment &amp;amp; web server manager for your NodeJS, Python, PHP, ASP.NET, Ruby, MySQL, MongoDB, Postgres, WordPress (and etc...) applications! It's blazingly fast and very robust as it uses Docker, nginx, LetsEncrypt and NetData under the hood behind its simple-to-use interface.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before going further, please note that I could not find a 100% free replacement for Heroku. CapRover is free and will remove from your &lt;br&gt;
shoulders most of the complexity of deploying your apps, but to make it work you still need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a VPS server of your choice: around 5$/month&lt;/li&gt;
&lt;li&gt;a domain name: around 10$/year&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good luck to find 100% free providers for these 😉 Now that this is clear, let's &lt;a href="https://caprover.com/docs/get-started.html" rel="noopener noreferrer"&gt;get started&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get yourself a domain name&lt;/li&gt;
&lt;li&gt;Get yourself a server&lt;/li&gt;
&lt;li&gt;Set-up DNS&lt;/li&gt;
&lt;li&gt;Deploy your app to CapRover&lt;/li&gt;
&lt;li&gt;Deploy a Django app with heavier dependencies&lt;/li&gt;
&lt;li&gt;Go full DevOps&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to go straight to the code, see &lt;a href="https://github.com/kenshuri/django_tailwind_caprover" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Get yourself a domain name
&lt;/h2&gt;

&lt;p&gt;I won't list all the existing options as many have done it already... You can look &lt;a href="https://themeisle.com/blog/best-domain-registrars/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or &lt;a href="https://www.codeinwp.com/blog/cheap-domains/" rel="noopener noreferrer"&gt;here&lt;/a&gt; for instance. &lt;br&gt;
In my case I chose &lt;a href="https://www.ovhcloud.com/en-ie/domains/" rel="noopener noreferrer"&gt;OVHCloud&lt;/a&gt; as it competed well with others in terms of pricing and has its headquarters in my country.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Get yourself a server
&lt;/h2&gt;

&lt;p&gt;Choosing a server is more delicate than choosing a domain name. To do so, you should follow the &lt;a href="https://caprover.com/docs/get-started.html#b2-server-specs" rel="noopener noreferrer"&gt;requiremnts listed&lt;br&gt;
by CapRover&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I chose the easy way, the one recommended by CapRover, which is &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;to install CapRover is via DigitalOcean one-click app. CapRover is available as a One-Click app in DigitalOcean marketplace.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I simply used &lt;a href="https://marketplace.digitalocean.com/apps/caprover?action=deploy&amp;amp;refcode=6410aa23d3f3" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to create a droplet (ie a server in DigitcalOcean vocabulary)&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Set-up DNS
&lt;/h2&gt;

&lt;p&gt;Now, you need to &lt;em&gt;connect&lt;/em&gt; your domain to your server. &lt;br&gt;
To do so, you need to change the DNS settings, so that when you connect to your domain, you're being redirected to your server.&lt;br&gt;
You need to create an &lt;code&gt;A-record&lt;/code&gt; in your DNS settings. It should be quite straight-forward to do in your domain manager website.&lt;/p&gt;

&lt;p&gt;In my case, I need to go to &lt;a href="https://www.ovh.com/manager/#/web/configuration" rel="noopener noreferrer"&gt;OVH manager&lt;/a&gt; and then&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href=""&gt;Domain names&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select my &lt;a href=""&gt;domain name&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Click on &lt;a href=""&gt;DNS zone&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;And finally &lt;a href=""&gt;Add an entry&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/saf17s" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2Fsaf17s.md.jpg" alt="saf17s.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, create an &lt;code&gt;A-record&lt;/code&gt; and &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose any sub-domain: in my case I chose &lt;code&gt;blog&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;As a target, use the ipv4 address of your server (or droplet if you're using DigitalOcean) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/saCrQ4" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FsaCrQ4.md.jpg" alt="saCrQ4.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Set-up CapRover on your server
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;from &lt;a href="https://caprover.com/docs/get-started.html#step-3-install-caprover-cli" rel="noopener noreferrer"&gt;CapRover Getting started doc&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Assuming you have npm installed on your local machine (e.g., your laptop), simply run (add sudo if needed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; caprover
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, run&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Below are the several steps and the answer to give if you are hesitating.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PS C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\a&lt;/span&gt;lexi&amp;gt; caprover serversetup

Setup CapRover machine on your server...

? have you already started CapRover container on your server? Yes
? IP address of your server: Your server &lt;span class="o"&gt;(&lt;/span&gt;droplet&lt;span class="o"&gt;)&lt;/span&gt; ipv4 address 
? CapRover server root domain: blog.yourdomain.com assuming that you &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.blog.mydomain.com to point to your IP address when creating the A-record
? new CapRover password &lt;span class="o"&gt;(&lt;/span&gt;min 8 characters&lt;span class="o"&gt;)&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;hidden]
? enter new CapRover password again: &lt;span class="o"&gt;[&lt;/span&gt;hidden]
? &lt;span class="s2"&gt;"valid"&lt;/span&gt; email address to get certificate and &lt;span class="nb"&gt;enable &lt;/span&gt;HTTPS: your.mail@mail.com
? CapRover machine name, with whom the login credentials are stored locally: captain-01

CapRover server setup completed: it is available as captain-01 at https://captain.blog.yourdomain.com

For more details and docs see CapRover.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As prompted, you can now visit the page &lt;code&gt;https://captain.blog.yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Deploy your app to CapRover
&lt;/h2&gt;

&lt;p&gt;To deploy to CapRover, you will need a &lt;a href="https://caprover.com/docs/captain-definition-file.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Captain Definition File&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
This file plays a similar role to the &lt;code&gt;Procfile&lt;/code&gt; when you're deploying to Heroku. &lt;br&gt;
It describes the foundation to run your app: its language and version.&lt;br&gt;
As the &lt;code&gt;Procfile&lt;/code&gt;, it needs to sit at the root of the project, next to the &lt;code&gt;requirements.txt&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In our case, as we are deploying a django app, it should contain the following (depending on your python version).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
  "schemaVersion": 2,
  "templateId": "python-django/3.10"
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to try and actually deploy something, you could clone &lt;a href="https://github.com/kenshuri/django_tailwind_caprover" rel="noopener noreferrer"&gt;this project&lt;/a&gt; and&lt;br&gt;
follow the instructions in the &lt;code&gt;README&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1. Create a CapRover app
&lt;/h3&gt;

&lt;p&gt;On the page &lt;code&gt;https://captain.blog.yourdomain.com&lt;/code&gt;, in &lt;code&gt;Apps&lt;/code&gt;, create a new app with the name of your choice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/saVdve" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FsaVdve.md.jpg" alt="saVdve.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, go in your config in CapRover and &lt;code&gt;Enable HTTPS&lt;/code&gt;. If you try to access your app at the address propsed&lt;br&gt;
(which should look like &lt;a href="https://this-is-a-test-app.blog.yourdomain.com" rel="noopener noreferrer"&gt;https://this-is-a-test-app.blog.yourdomain.com&lt;/a&gt;), you should see something like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/saVDHF" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FsaVDHF.md.jpg" alt="saVDHF.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4.2. Deploy your app
&lt;/h3&gt;

&lt;p&gt;In a terminal run&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And follow the steps:&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="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; PS &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; caprover deploy


Preparing deployment to CapRover...

? &lt;span class="k"&gt;select &lt;/span&gt;the CapRover machine name you want to deploy to: captain-01
Ensuring authentication...
? &lt;span class="k"&gt;select &lt;/span&gt;the app name you want to deploy to: this-is-a-test-app
? git branch name to be deployed: main
? note that uncommitted and gitignored files &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;any&lt;span class="o"&gt;)&lt;/span&gt; will not be pushed to server! Are you sure you want to
deploy? Yes

Build has finished successfully!

Deployed successfully this-is-a-test-app
App is available at https://this-is-a-test-app.blog.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bravo 👏👏 Your app should now be successfully deployed!!&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3. Add environment variables
&lt;/h3&gt;

&lt;p&gt;You should see something like this :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/saWszG" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FsaWszG.md.jpg" alt="saWszG.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, we're almost there... As described in the repo &lt;a href="https://github.com/kenshuri/django_tailwind_caprover" rel="noopener noreferrer"&gt;&lt;code&gt;README&lt;/code&gt;&lt;/a&gt;, we need to modify our app environments variables.&lt;/p&gt;

&lt;p&gt;To do so, go in the tab &lt;code&gt;App Configs&lt;/code&gt; in CapRover, and use the bulk edit to create the environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DJANGO_DEBUG=TRUE
DJANGO_SECRET_KEY=^a@fg8s132ksy00(ww9xc-vgi3v78om#$rh(a-(9)68a=zptk2
APP_ALLOWED_HOSTS=this-is-a-test-app.blog.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to you app again. Do you see something like this?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/fr" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2Fsajlxs.jpg" alt="sajlxs.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It could be for 2 reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to upload the CSS file&lt;/li&gt;
&lt;li&gt;You need to run &lt;code&gt;collectstatic&lt;/code&gt; at deployment so that your static files are served to the server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.4. Upload the CSS file
&lt;/h3&gt;

&lt;p&gt;If the answer is yes, let's face it: this daisy button does not look at all like a &lt;a href="https://daisyui.com/components/button/#button" rel="noopener noreferrer"&gt;daisy button&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The reason is quite simple: it's simply because we did not push the css file. After cloning the example repo, you should&lt;br&gt;
create your own repo and push the css file. Here is the process I usually follow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new repo in Github, let's call it &lt;code&gt;test_app_cap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove the current remote branch from the repo you juste cloned &lt;code&gt;git remote rm origin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Finally push to your new repo
4.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin https://github.com/username/test_app_cap.git
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, you should build the css file as described in the repo &lt;code&gt;README&lt;/code&gt;&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="nb"&gt;cd &lt;/span&gt;jstoolchains
npm run tailwind-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new file &lt;code&gt;blogApp/static/css/output.css&lt;/code&gt; has been created. Commit and push it.&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="nb"&gt;cd&lt;/span&gt; ..
git commit .&lt;span class="se"&gt;\b&lt;/span&gt;logApp&lt;span class="se"&gt;\s&lt;/span&gt;tatic&lt;span class="se"&gt;\c&lt;/span&gt;ss&lt;span class="se"&gt;\o&lt;/span&gt;utput.css &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"update css"&lt;/span&gt;
git push origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5. Run &lt;code&gt;collectstatic&lt;/code&gt; at deployment
&lt;/h3&gt;

&lt;p&gt;To run &lt;code&gt;collectstatic&lt;/code&gt; at deployment, you need to tweak the &lt;code&gt;captain-definition&lt;/code&gt; file that we created before.&lt;/p&gt;

&lt;p&gt;The default &lt;code&gt;captain-definition&lt;/code&gt; for a &lt;code&gt;python-django&lt;/code&gt; app define a default list of commands to be executed at deployment. &lt;br&gt;
You can see these commands being executed (one step for each command) when you call &lt;code&gt;caprover deploy&lt;/code&gt;.&lt;br&gt;
Unfortunately, the &lt;code&gt;run collectstatic&lt;/code&gt; is not part of these default commands. &lt;br&gt;
We thus need to define a custom deployment file ourselves, stating explicitly that we want to run &lt;code&gt;collectstatic&lt;/code&gt;. &lt;br&gt;
To do so, we will create a custom &lt;code&gt;Dockerfile&lt;/code&gt;!&lt;/p&gt;
&lt;h4&gt;
  
  
  4.5.1 Modify &lt;code&gt;captain-definition&lt;/code&gt; file
&lt;/h4&gt;

&lt;p&gt;Change your current &lt;code&gt;captain-definition&lt;/code&gt; file so that it does not use the default &lt;code&gt;django-python&lt;/code&gt; list of commands&lt;br&gt;
but refer to your custom dockerfile instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;captain-definition

 {
  "schemaVersion": 2,
  "dockerfilePath": "./Dockerfile"
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.5.2 Create custom &lt;code&gt;Dockerfile&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;At the root of your project, create a custom &lt;code&gt;Dockerfile&lt;/code&gt; as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;#Dockerfile&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; library/python:3.10-alpine&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk upgrade &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; make g++ bash git openssh postgresql-dev curl

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/src/app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./requirements.txt /usr/src/app/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./ /usr/src/app&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;

&lt;span class="c"&gt;# Collect static files&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;python manage.py collectstatic &lt;span class="nt"&gt;--noinput&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "manage.py", "runserver", "0.0.0.0:80"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each row of this &lt;code&gt;Dockerfile&lt;/code&gt; corresponds to a command that was executed by default. &lt;br&gt;
You can check it against the steps executed when running &lt;code&gt;caprover deploy&lt;/code&gt; before. &lt;br&gt;
There is only one addition: &lt;code&gt;RUN python manage.py collectstatic --noinput&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that this is done, you can commit, push and deploy again !&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit .&lt;span class="se"&gt;\b&lt;/span&gt;logApp&lt;span class="se"&gt;\s&lt;/span&gt;tatic&lt;span class="se"&gt;\c&lt;/span&gt;ss&lt;span class="se"&gt;\o&lt;/span&gt;utput.css &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"add Dockerfile"&lt;/span&gt;
git push origin
caprover deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bravissimo 👏!! You have now deployed 🚀 a django app to your server using CapRover: bye-bye Heroku 👋👋!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Deploy a Django app with heavier dependencies
&lt;/h2&gt;

&lt;p&gt;While everything is running perfectly at the moment, you could quickly face deployment issues if your were to add some heavier dependencies.&lt;br&gt;
For instance, let's try to add &lt;code&gt;pandas&lt;/code&gt; to your &lt;code&gt;requirements.txt&lt;/code&gt; and deploy again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pandas
pip freeze &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt
git commit requirements.txt &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"add Pandas"&lt;/span&gt;
git push
caprover deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If as me, you took the cheapest server available on DigitalOcean with only 1GB of memory, there is a big chance that the &lt;br&gt;
deployment fails as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Collecting &lt;span class="nv"&gt;pandas&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;1.5.0
Downloading pandas-1.5.0.tar.gz &lt;span class="o"&gt;(&lt;/span&gt;5.2 MB&lt;span class="o"&gt;)&lt;/span&gt;
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.2/5.2 MB 108.9 MB/s eta 0:00:00

Installing build dependencies: started
Installing build dependencies: still running...
Installing build dependencies: still running...
Installing build dependencies: still running...

Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
502 - &lt;span class="s2"&gt;"&amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;502 Bad Gateway&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;502 Bad Gateway&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Error: connect ECONNREFUSED 164.92.140.20:443


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
502 - &lt;span class="s2"&gt;"&amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;502 Bad Gateway&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;502 Bad Gateway&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
502 - &lt;span class="s2"&gt;"&amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;502 Bad Gateway&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;502 Bad Gateway&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Captain is not ready yet...


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Captain is not ready yet...


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Captain is not ready yet...


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Error: connect ECONNREFUSED 164.92.140.20:443


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Error: connect ECONNREFUSED 164.92.140.20:443


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Error: connect ETIMEDOUT 164.92.140.20:443


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Captain is not ready yet...


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Captain is not ready yet...


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Password is incorrect.


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Password is incorrect.


Something bad happened &lt;span class="k"&gt;while &lt;/span&gt;retrieving issue-app app build logs.
Password is incorrect.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's happening here is that your server is running out of memory and the entire server crashes.&lt;/p&gt;

&lt;p&gt;This a well known issue documented&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In this &lt;a href="https://github.com/caprover/caprover/issues/1507" rel="noopener noreferrer"&gt;github&lt;/a&gt; issue&lt;/li&gt;
&lt;li&gt;In the &lt;a href="https://caprover.com/docs/best-practices.html#out-of-memory-when-building" rel="noopener noreferrer"&gt;doc&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The doc describes possible options below&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you build on a paid service such as Heroku, your build process happens on a machine with high CPU and RAM. When you use CapRover, your build is done on the same machine that serves your app. This is not a problem until your app gets too big and the build process requires too much RAM. In that case, your build process might crash! See this for example. There are multiple solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add swap space to the web server, explained here.&lt;/li&gt;
&lt;li&gt;Build on your local machine. For example, this process is explained in detail here for Create React App.&lt;/li&gt;
&lt;li&gt;However, the best solution is to use a separate build system. You can see the guide &lt;a href="https://caprover.com/docs/ci-cd-integration.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, there is a simpler one that I would like to introduce (solution 3 is also implemented later in this tutorial)!&lt;/p&gt;

&lt;p&gt;The problem is that the building of the docker image takes a lot of time. &lt;br&gt;
The main reason for this is that we use the Alpine linux image. &lt;br&gt;
This issue is discussed in this &lt;a href="https://stackoverflow.com/questions/49037742/why-does-it-take-ages-to-install-pandas-on-alpine-linux" rel="noopener noreferrer"&gt;stackoverflow ticket&lt;/a&gt; &lt;br&gt;
or in this very good &lt;a href="https://pythonspeed.com/articles/alpine-docker-python/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;br&gt;
To put it simply, Alpine Linux is usually a very good image to use, but not when packaging a Python application: it's better to use a Debian based image in such cases.&lt;br&gt;
This &lt;a href="https://hub.docker.com/_/python" rel="noopener noreferrer"&gt;page&lt;/a&gt; list several images available, we'll use the &lt;code&gt;slim&lt;/code&gt; image!&lt;/p&gt;

&lt;p&gt;Let's modify the &lt;code&gt;Dockerfile&lt;/code&gt; accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;#Dockerfile&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.10.8-slim&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/src/app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./requirements.txt /usr/src/app/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./ /usr/src/app&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "manage.py", "runserver", "0.0.0.0:80"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, deploy again your app&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;We're finally free from Heroku, and it works well! Moreover, now that you've deployed once, &lt;br&gt;
it's even faster than with Heroku to deploy again! &lt;/p&gt;
&lt;h2&gt;
  
  
  6. Go full DevOps
&lt;/h2&gt;

&lt;p&gt;To make your deployment even faster, we can follow Caprover doc advice, and implement a solution to build and deploy automatically from Github when a change happen on your main branch : how cool is that 😎 ??!!&lt;/p&gt;

&lt;p&gt;The steps are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable App Token in your CapRover app configuration&lt;/li&gt;
&lt;li&gt;Add Github Secrets&lt;/li&gt;
&lt;li&gt;Create Github Action&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Enable App Token in your CapRover app configuration
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;from &lt;a href="https://caprover.com/docs/ci-cd-integration/deploy-from-github.html#enable-app-token" rel="noopener noreferrer"&gt;CapRover doc&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Find the "Deployment" tab for your new app, click Enable App Token and copy this token. This is your &lt;strong&gt;&lt;code&gt;APP_TOKEN&lt;/code&gt;&lt;/strong&gt; secret.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a Personal Acces Token in Github
&lt;/h3&gt;

&lt;p&gt;In your Github Settings, go to &lt;a href="https://github.com/settings/apps" rel="noopener noreferrer"&gt;Developer settings&lt;/a&gt;. Then, in Personal access tokens, &lt;br&gt;
&lt;a href="https://github.com/settings/tokens/new" rel="noopener noreferrer"&gt;Generate a new classic token&lt;/a&gt; with scope: &lt;code&gt;write:packages&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Add the Docker Registry in Caprover
&lt;/h3&gt;

&lt;p&gt;On the caprover machine where your app is deployed, go to Cluster, and add your Remote Registry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/DCaHJe" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FDCaHJe.md.jpg" alt="DCaHJe.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Add Github Secrets
&lt;/h3&gt;

&lt;p&gt;Github secrets are variables used by Github when trying to deploy your app. You need to define several variables/secrets.&lt;/p&gt;

&lt;p&gt;To define your Github Secrets, go in your repo Settings &amp;gt; Secrets &amp;gt; Actions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://freeimage.host/i/sbHZf2" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fiili.io%2FsbHZf2.md.jpg" alt="sbHZf2.md.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And define the following repository secrets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CAPROVER_SERVER = &lt;a href="https://captain.blog.yourdomain.com" rel="noopener noreferrer"&gt;https://captain.blog.yourdomain.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CAPROVER_PASSWORD = yourcaproverpassword&lt;/li&gt;
&lt;li&gt;APP_NAME = this-is-a-test-app&lt;/li&gt;
&lt;li&gt;PAT = PERSONAL_ACCES_TOKEN&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Create Github Action
&lt;/h3&gt;

&lt;p&gt;Now, you need to tell Github that it should do something when a change happen on the main branch, and define what it should do.&lt;/p&gt;

&lt;p&gt;This is done thanks to &lt;code&gt;.yml&lt;/code&gt; that needs to live in a specific folder in your repo. Create a new file &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;&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="c1"&gt;#.github/workflows/deploy.yml&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to caprover&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository }}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Log in to the Container registry&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.actor }}&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.PAT }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract metadata (tags, labels) for Docker&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meta&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/metadata-action@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.tags }}&lt;/span&gt;
        &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.meta.outputs.labels }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy image&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;floms/action-caprover@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.CAPROVER_SERVER&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.CAPROVER_PASSWORD&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.APP_NAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&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;${{ steps.meta.outputs.tags }}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're finally done !!&lt;/p&gt;

&lt;p&gt;The final code is available &lt;a href="https://github.com/kenshuri/django_tailwind_caprover" rel="noopener noreferrer"&gt;here&lt;/a&gt; and the post was initially posted on my &lt;a href="https://blog.kenshuri.com/posts/006_from_heroku_to_capRover.md" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>django</category>
      <category>heroku</category>
      <category>caprover</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
