<?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: Matthew Platts</title>
    <description>The latest articles on DEV Community by Matthew Platts (@mplatts).</description>
    <link>https://dev.to/mplatts</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%2F74320%2F9c2aeac1-cd55-4d98-9109-aa8938bc1439.jpeg</url>
      <title>DEV Community: Matthew Platts</title>
      <link>https://dev.to/mplatts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mplatts"/>
    <language>en</language>
    <item>
      <title>Built a community sharing platform in my isolation to help with covid19</title>
      <dc:creator>Matthew Platts</dc:creator>
      <pubDate>Fri, 03 Apr 2020 21:32:18 +0000</pubDate>
      <link>https://dev.to/mplatts/built-a-community-sharing-platform-in-my-isolation-2ifd</link>
      <guid>https://dev.to/mplatts/built-a-community-sharing-platform-in-my-isolation-2ifd</guid>
      <description>&lt;p&gt;I was forced into isolation after returning to Melbourne from the US. Luckily, I had a friend in my apartment building to provide me with groceries - but I wondered how the less fortunate would be handling it.&lt;/p&gt;

&lt;p&gt;So during my 14 days stuck in my apartment I built this web app to allow people to signal if they need help or offer to provide help. Hopefully it helps someone, somewhere! A friend did the landing page, and another friend is trying to get it out there. Anyway, check it out and register your ability to help your local community.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.crisisheroes.com"&gt;www.crisisheroes.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tech:&lt;br&gt;
&lt;a href="https://www.phoenixframework.org/"&gt;Elixir (Phoenix)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.postgresql.org/"&gt;Postgres&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.algolia.com/"&gt;Algolia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tailwindcss.com/"&gt;Tailwind CSS&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/alpinejs/alpine"&gt;Alpine JS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deployed to &lt;a href="https://cloud.google.com/appengine/docs/flexible"&gt;Google Cloud Platform - App Engine Flex&lt;/a&gt;&lt;/p&gt;

</description>
      <category>covid19</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Deploying Phoenix via Dokku</title>
      <dc:creator>Matthew Platts</dc:creator>
      <pubDate>Sat, 11 May 2019 09:53:43 +0000</pubDate>
      <link>https://dev.to/mplatts/deploying-phoenix-via-dokku-1gip</link>
      <guid>https://dev.to/mplatts/deploying-phoenix-via-dokku-1gip</guid>
      <description>&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvdka3etm4kj12jwkloq5.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvdka3etm4kj12jwkloq5.png" alt="cover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deploy early and deploy often.&lt;/p&gt;

&lt;p&gt;I like making MVPs that could potentially turn into a proper startup. Obviously I want to save on costs. Non tech entrepreneurs often end up with a server on Amazon EC2 with an accompanying Postgres instance and end up paying over $100 per month. This is because they've hired a developer to do it who doesn't care about costs. &lt;/p&gt;

&lt;p&gt;You should only pay this much when your startup is validated and you have traction. Until then you are essentially in find-product-market-fit mode. It's unlikely many people will be using your site in this mode and you should ideally be on a $5/month VPS. Once you hit traction you can upgrade easy enough - export your DB and upgrade to Amazon or GCP. Phoenix on $5/month will handle a large amount of traffic if your app isn't overly complicated. &lt;/p&gt;

&lt;p&gt;I don't really like dev ops work so I'm going to use Dokku, which basically mimics Heroku in that it acts as a PaaS and you just do git remote pushes to deploy your code. I use this for all the projects I build with my &lt;a href="https://petal.build" rel="noopener noreferrer"&gt;Phoenix boilerplate template&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploying Phoenix on Vultr
&lt;/h1&gt;

&lt;p&gt;Note that this could apply to any VPS (eg Digital Ocean). I use Vultr because it has an Australian location option.&lt;/p&gt;

