Deploy Your Elixir Phoenix Project with a Release

We’re going to learn how to deploy a Phoenix project using an Elixir release (available in Elixir 1.9+). Elixir Releases allow us to package our Elixir application to run in production. A release packages your Phoenix application into a self-contained directory that includes the Erlang VM, Elixir, all of your code and dependencies. This package can then be dropped into a production machine.

We’ll go through the steps to build a Phoenix project with a Postgres database using Elixir releases.

Overview

Here are the steps we’ll cover to deploy the project:

  1. Create new Elixir Phoenix project
  2. Add users resource with Phoenix generator
  3. Configure your Elixir release
  4. Deploy your Elixir Release Locally

Prerequisites

To follow this guide, make sure you have at least the following applications installed on your machine. In the brackets are the versions with which this guide was written.

  • Elixir (1.11.4-otp-24)
  • Erlang (OTP 24)
  • Phoenix (1.5.12)
  • Node.js with npm (11.6.0)
  • Docker (20.10.7)

Make sure to install at least Elixir 1.9. I like to use asdf to manage my Erlang and Elixir versions.

If you run into problems, the finished project is available on GitHub as StakNine Elixir Release. Each section is a separate commit.

Create new Elixir Phoenix project

To begin, I’m going to call this project DockerPhx because we are going to use Docker later, so use the command line to create a new Phoenix project:

$ mix phx.new docker_phx

## output ##

Fetch and install dependencies? [Yn] y
* running mix deps.get
* running cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development
* running mix deps.compile

We are almost there! The following steps are missing:

    $ cd docker_phx

Then configure your database in config/dev.exs and run:

    $ mix ecto.create

Start your Phoenix app with:

    $ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phx.server

Change into the docker_phx directory, create your database and test your app:

$ cd docker_phx

docker_phx $ mix ecto.create
Compiling 13 files (.ex)
Generated docker_phx app
The database for DockerPhx.Repo has been created

docker_phx $ mix phx.server
[info] Running DockerPhxWeb.Endpoint with cowboy 2.7.0 at 0.0.0.0:4000 (http)
[info] Access DockerPhxWeb.Endpoint at http://localhost:4000

Now visit http://localhost:4000 and you should see the Welcome to Phoenix! page.

Elixir Release Deployed

Add users resource with Phoenix generator

Now we want to add users to the project with the phx.gen html task, following the Phoenix Contexts guide.

docker_phx $ mix phx.gen.html Accounts User users name:string \
username:string:unique

* creating files...

Add the resource to your browser scope in lib/docker_phx_web/router.ex:

    resources "/users", UserController

Remember to update your repository by running migrations:

    $ mix ecto.migrate

Follow the directions to add the resource to the lib/docker_phx_web/router.ex file and migrate the database with mix ecto.migrate.

Now start your server with mix phx.serverand visit http://localhost:4000/users on your local machine to see the index of users. Add a new user to test out the database.

deploy elixir with docker success

We’ll use this basic project to test our database is migrated and our app is deployed properly.

Configure your Elixir release

A release consists of your application code, all of its dependencies, plus the whole Erlang Virtual Machine and runtime. Once a release is assembled, it can be packaged and deployed to a target as long as the target runs on the same operating system distribution and version as the machine that assembled the release.

A release does not require the source code to be included in your production artifacts. All of the code is precompiled and packaged.

To build, configure and start your release, we’re going to borrow the steps from the Phoenix Deploying with Releases guide to set up Mix releases.

Releases, assemble!

First set the following environment variables:

docker_phx $ mix phx.gen.secret
REALLY_LONG_SECRET
docker_phx $ export SECRET_KEY_BASE=REALLY_LONG_SECRET
docker_phx $ export DATABASE_URL=postgres://postgres:postgres@localhost:5432/docker_phx_dev

Then load dependencies to compile code and assets:

# Initial setup
$ mix deps.get --only prod
$ MIX_ENV=prod mix compile

# Compile assets
$ npm run deploy --prefix ./assets
$ mix phx.digest

Update the config file config/prod.secret.exs with the following (you may just need to uncomment a line):

config :docker_phx, DockerPhx.Endpoint, server: true

Runtime configuration

Update the project to use runtime configuration for environment variables with the steps below. With runtime configuration, you are able to store environment variables in an external configuration system in an actual production setup.

  1. Rename config/prod.secret.exs environment file to config/releases.exs
  2. Change use Mix.Config inside the new config/releases.exs file to import Config.
  3. Change config/prod.exs to no longer call import_config "prod.secret.exs" at the bottom.

Ecto migrations and custom commands

Create a new release commands file in your application, lib/docker_phx/release.ex, with the following:

defmodule DockerPhx.Release do
  @app :docker_phx

  def migrate do
    for repo <- repos() do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
    end
  end

  def rollback(repo, version) do
    {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
  end

  defp repos do
    Application.load(@app)
    Application.fetch_env!(@app, :ecto_repos)
  end
end

If you are using the file as a template, you only need to change the first two lines.

Deploy Your Elixir Release Locally

Once you’ve completed those sections, you should be able to test your app with the following commands to start building releases.

Drop the existing database and create a new database, so you can test the release command.

docker_phx $ mix ecto.drop
The database for DockerPhx.Repo has been dropped

docker_phx $ mix ecto.create
The database for DockerPhx.Repo has been created

Then run the mix command to build the release with the MIX_ENV=prod mix release build script.

docker_phx $ MIX_ENV=prod mix release
Compiling 18 files (.ex)
Generated docker_phx app
* assembling docker_phx-0.1.0 on MIX_ENV=prod
* using config/releases.exs to configure the release at runtime

Release created at _build/prod/rel/docker_phx!

    # To start your system
    _build/prod/rel/docker_phx/bin/docker_phx start

Once the release is running:

    # To connect to it remotely
    _build/prod/rel/docker_phx/bin/docker_phx remote

    # To stop it gracefully (you may also send SIGINT/SIGTERM)
    _build/prod/rel/docker_phx/bin/docker_phx stop

To list all commands:

    _build/prod/rel/docker_phx/bin/docker_phx

Migrate your database

docker_phx $ _build/prod/rel/docker_phx/bin/docker_phx eval "DockerPhx.Release.migrate"
19:13:05.601 [info] == Running 20200229181048 DockerPhx.Repo.Migrations.CreateUsers.change/0 forward
19:13:05.604 [info] create table users
19:13:05.676 [info] create index users_username_index
19:13:05.699 [info] == Migrated 20200229181048 in 0.0s

Start your application.

docker_phx $ _build/prod/rel/docker_phx/bin/docker_phx start
19:15:07.911 [info] Running DockerPhxWeb.Endpoint with cowboy 2.7.0 at :::4000 (http)
19:15:07.913 [info] Access DockerPhxWeb.Endpoint at http://example.com

Now you should be able to visit http://localhost:4000/users on your local machine to see the index of users. You can add a user again to test out the site is working properly.

List Users in Phoenix

Conclusion

Congratulations! You’ve learned how to build an Elixir releases to package your Phoenix application to include the Erlang VM, Elixir, all of your code and dependencies. You can use the release in your deployment process when deploying your Elixir apps to a production machine.

Next learn how to Use Docker to Deploy Your Elixir App Anywhere!

Want To Know How To Deploy Phoenix Apps Using A single Command?

This brand-new FREE training reveals the most powerful new way to reduce your deployment time and skyrocket your productivity… and truly see your programming career explode off the charts!