Hosting Phoenix Applications on Heroku
Heroku is a natural platform to deploy Phoenix applications to. It builds your application automatically on a code push, uses Postgres as the standard data store and has a stable components ecosystem to expand the services on offer. Best of all, for low capacities, i.e. for development, its free
Heroku
First off, you will need an account on Heroku. If you don’t already have one head over to the Heroku Sign up Page, fill in the form and follow the instructions provided.
Heroku provides a suit of command line tools called Heroku CLI that allows you access to all features of your account. Installation of this tool is provided on that page.
Once you are installed, the next thing that you will need to do is create an App on Heroku.
There are two ways of doing this: via the CLI tool or the Heroku website.
For brevity we’ll use the CLI set up, so pull out your handy terminal, navigate to the directory where your nice shiny Phoenix/Elixir app is and enter this:
$ heroku apps:create
Creating app... done, ⬢ example-name-62029
https://example-name-62029.herokuapp.com/ | https://git.heroku.com/example-name-62029.git
The output of this command is the URL of the app created and the URL for the git repo that will be used for deployments.
Next thing then is to set up the git remote.
Git
I won’t go through setting up Git or provide usage instructions beyond the necessary to set this up. I am assuming that this directory is already under some form of DVCS control.
If not, then $ git init
will sort that out.
To link this to the Heroku remote issue the following (changing the git remote URL to that returned by the apps:create command)
$ git remote add heroku https://git.heroku.com/example-name-62029.git
$ git remote -v
origin <your git host URL> (fetch)
origin <your git host URL> (push)
heroku https://git.heroku.com/example-name-62029.git (fetch)
heroku https://git.heroku.com/example-name-62029.git (push)
I’m using ‘heroku’ here as the target master as I’m assuming that you’ve already got origin set.
Buildpacks
In order to have Heroku build and serve Elixir/Phoenix projects you need to add some build packs and create the relevant configurations.
Phoenix projects require two buildpacks:
$ heroku buildpacks:set https://github.com/HashNuke/heroku-buildpack-elixir
$ heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
With buildpacks set up the need a little bit of configuration. Create each of the following in root of your application directory (next to your mix.exs file).
elixir_buildpack.config
erlang_version=19.2 <-- Put the required Erlang version here
elixir_version=1.4.1 <-- Put the required Elixir version here
always_rebuild=true <-- Use this to force a rebuild the application each time
phoenix_static_buildpack.config
clean_cache=true <-- clean the phoenix cache
node_version=7.4.0 <-- an appropriate node version for your code
npm_version=4.1.2 <-- an appropriate npm version for your code
Procfile
Heroku uses the Procfile to run the application server, so you’ll need to add one of those. Add this file in the same directory as the two files above:
Procfile
web: MIX_ENV=prod mix phoenix.server
Database
The next thing that you will need to do is set up the database on Heroku. Here I’m setting up a PostgreSQL database in line with a default Phoenix application
$ heroku addons:create heroku-postgresql --app example-name-62029
Creating postgresql-deep-6913... done, (free)
Adding postgresql-deep-6913 to my-app... done
Setting DATABASE_URL and restarting my-app... done, v5
Database has been created and is available
$ heroku addons --app my-app
Add-on Plan Price
───────────────────────────────────────── ───────── ─────
heroku-postgresql (postgresql-deep-6913) hobby-dev free
└─ as DATABASE
This returns an environment variable DATABASE_URL.
When you’ve done this, you will also need to create a secret base key and pool size on Heroku
$ heroku config:set POOL_SIZE=18
$ mix phoenix.gen.secret
<created secret key>
$ heroku config:set SECRET_KEY_BASE="<created secret key>"
Update Phoenix prod configuration
You will need to update your config/prod.exs file to use the new environment variables - update the secret_key_base and the database configuration:
use Mix.Config
config :appKey, PhoenixApp.Endpoint, <-- change :appKey and PhoenixApp to your application
http: [port: {:system, "PORT"}],
url: [scheme: "http", host: "appURL"], <-- change appURL to your site URL
#force_ssl: [rewrite_on: [:x_forwarded_proto]],
cache_static_manifest: "priv/static/manifest.json",
secret_key_base: System.get_env("SECRET_KEY_BASE")
config :logger, level: :info
config :appKey, PhoenixApp.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true
Run deployment
Everything should now be in order to be able to deploy code.
$ git commit -am 'Message'
$ git push heroku master <-- or whatever your branch is called
... <-- Loads of output
remote: Verifying deploy.... done.
Run Heroku setup scripts
If this is the initial deploy, run the following tasks
$ heroku run "POOL_SIZE=2 mix run priv/repo/seeds.exs"
Running POOL_SIZE=2 mix run priv/repo/seeds.exs on ⬢ example-name-62029... up, run.4778 (Free)
$ heroku run "POOL_SIZE=2 mix phoenix.digest"
Running POOL_SIZE=2 mix phoenix.digest on ⬢ example-name-62029... up, run.3980 (Free)
Check your digested files at "priv/static"
$ heroku run "POOL_SIZE=2 mix ecto.migrate"
Running POOL_SIZE=2 mix ecto.migrate on ⬢ example-name-62029... up, run.9353 Free)
...
12:47:26.002 [info] == Migrated in 0.0s
Check the site
Navigate to the URL that was created in the apps:create command given above, in the case of this post https://example-name-62029.herokuapp.com
If all has gone well, then you should see your site running.
Until next time.