Deploying a Phoenix app to Heroku

In this episode we build a new Phoenix app, set up Heroku and deploy our app. Heroku may not be the ideal choice for an Elixir app but Elixir and Phoenix is an ideal stack to run on Heroku!

If you haven't already installed and set up Elixir on your computer, go through the setup part of lesson 1 and then you'll be ready to follow along here. These are the steps we'll go over:

  • Sign up for Heroku (here)
  • Install the Heroku Toolbelt (download here)
  • Create a new Phoenix app
  • Create a new app for it on Heroku
  • Add the Phoenix static buildpack
  • Create a free tier database on Heroku
  • Change some settings in our project
  • Make a Procfile and elixir_buildpack.config for Heroku
  • Push everything to Heroku to deploy!

Quick start

We'll call our app Hello, so here's what we need to run:

mix phx.new hello
cd hello
git init
heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git"
heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
heroku addons:create heroku-postgresql:hobby-dev

Application files to change

Heroku stores secrets in system environment variables instead of a secrets file, so we can delete prod.secrets.exs. Then, we can update prod.exs to get the secrets we need from System.get_env. While we're there we can also set the app to use SSL and update the host name to whatever Heroku named our app when we created it. Finally add the database settings to the bottom of the file:

use Mix.Config

config :hello, HelloWeb.Endpoint,
  load_from_system_env: true,
  url: [scheme: "https", host: "NAME_OF_HEROKU_APP.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")

# Do not print debug messages in production
config :logger, level: :info

# Configure your database
config :hello, Hello.Repo,
  adapter: Ecto.Adapters.Postgres,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
  ssl: true,
  url: System.get_env("DATABASE_URL")

If your app is going to use channels, then update your user_socket.ex file to add a timeout for sockets. Heroku limits them to 55 seconds, so set the time out to something like 45 seconds to be safe:

transport(:websocket, Phoenix.Transports.WebSocket, timeout: 45_000)

Application settings for Heroku

By default Phoenix uses a pool size of 10. This is very low and ideally we want to use nearly as much as is available. On Heroku we have a maximum pool of 20, so we'll set our application to use 18 and just use 2 for mix tasks. We'll also generate a secret key with Phoenix and set that in Heroku so that the app can get it from the system environment in production:

heroku config:set POOL_SIZE=18
heroku run "POOL_SIZE=2 mix hello.task"
mix phx.gen.secret
heroku config:set SECRET_KEY_BASE="<SECRET PHOENIX JUST GENERATED ABOVE>"

New files to add

In the root directory of our app, we'll add two more files for Heroku—one called Procfile that has just one line:

web: MIX_ENV=prod mix phx.server

and one called elixir_buildpack.config that holds some configuration settings:

erlang_version=20.1
elixir_version=1.7.2
always_rebuild=false
runtime_path=/app

Important: Make sure that both files have LF line endings. Heroku throws errors on CRLF!

Deploy!

git add .
git commit -m "prepares for heroku"
git push heroku master
Back to index

No Comments