&lt;p&gt;Create a blank phoenix app using their &lt;a href="https://hexdocs.pm/phoenix/installation.html#content" rel="noopener noreferrer"&gt;install guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the server &lt;code&gt;mix phx.server&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftb37uiccylyhdwjabxmy.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftb37uiccylyhdwjabxmy.png" alt="Phoenix hello world screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get Ubuntu up and running somewhere in the cloud. For Vultr just register and click the big blue plus button.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Server Location: Pick one closest to you or your target audience.&lt;/li&gt;
&lt;li&gt;Server Type: Ubuntu 16.04 (could probably try newer versions - up to you)&lt;/li&gt;
&lt;li&gt;Server Size: Might as well start with a $5/month one&lt;/li&gt;
&lt;li&gt;Additional Features: All unchecked&lt;/li&gt;
&lt;li&gt;Startup script: Leave it empty&lt;/li&gt;
&lt;li&gt;SSH Keys: Add your computers ssh key (&lt;code&gt;cat ~/.ssh/id_rsa.pub&lt;/code&gt;) to see it. Or look up SSH keys if you don't have one.&lt;/li&gt;
&lt;li&gt;Server Hostname &amp;amp; Label: Whatever you want&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once that's installed, click on it and get the IP address and password so we can login.&lt;/p&gt;

&lt;p&gt;Mine is 45.76.112.118.&lt;/p&gt;

&lt;p&gt;In your terminal login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh root@45.76.112.118

Are you sure you want to continue connecting (yes/no)? yes
root@45.76.112.118's password:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste your password.&lt;/p&gt;

&lt;p&gt;Now that we're inside the Ubuntu instance we should first ensure all the linux packages are up to date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can install &lt;a href="http://dokku.viewdocs.io/dokku/" rel="noopener noreferrer"&gt;dokku&lt;/a&gt;. Make sure you check those docs as the version might be higher than what I'm using.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/dokku/dokku/v0.20.4/bootstrap.sh;
sudo DOKKU_TAG=v0.20.4 bash bootstrap.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in your browser copy and paste your server's IP address into the address bar and follow the web installer.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flq5hj0uj2edxobqz9jw5.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flq5hj0uj2edxobqz9jw5.png" alt="Dokku web installer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just add your ssh key like before - &lt;code&gt;cat ~/.ssh/id_rsa.pub&lt;/code&gt;. And I just leave the rest as defaults. Click finish.&lt;/p&gt;

&lt;p&gt;Now that Dokku is installed we can start using its command line interface (CLI) to setup a database and link it to our app.&lt;/p&gt;

