While churning through the exercises in Programming Elixir (affiliate link), I came across a section dedicated to deploying Elixir applications using the Elixir Release Manager (exrm).

Browsing through the Elixir Release Manager project, I noticed that it is being replaced by Distillery:

I would highly recommend using [Distillery] moving forward, as most of my efforts will be put towards that project from now on.

Rather than learning how to use a deprecated tool, I decided it might be a better investment of my time to learn how to deploy Elixir applications using Distillery.

Below is a guide for doing a basic release with Distillery. For the most part, the instructions are very similar to doing a release with exrm, with a few minor differences.

Creating Our Application

Before we start, we’ll need an Elixir project we want to deploy. To keep things simple, we’ll use a bare-bones Phoenix application. We can create our application (called HelloDistillery) with the phoenix.new Mix task:

mix phoenix.new --no-ecto hello_distillery

Once we’ve got our application set up and tested locally (mix phoenix.server), we can start the Distillery deployment process.

Installing Distillery

The first step of deploying an Elixir project with Distillery is to add Distillery as a dependency. In our mix.exs file, add a dependency on :distillery version 1.0:

{:distillery, "~> 1.0"}

Now tell Mix to pull down the new dependency:

mix deps.get

Once installed, Distillery creates a new release Mix task. If we try to run it, we’ll be told that we need to do some initial configuration:

mix release
==> You are missing a release config file. Run the release.init task first

Following that advice, we can generate our initial config file with the release.init Mix task:

mix release.init

Review the newly generated rel/config.exs file. For our purposes, the defaults should be fine.

Configuring Our Release

The last step before we build our first release is to do some final configuration on the environment we’ll be deploying.

In our case, we’ll be deploying the prod environment. If we look in our config/prod.exs file, we’ll see a comment block addressing releases:

# ## Using releases
# If you are doing OTP releases, you need to instruct Phoenix
# to start the server for all endpoints:
# config :phoenix, :serve_endpoints, true
# Alternatively, you can configure exactly which server to
# start per endpoint:
#     config :hello_distillery, HelloDistillery.Endpoint, server: true

Following this advice and the advice in the Distillery Phoenix Walkthrough, we’ll add a few configuration options to our HelloDistillery endpoint, and update its url:

config :hello_distillery, HelloDistillery.Endpoint,
  url: [ ... ],
  server: true,
  root: ".",
  version: Mix.Project.config[:version]

Once we’ve made those configuration changes, we’re ready to build and deploy our release!

Building Our Release

Building our release with Distillery is an easy process.

If we’re deploying a Phoenix application, we’ll need to be sure that we’ve bundled our front-end assets. We can do that with the following command:

brunch build --production

Next, we’ll run a series of Mix tasks. First, we’ll compile our project. Next, we’ll compress and digest all of our static files. Finally, we’ll build our prod release:

MIX_ENV=prod mix do compile, phoenix.digest, release --env=prod

The mix release task builds our release and places it in the _build folder. To make sure everything went well, we can run the release locally using the following command:

PORT=8080 ./_build/prod/rel/hello_distillery/bin/hello_distillery foreground

If the release was successful, we should see our application’s server logs in the console, and we should be able to access your application at http://localhost:8080.

Deploying Our Release

At this point, I’ll assume that you’ve already provisioned the machine you’ll be using for your production environment.

As a side note, I decided to deploy my application to an Amazon EC2 instance running 64 bit Amazon Linux.

Because we’re using the default configuration value of include_erts: false, we’ll need to be sure that Erlang is installed on the machine we’ll be deploying our release to.

Following these instructions, I was able to easily build Erlang from source and install it on my production machine. You may also have luck with a pre-compiled Erlang package.

Be sure to use the same version of Erlang on your production machine as the machine you built your release on. If you do not, you may encounter obtuse errors when trying to run your release.

Once our machine is provisioned and Erlang is installed, we’ll copy our release tarball from our development machine up to our production machine:

scp -i ~/hello_distillery.pem \ 
       _build/prod/rel/hello_distillery/releases/0.0.1/hello_distillery.tar.gz \

Be sure to tweak this command to suite your needs. I’m authenticating with a pem file stored in my home directory, and deploying to the home directory of the default ec2-user of my Amazon EC2 instance.

Once our release tarball is pushed up to our production server, we’ll need to extract it and run the release.

On the production server, extract the newly uploaded tarball:

tar -xzf ~/hello_distillery.tar.gz

Now is the moment of truth. Run the release binary using the foreground option:

PORT=8080 ./bin/hello_distillery foreground

If everything went well, we should see our application’s server logs in the console. Additionally, we should be able to access our application at our production machine’s host on port 8080 (granted you’ve properly opened that port).

Now that we know everything works, kill the server process. This time we’ll run the hello_distillery application as a daemon:

PORT=8080 ./bin/hello_distillery start

Once we’ve started the application, we can ensure that it’s running with a ping:

./bin/hello_distillery ping
> pong

And with that, we’ve deployed a basic Phoenix application using Distillery!

Final Thoughts

This was a simple run-through of a happy-path first deployment using Distillery.

I highly recommend you check out Distillery’s documentation, especially the Walkthrough and Phoenix Walkthrough sections. They go into much more detail about the various aspects of deploying with Distillery.

Overall, the process of deploying an application with Distillery was very similar to the Elixir Release Manager process described in Programming Elixir.

If you’d like to see Distillery in action, check out this short webm of entire entire deployment process: