How to deploy Phoenix app to heroku

Yasser Hussain
6 min readApr 23, 2017

--

Your production code. Credits to https://wall.alphacoders.com

Sometime back I published a post detailing how to deploy a Phoenix app to heroku. But at that time I had no experience with PostgreSQL database and so that post only talked about apps which do not use a database.

In this post I will discuss how to deploy a Phoenix app with a database to heroku.

Prerequisites

Setup your heroku account here.

Install elixir. See here.

Install heroku toolbelt. See here.

Install PostgreSQL. See here.

Postgres GUI client. You can use pgadmin on Ubuntu and postico on Mac.

Step 1 (Create a new phoenix app)

Create a phoenix app. Run command —

$ mix phoenix.new elixir-test-app --app elixir_test_app

Notes:-

  • “elixir_test_app” is the name of the app. “elixir-test-app” is the name of the directory. You can chose any other name here.

Press “y” if prompted for installing dependencies.

Then cd into the directory —

$ cd elixir-test-app

STEP 2 (Commit your app)

We will use git to commit our app. Run the following commands in sequence.

$ git init
$ git add --all
$ git commit -m "First Commit"

STEP 3 (Set up local database configurations)

Open the file ./config/dev.exs and set up your username and password.

Note:- I am not adding details about what exactly should be the username and password, because it is dependant on what system you are using (Mac/Windows/*nix) and detailing it out for each system could take a whole different post.

STEP 4 (Commit your config changes)

Run following command —

$ git commit -am "updated db creds"

STEP 5 (Create you database)

Run following command —

$ mix ecto.create

You might see a bunch of output at the end of which you should see,

The database for ElixirTestApp.Repo has been created

STEP 6 (Create a migration)

We will create a migration just to make sure that we are able to manipulate our database. To do this run —

$ mix ecto.gen.migration add_test

You should an output something like this —

* creating priv/repo/migrations
* creating priv/repo/migrations/20170423200957_add_test.exs

A new migration file has been created for you, where you can specify what table you want created.

Note-

  • The name of the migration file also contains the date when it was generated. In my case it is —20170423200957_add_test.exs” . Your migration file will most likely have a different name.

STEP 7 (Create a test table)

Open file priv/repo/migrations/...._add_test.exs . Modify change function like so —

def change do
create table(:test) do
add :title, :string

timestamps()
end
end

For more info on how to do this. See my commit here.

If we run this migration now we will end up with a table named test. And it will have a field named title whose type will be string.

To run this migration, run following command —

$ mix ecto.migrate

You will see a bunch of output at the end of which you should be seeing something like this —

... Migrated in 0.0s

Verify that the table was created using a Postgres GUI client.

STEP 8 (Commit migration)

Run command —

$ git commit -am "Added migration"

STEP 9 (Create a new heroku app)

We will use heroku toolbelt for this step. Run command —

$ heroku create my-elixir-test-app

Notes:-

  • Heroku app names are unique. So you should replace the app name above “my-elixir-test-app” with a name of your choice, or heroku will complain that the name has already been taken.
  • If this is the first time you are creating a heroku app. You may be asked to sign in. Just enter your heroku credentials.

STEP 10 (Add production configs to your app)

In this step we are going to create a new file Procfile and modify two existing files -

  • config/prod.exs
  • web/channels/user_socket.ex

Notes:-

  • For detailed info about how to do this, check this out.
  • If you want to see the exact changes required to achieve this, see my commit.

Create a Procfile with the following contents.

web: MIX_ENV=prod mix phoenix.server

One of the ways for creating such a file is to run this command

$ echo "web: MIX_ENV=prod mix phoenix.server" > Procfile

Procfile contains the command heroku will run to start up your app. For more info see heroku docs.

Now as I said above we need to modify the following two files

  • config/prod.exs
  • web/channels/user_socket.ex

In config/prod.exs -

  1. Replace line -

cache_static_manifest: "priv/static/manifest.json"

with

cache_static_manifest: "priv/static/manifest.json",
secret_key_base: System.get_env("SECRET_KEY_BASE")

Here we’re saying that we want the secret_key_base value to be taken from the environment variable SECRET_KEY_BASE.

2. Add database configuration

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

3. Replace line -

url: [host: "example.com", port: 80],

with

url: [scheme: "https", host: "my-elixir-test-app.herokuapp.com", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],

Note :- Replace the highlighted “my-elixir-test-app.herokuapp.com” with your full heroku app url.

Here we are simply setting up the https protocol.

3. Comment out line -

import_config “prod.secret.exs”

like so -

# import_config "prod.secret.exs"

The app secret will be taken from the environment variable so no need to load it from another file.

In web/channels/user_socket.ex,

Replace line -

transport :websocket, Phoenix.Transports.WebSocket

with

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

Here we are limiting the idle time of our app.

STEP 11 (Commit your production config changes)

Run following command —

$ git commit -am "Added heroku deploy configs"

STEP 12 (Add buildpacks)

Buildpacks are a way of telling heroku what framework and language we are using in the app, so that heroku can compile/build our apps properly.

Run the following commands.

$ heroku buildpacks:add https://github.com/HashNuke/heroku-buildpack-elixir.git$ heroku buildpacks:add  https://github.com/gjaldon/heroku-buildpack-phoenix-static.git

STEP 13 (Setup heroku database)

Create heroku PostgreSQL addon. Run following commands —

heroku addons:create heroku-postgresql:hobby-dev
heroku config:set POOL_SIZE=18

According to heroku docs,

This value should be just under the number of available connections, leaving a couple open for migrations and mix tasks. The hobby-dev database allows 20 connections, so we set this number to 18.

STEP 14 (Set up app secret)

Create an app secret. Run

$ mix phoenix.gen.secret

You might see a bunch of output. If you do, that’s because mix is building your project.

We are interested in the last line of output. You will see a long string something like this -

aoE/12HHjsaduayasdlkkalsduweo732892j+asdSASuaios

It is a random and unique string and we will set it up as our app’s secret.

Like so -

$ heroku config:set SECRET_KEY_BASE="aoE/12HHjsaduayasdlkkalsduweo732892j+asdSASuaios"

Note:- Please use the string generated in your machine instead of “aoE/12HHjsaduayasdlkkalsduweo732892j+asdSASuaios”

STEP 15 (Push your code to heroku)

Push your code to heroku by running —

$ git push -u heroku master

As soon as you push your code to heroku, heroku automatically starts building and deploying the project.

If successful you will see a message like this

remote: -----> Launching...
remote: Released v4
remote: https://my-elixir-test-app.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/my-elixir-test-app.git

Instead of the highlighted url, you will see url relating to your app.

STEP 16 (Last Step, run your migration in heroku)

Run this command —

$ heroku run "POOL_SIZE=2 mix ecto.migrate"

You should see an output similar to this.

Running POOL_SIZE=2 mix ecto.migrate on ⬢ my-elixir-test-app... up, run.7644 (Free)20:35:29.535 [info]  == Running ElixirTestApp.Repo.Migrations.AddTest.change/0 forward20:35:29.535 [info]  create table test20:35:29.545 [info]  == Migrated in 0.0s

Once you see that head over to your app url and see if it is deployed.

You should be seeing something like this.

If you don’t see that. Please a leave a comment below so I might try to help you.

Thanks.

--

--