&lt;p&gt;Still on your remote server run these commands (note that I'm calling my app card-tracker).&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;# Create a dokku app called card-tracker&lt;/span&gt;
dokku apps:create card-tracker

&lt;span class="c"&gt;# Dokku has lots of plugins - this one helps us create a postgres db&lt;/span&gt;
dokku plugin:install https://github.com/dokku/dokku-postgres.git

&lt;span class="c"&gt;# Use the pluging to create a db instance called 'db'&lt;/span&gt;
dokku postgres:create db

&lt;span class="c"&gt;# Linking just creates a global ENV config variable in card-tracker called 'DATABASE_URL`&lt;/span&gt;
dokku postgres:link db card-tracker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your dokku app has settable global ENV config variables. You use these to set stuff you don't want to commit into git - important stuff like your database credentials, third party api keys, etc.&lt;/p&gt;

&lt;p&gt;You can check the currently set ENV vars with &lt;code&gt;dokku config:export card-tracker&lt;/code&gt;. There should be only one set - &lt;code&gt;DATABASE_URL&lt;/code&gt;. This was set when you ran &lt;code&gt;dokku postgres:link db card-tracker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Go back to your phoenix app codebase and look at the file &lt;code&gt;prod.secret.exs&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2xcr0jjgc4p28w09583q.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2xcr0jjgc4p28w09583q.png" alt="Prod secret file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see Phoenix by default will look for an ENV var called &lt;code&gt;DATABASE_URL&lt;/code&gt; and set up your database to use it for the credentials. Handy.&lt;/p&gt;

&lt;p&gt;The Endpoint config is oddly split over &lt;code&gt;prod.exs&lt;/code&gt; and &lt;code&gt;prod.secret.exs&lt;/code&gt; (when you write &lt;code&gt;config :app, AppWeb.Endpoint, blah&lt;/code&gt;, it's just adding to the existing config, not overwriting it). &lt;/p&gt;

&lt;p&gt;I ended up deleting the Endpoint config in &lt;code&gt;prod.exs&lt;/code&gt; and putting it completely in &lt;code&gt;prod.secret.exs&lt;/code&gt; for simplicity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# I deleted this from prod.exs:&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;url:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;host:&lt;/span&gt; &lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;cache_static_manifest:&lt;/span&gt; &lt;span class="s2"&gt;"priv/static/cache_manifest.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the file &lt;code&gt;prod.secret.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;cache_static_manifest:&lt;/span&gt; &lt;span class="s2"&gt;"priv/static/cache_manifest.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;http:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"4000"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="ss"&gt;url:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;scheme:&lt;/span&gt; &lt;span class="s2"&gt;"https"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;host:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"WEB_HOST"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;force_ssl:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;rewrite_on:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:x_forwarded_proto&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="ss"&gt;secret_key_base:&lt;/span&gt; &lt;span class="n"&gt;secret_key_base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now back to our remote server we can set the &lt;code&gt;WEB_HOST&lt;/code&gt; global ENV variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku config:set --no-restart card-tracker WEB_HOST=45.76.112.118
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also looking back at &lt;code&gt;prod.secret.exs&lt;/code&gt; down the bottom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;secret_key_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SECRET_KEY_BASE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="sd"&gt;"""
    environment variable SECRET_KEY_BASE is missing.
    You can generate one by calling: mix phx.gen.secret
    """&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;http:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:inet6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"4000"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="ss"&gt;secret_key_base:&lt;/span&gt; &lt;span class="n"&gt;secret_key_base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should generate a &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; by running &lt;code&gt;mix phx.gen.secret&lt;/code&gt;. Do that in your console on your local computer (not remote).&lt;/p&gt;

&lt;p&gt;Then set it on the remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dokku config:set &lt;span class="nt"&gt;--no-restart&lt;/span&gt; card-tracker &lt;span class="nv"&gt;SECRET_KEY_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"TGISHf+6hJiQgEuroRY29k8IWnmY9MzggnPY86x16AYkJnMoPZDBcRuVgiUkT/Zu"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you run &lt;code&gt;dokku config:export card-tracker&lt;/code&gt; again you should have ENV vars for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DATABASE_URL&lt;/li&gt;
&lt;li&gt;SECRET_KEY_BASE&lt;/li&gt;
&lt;li&gt;WEB_HOST&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now go back to local terminal inside your phoenix app. We need to add our server as a remote to push to.&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;# Add a remote called dokku. In the dokku setup it created a user called dokku&lt;/span&gt;
git remote add dokku dokku@45.76.112.118:card-tracker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're still not quite ready to deploy though. Like I said Dokku is like Heroku - and even Heroku doesn't support all languages and frameworks. Instead it relies on "buildpacks", which are basically install scripts for different environments. There is &lt;a href="https://github.com/HashNuke/heroku-buildpack-elixir" rel="noopener noreferrer"&gt;one for Phoenix&lt;/a&gt;. If you are serving static content (like JS/CSS) then you also need a &lt;a href="https://github.com/gjaldon/heroku-buildpack-phoenix-static" rel="noopener noreferrer"&gt;Phoenix static buildpack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are a couple of ways to tell Dokku what buildpacks to use, but we'll use the method where you create a &lt;code&gt;.buildpacks&lt;/code&gt; file in the root of your Phoenix project.&lt;/p&gt;

&lt;p&gt;In you .buildpacks file add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/HashNuke/heroku-buildpack-elixir.git
https://github.com/gjaldon/heroku-buildpack-phoenix-static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The elixir buildpack allows you to set the elixir and erlang versions. To do this create another file called &lt;code&gt;elixir_buildpack.config&lt;/code&gt; in the root of your Phoenix project and add the contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;elixir_version=1.9.0
erlang_version=21.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The versions above worked for me as of 23 July 2019 - maybe google the latest or check yours with &lt;code&gt;brew info erlang&lt;/code&gt; and &lt;code&gt;brew info elixir&lt;/code&gt;. Although I found if I used the latest versions the deploy process failed. So if you get random deploy fails then move the versions back until it works.&lt;/p&gt;

&lt;p&gt;Finally, create another file called &lt;code&gt;Procfile&lt;/code&gt; in your root directory. Inside it add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: ./.platform_tools/elixir/bin/mix phx.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read up on Procfiles &lt;a href="https://devcenter.heroku.com/articles/procfile" rel="noopener noreferrer"&gt;here&lt;/a&gt;. They are a Heroku thing that Dokku also honours. I'm not really sure why we need to add this but I found it in a forum somewhere because without it my server wasn't working. The elixir buildpack says this "If your app doesn't have a Procfile, default web task mix run --no-halt will be run." So maybe that &lt;code&gt;mix run --no-halt&lt;/code&gt; isn't good enough anymore.&lt;/p&gt;

&lt;p&gt;Anyway, commit those 3 files and then let's try deploying!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add -A
git commit -m 'Add dokku config files'
git push dokku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will print out a bunch of install logs - might take a while. It should finish with something like:&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; Application deployed:
       http://45.76.112.118:31894
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste that URL into your browser (or CMD-click it if in iterm2) and you should see your app online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrations
&lt;/h2&gt;

&lt;p&gt;By default our elixir buildpack doesn't run Phoenix migrations. To run them, we'll need to utilise Dokkus post deploy hook. To do this we add another file in the root directory of our Phoenix folder called &lt;code&gt;app.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dokku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"postdeploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mix ecto.migrate"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit that and deploy and you should see that command being run in the logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domains
&lt;/h2&gt;

&lt;p&gt;By default Dokku is just using the IP address and using ports to show your app to the world.&lt;/p&gt;

&lt;p&gt;You could add another app &lt;code&gt;dokku apps:create blah&lt;/code&gt; and it would just live on another port.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://45.76.112.118:31894" rel="noopener noreferrer"&gt;http://45.76.112.118:31894&lt;/a&gt; =&amp;gt; card-tracker&lt;br&gt;
&lt;a href="http://45.76.112.118:32939" rel="noopener noreferrer"&gt;http://45.76.112.118:32939&lt;/a&gt; =&amp;gt; blah&lt;/p&gt;

&lt;p&gt;Anyway I registered cardtracker.com.au on Godaddy and I'd like this domain to point to my IP address.&lt;/p&gt;

&lt;p&gt;To do that I go into DNS settings in Godaddy and make sure there are no A records except for one: &lt;/p&gt;

&lt;p&gt;Type: A&lt;br&gt;
Name: @&lt;br&gt;
Value: 45.76.112.118&lt;/p&gt;

&lt;p&gt;This means cardtracker.com.au is now pointing to my remote server. Since I want www to also point there I can create a cname record to point to my root record:&lt;/p&gt;

&lt;p&gt;Type: CNAME&lt;br&gt;
Name: www&lt;br&gt;
Value: @&lt;/p&gt;

&lt;p&gt;Now on the remote server add the domain to Dokku:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku domains:add card-tracker cardtracker.com.au
dokku domains:add card-tracker www.cardtracker.com.au
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a bit of time for the changes to propagate. You can check what's happening in the terminal with &lt;code&gt;host -a cardtracker.com.au&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;Trying "cardtracker.com.au"
;; -&amp;gt;&amp;gt;HEADER&amp;lt;&amp;lt;- opcode: QUERY, status: NOERROR, id: 20867
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;cardtracker.com.au.        IN  ANY

;; ANSWER SECTION:
cardtracker.com.au. 599 IN  A   45.76.112.118
cardtracker.com.au. 3599    IN  NS  ns69.domaincontrol.com.
cardtracker.com.au. 3599    IN  NS  ns70.domaincontrol.com.
cardtracker.com.au. 3599    IN  SOA ns69.domaincontrol.com. dns.jomax.net. 2019050807 28800 7200 604800 600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to update the WEB_HOST environment variable with your new host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku config:set card-tracker WEB_HOST=cardtracker.com.au
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Redirect www to root
&lt;/h2&gt;

&lt;p&gt;When someone hits &lt;a href="http://www.cardtracker.com.au" rel="noopener noreferrer"&gt;www.cardtracker.com.au&lt;/a&gt; we want the response to be a 301 redirect to cardtracker.com.au. We need a server to be able to give this response - luckily Dokku has a &lt;a href="https://github.com/dokku/dokku-redirect" rel="noopener noreferrer"&gt;plugin&lt;/a&gt; to manage this for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku plugin:install https://github.com/dokku/dokku-redirect.git
dokku redirect:set card-tracker www.cardtracker.com.au cardtracker.com.au
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SSL
&lt;/h2&gt;

&lt;p&gt;SSL is the norm these days. Dokku makes it easy with the &lt;a href="https://github.com/dokku/dokku-letsencrypt" rel="noopener noreferrer"&gt;dokku-letsencrypt plugin&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku config:set --no-restart card-tracker DOKKU_LETSENCRYPT_EMAIL=your_email@mail.com

# Free SSL for 90 days
dokku letsencrypt:enable card-tracker

# Add a monthly CRON job to refresh your free SSL certificate each month
dokku letsencrypt:cron-job --add

# View your SSL status
dokku letsencrypt:ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to view your site with https. Make sure you check in Chrome incognito - mine wasn't working on my normal Chrome, probably due to some caching issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the database
&lt;/h2&gt;

&lt;p&gt;You can use any database tool to connect to your remote database. I use &lt;a href="https://tableplus.com/" rel="noopener noreferrer"&gt;Table Plus&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku postgres:expose db
dokku postgres:info db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output you can find these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exposed ports:       5432-&amp;gt;24321  
postgres://postgres:xxxxxxxxxxxxxxxx@dokku-postgres-db:5432/db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is in the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgres://USERNAME:PASSWORD@dokku-postgres-db:5432/DATABASE_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So overall we have the information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP Address: the IP address of your server&lt;/li&gt;
&lt;li&gt;Port: 24321&lt;/li&gt;
&lt;li&gt;Username: postgres&lt;/li&gt;
&lt;li&gt;PW: xxxxxxxxxxxxxxxx&lt;/li&gt;
&lt;li&gt;Database name: db&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just plug that into your database app and you're away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backing up the database to S3
&lt;/h2&gt;

&lt;p&gt;Sign up to Amazon.&lt;br&gt;
Create a bucket "card-tracker-backups" - no public access.&lt;br&gt;
Go to IAM and create a new user with programmatic access and full access to S3.&lt;br&gt;
Grab the access key and secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku postgres:backup-auth db AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test backing up the &lt;code&gt;db&lt;/code&gt; service to the &lt;code&gt;BUCKET_NAME&lt;/code&gt; bucket on AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku postgres:backup db BUCKET_NAME

=&amp;gt; 2021-05-06-00-59-06: The backup for xxx finished successfully.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schedule a backup. CRON_SCHEDULE is a crontab expression, eg. "0 3 * * *" for each day at 3am&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokku postgres:backup-schedule db "0 3 * * *" BUCKET_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File uploads
&lt;/h2&gt;

&lt;p&gt;I found that if you allow file upload then you need to increase the file upload max limit in the nginx configuration. You can do it by sshing into the server and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'client_max_body_size 50m;' &amp;gt; /home/dokku/&amp;lt;APP NAME&amp;gt;/nginx.conf.d/upload.conf

dokku ps:restart &amp;lt;APP NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'client_max_body_size 50m;' &amp;gt; /home/dokku/card-tracker/nginx.conf.d/upload.conf

dokku ps:restart card-tracker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Note: do the following at your own risk. I recommend researching security yourself instead of trusting this. &lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/akcryptoguy/vps-harden" rel="noopener noreferrer"&gt;VPS Harden&lt;/a&gt;, which will make your server much harder to crack for hackers.  &lt;/p&gt;

&lt;p&gt;I ran the install command on the remote server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo git clone https://github.com/akcryptoguy/vps-harden.git &amp;amp;&amp;amp; cd vps-harden &amp;amp;&amp;amp; sudo bash get-hard.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When asked I created a non-root user and disabled password login and root access. I kept the SSH port on 22 though as I was worried it might interfere with pushing code to dokku.&lt;/p&gt;

&lt;p&gt;Afterwards I changed to my new login &lt;code&gt;su - newuser&lt;/code&gt;.&lt;br&gt;
Then I added my ssh public key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir ~/.ssh &amp;amp;&amp;amp; touch ~/.ssh/authorized_keys
sudo chmod 700 ~/.ssh &amp;amp;&amp;amp; chmod 600 ~/.ssh/authorized_keys
sudo vim ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get your ssh key with &lt;code&gt;cat ~/.ssh/id_rsa.pub&lt;/code&gt; locally.&lt;/p&gt;

&lt;p&gt;Then you run this to restart ssh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep this tab open and now try and ssh in from your local computer. &lt;code&gt;ssh newuser@ipaddress&lt;/code&gt;. If this fails, keep troubleshooting until you sure you can login... since if you close the other open tab you've lost access to the server forever thanks to you disabling password login.&lt;/p&gt;

&lt;p&gt;Once you can ssh into your newuser then you can just swap back to the root user with &lt;code&gt;su -&lt;/code&gt; and run dokku commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server monitoring
&lt;/h2&gt;

&lt;p&gt;If you want to monitor your servers with netadata: &lt;a href="https://www.vultr.com/docs/installing-netdata-on-linux-multiple-distros" rel="noopener noreferrer"&gt;https://www.vultr.com/docs/installing-netdata-on-linux-multiple-distros&lt;/a&gt;&lt;/p&gt;

</description>
      <category>phoenix</category>
      <category>elixir</category>
      <category>dokku</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
