You want to deploy your Web Application with Database to Heroku as fast as possible while still understanding all the steps!
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".
Anyone who wants a quick, easy and "free" way to deploy a demo app!
First, let's do the setup on Heroku:
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
:
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:
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
Search
to find the repo. - Click "Connect" button.
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:
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
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.
This section "borrows liberally" from: https://hexdocs.pm/phoenix/heroku.html#making-our-project-ready-for-heroku
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
url
should be your heroku app name (in our casephxchat
)
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.
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"
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.
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)
Note: if you are
new
to 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
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:
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!
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()
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".
- "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.exs
changes. - Migrating a Phoenix App on Heroku: https://blog.learnphoenix.io/strategies-for-migrating-a-phoenix-app-on-heroku-ed0ea3aee4e5 confirmed that
mix ecto.migrate
works inProcfile
. (Thanks @SamCorcos)