Deploying an Elixir/Phoenix App to Heroku
December 18, 2019 ยท View on GitHub

Why?
You want to deploy your Web Application with Database to Heroku as fast as possible while still understanding all the steps!
What?
A step-by-step guide to deploying a (Phoenix) Web App on Heroku.
We created this walkthrough/tutorial while deploying our
"beginner phoenix example":
https://github.com/dwyl/phoenix-chat-example
So we know it works! Try it: https://phxchat.herokuapp.com
Note: most of this is applicable to any App (Node.js, Python, Ruby, etc.)
Even if you are deploying a totally different Language/Framework, it's still worth "skimming".
Who?
Anyone who wants a quick, easy and "free" way to deploy a demo app!
How?
First, let's do the setup on Heroku:
1. Create a New App
Once you have logged into your Heroku account and are viewing your "dashboard": https://dashboard.heroku.com
1.1 Click on the New button, then
1.2 Click on Create new app:

2. Give Your New App a Name
Input your desired name
(if it's available; otherwise get creative!):
In this case we are creating an App called phxchat.
(short for Phoenix Chat,
because obviously phoenixchat is "taken"...)
Leave the rest of the options to the "default" options (unless you have specific needs).
Note: don't worry about the "Add to pipeline" option for now, we will come back to it later.
Click on the Create app button.
You will be directed to the "Deploy" tab for your app:

3. Create "Deployment Pipeline"
On the "Deploy" tab of your app, scroll down till you see the "Deployment Method" section:

- Click on "GitHub"
- Select the "Owner" of the App you want to deploy (usually your own GitHub username)
- Type (or copy-paste) the name of your App.
- Click
Searchto find the repo. - Click "Connect" button.
You should see:

4. Add the PostgreSQL Database "Add-on"
Given that our Phoenix App uses a Postgres database to store it's data, let's add it as an "Add-on".
Scroll to the top of the dashboard and click on the "Resources" tab:

On the "Resources" page, scroll down till you See "Add-ons"

- Type: "post" (in the add-on search input box)
- Select "Heroku Postgres" from the list.
This will open a "Modal" for you to confirm:

Leave the default "Hobby Dev - Free" and click the "Provision" button.
You should now see (something similar to) the following:

5. Create a elixir_buildpack.config File
In the root directory of the App you are trying to deploy,
create a file called elixir_buildpack.config
Paste the following lines into the file:
# Latest version of Erlang/OTP see: https://git.io/Je5k6
erlang_version=22.2
# Latest Elixir Version see: https://github.com/elixir-lang/elixir/releases
elixir_version=1.9.4
# Always rebuild from scratch on every deploy?
always_rebuild=false
# Set the path the app is run from
runtime_path=/app
This file overrides the default options defined
by adding the buildpack in Step 9 (below).
For more detail on the configuration options
for your elixir_buildpack.config file
see:
https://github.com/HashNuke/heroku-buildpack-elixir#configuration
6. Create a Procfile File
Also in the root directory of your App,
create a file called Procfile
Paste this line in the file:
web: MIX_ENV=prod mix ecto.migrate && mix phx.server
That will ensure that your database tables/schema is up-to-date before trying to launch the app.
7. Update Your prod.exs File
This section "borrows liberally" from: https://hexdocs.pm/phoenix/heroku.html#making-our-project-ready-for-heroku
7.1 Configure the Endpoint Section
The default looks something like this:
config :chat, ChatWeb.Endpoint,
load_from_system_env: true,
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
Update the following params: url, force_ssl and secret_key_base:
config :chat, ChatWeb.Endpoint,
load_from_system_env: true,
url: [scheme: "https", host: "phxchat.herokuapp.com", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
cache_static_manifest: "priv/static/cache_manifest.json",
secret_key_base: Map.fetch!(System.get_env(), "SECRET_KEY_BASE")
Where:
- The first line remains the same (dependent on the name of your app)
- The
urlshould be your heroku app name (in our casephxchat)
7.2 Create a Repo Section
By default prod.exs does not have a Repo section,
so we need to create one. Here's a "template"
# Configure your database
config :hello, Hello.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true
The one for our "chat" application is:
# Configure your database
config :chat, Chat.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true
All that changes is the first line which is the name of your app.
7.3 Comment out Last Line in prod.exs
Given that we are storing our "secrets" as Environment Variables on Heroku.
We can safely comment out the line in prod.exs:
import_config "prod.secret.exs"
becomes:
# import_config "prod.secret.exs"
8. Generate the SECRET_KEY_BASE String
The SECRET_KEY_BASE is the key that your app will use to
digitally sign request tokens. It's vital to keep it a secret
to avoid "compromising" your app.
Therefore we will store it in an Environment Variable on Heroku.
8.1 Run the mix phx.gen.secret Command
On your localhost (terminal), run the following command:
mix phx.gen.secret
That will output a 64 character String such as:
khaO4IJvSa+AFJHGFzlsgVlOuNNLgrUg9D4PCD943tKqersy3YNtABh/zmqd/v7y
Copy that string to your clipboard. (we will use it in the next step)
8.2 Define the SECRET_KEY_BASE Environment Variable on Heroku
Note: if you are
newto Environment Variables, we recommend you read our "complete beginner" tutorial: github.com/dwyl/learn-environment-variables
Open the "Settings" Tab of your App's Heroku Dashboard:

Now scroll down to the "Config Variables" and click on the "Reveal Config Vars" button:

This will display your existing variable DATABASE_URL
and allow the creation of new Environment Variables.

- Set the "key" for the variable:
SECRET_KEY_BASE - Paste the value generated in step 8.1 (above)
- Click the "Add" button
9. Add the Elixir "Buildpack"
Still in the "Settings" Tab of the Heroku Dashboard for the App, Scroll down to the "Buildpacks" section:

Click on the "Add buildpack" button.
A "Buildpack" tells Heroku how to run your app. In the case of an elixir app it defines how to get the dependencies and what the app expects/requires.
For more detail, see: https://devcenter.heroku.com/articles/buildpacks
When the "Modal" opens:

- Paste the value: https://github.com/HashNuke/heroku-buildpack-elixir.git into the field.
- Click on "Save change" button
You should now see the following:

9.1 Repeat
In order to compile any "static assets" (JS/etc.) we need to add a second buildpack: https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
Repeat the process you just went through but this time
add the heroku-buildpack-phoenix-static buildpack.
Great! Now onto the final step!
10. (Manually) Deploy
Don't worry, you only have to do this once.
All subsequent deploys are automatic!
Back on the "Deploy" tap of your App's Dashboard, Scroll down to the "Manual deploy" section:

Click on the "Deploy Branch" button.
This will start the build process. Heroku will show you the "build log":

Once the build is complete,
click on the "Open App" button in the top-right of your Heroku dashboard:

You should see your app running in the browser!
In our case the app is: https://phxchat.herokuapp.com

done()
Why Not use the "Official" Deployment Guide?
We are aware of (and have read) the
"Deploying on Heroku" guide:
https://hexdocs.pm/phoenix/heroku.html
It's a good guide for people with "intermediate" Heroku skills,
however it's longer (more steps) than this tutorial,
uses the Heroku "Toolbelt" (Command Line Interface "CLI"),
which most "beginners" don't have installed
and does not setup a "deployment pipeline" so it's a "manual" job
(running the deploy command each time).
With that said, it is a good reference, so if you are stuck, that is a good place to look for "trouble-shooting".
References & Background Reading
- "Official" Heroku Deployment guide: https://hexdocs.pm/phoenix/heroku.html
- Basic deployment: https://medium.com/@yasserhussain1110/how-to-deploy-phoenix-app-to-heroku-95d4bef32322 also uses Heroku CLI and doesn't setup a deployment pipeline. But good section on
config/prod.exschanges. - Migrating a Phoenix App on Heroku: https://blog.learnphoenix.io/strategies-for-migrating-a-phoenix-app-on-heroku-ed0ea3aee4e5 confirmed that
mix ecto.migrateworks inProcfile. (Thanks @SamCorcos)