Deploy a Phoenix App with Mix Releases
Tags: elixir, erlang
Published: 2019-07-22 04:12:19

This is a guide to deploying a [Phoenix](https://phoenixframework.org) application with [Mix releases](https://hexdocs.pm/mix/Mix.Tasks.Release.html) on [Render](https://render.com), a new cloud platform with native support for Elixir.

The finished code for this example is [available on GitHub](https://github.com/render-examples/phoenix_hello).

## Getting Started
Create a new Phoenix app in the terminal. We don't need a database for this example, so we're passing the `--no-ecto` flag to `mix`.
   ```bash
   # install phx.new; feel free to change 1.4.9 to a different version
   $ mix archive.install hex phx_new 1.4.9
   $ mix phx.new phoenix_hello --no-ecto # also fetch and install dependencies
   $ cd phoenix_hello
   ```

## Configure Mix Releases

Create [runtime configuration](https://hexdocs.pm/phoenix/releases.html#runtime-configuration) needed for Mix releases.

   1. Rename `config/prod.secret.exs` to `config/releases.exs`.
   2. Change `use Mix.Config` in your new `config/releases.exs` file to `import Config`.
   3. Uncomment the following line in `config/releases.exs`:
   ```elixir
   config :phoenix_hello, PhoenixHelloWeb.Endpoint, server: true # uncomment me!
   ```
   4. Finally, update `config/prod.exs` to delete the line `import_config "prod.secret.exs"` at the bottom.

## Create a Build Script

We need to run a series of commands to build our app on every push to our Git repo, and we can accomplish this with a build script. Create a script called `build.sh` at the root of your repo:
   ```bash
   #!/usr/bin/env bash
   # Initial setup
   mix deps.get --only prod
   MIX_ENV=prod mix compile

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

   # Remove the existing release directory and build the release
   rm -rf "_build"
   MIX_ENV=prod mix release
   ```

   Make sure the script is executable before checking it into Git:
   ```bash
   $ chmod a+x build.sh
   ```

## Update Your App for Render

Update `config/prod.exs` to change the lines below.
   ```elixir{2}
   config :phoenix_hello, PhoenixHelloWeb.Endpoint,
     url: [host: "example.com", port: 80],
     cache_static_manifest: "priv/static/cache_manifest.json"
   ```
   to this:
   ```elixir{2}
   config :phoenix_hello, PhoenixHelloWeb.Endpoint,
     url: [host: System.get_env("RENDER_EXTERNAL_HOSTNAME") || "localhost", port: 80],
     cache_static_manifest: "priv/static/cache_manifest.json",
   ```
   Render populates `RENDER_EXTERNAL_HOSTNAME` for `config/prod.exs`.

   <warning-block>If you add a custom domain to your Render app, don't forget to change the host to your new domain.</warning-block>

## Build and Test Your Release Locally

Compile your release locally by running `./build.sh`. The output should look like this:
   ```bash
   * assembling phoenix_hello-0.1.0 on MIX_ENV=prod
   * using config/releases.exs to configure the release at runtime
   * skipping elixir.bat for windows (bin/elixir.bat not found in the Elixir installation)
   * skipping iex.bat for windows (bin/iex.bat not found in the Elixir installation)

   Release created at _build/prod/rel/phoenix_hello!

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

   Once the release is running:

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

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

   To list all commands:

       _build/prod/rel/phoenix_hello/bin/phoenix_hello
   ```

Test your release by running the following command and navigating to http://localhost:4000.
```bash
SECRET_KEY_BASE=`mix phx.gen.secret` _build/prod/rel/phoenix_hello/bin/phoenix_hello start
```

If everything looks good, push your changes to your repo. You can now deploy your app in production! 🎉

## Deploy to Render

1. Create a new **Web Service** on Render, and give Render permission to access your Phoenix repo.

2. Use the following values during creation:

     Field     | Value     
    ---------- | --------- 
    **Environment** | `Elixir` 
    **Build Command** | `./build.sh`
    **Start Command** | `_build/prod/rel/phoenix_hello/bin/phoenix_hello start`

    Under the **Advanced** section, add the following environment variables:

        Key            | Value           
    ------------------ | --------------- 
    `SECRET_KEY_BASE`  | A sufficiently strong secret. Generate it locally by running `mix phx.gen.secret`

That's it! Your Phoenix web service built with Mix releases will be live on your Render URL as soon as the build finishes. Going forward, every push to your GitHub repo will automatically update and deploy your app with zero downtime. 💯