---
# System prepended metadata

title: Real World Phoenix |> Let's d4y

---

# Real World Phoenix |> Let's d4y

I believe there is a strong case to be made for shipping your app / idea as soon as possible as this pushes you to think about creating something small that is functional and finished. 

So today I want to cover a topic that has been discussed a lot in the community and there seems to be a tendency in Elixir land that they are hard. Let's discuss deployments! The fact that it is often categorised as difficult or hard seems to scare people away and confuses a lot of people. I'm here to tell you that deployments are not hard, once you know your options.

## Releases - yes you should use them!

There are basically two ways to run your elixir app in production. One is using `mix` and the other is using `releases`. I want to focus today on using releases as using a build tool to deploy and run your app seems silly... And I think demistifying all the fuss around releases will make sure we get more comfortable using them.

We'll take 3 steps in learning about deployment. First we'll package and run our release locally to test out how releases work, next we'll take one of the easiest platforms I've seen to deploy our app, [render.com](https://render.com/), and lastly we'll go the other deep end and run our app in a kubernetes cluster! 

In this post we'll cover steps 1 and 2 and I'm going to leave the kubernetes way for the next blog post as that needs some more indepth explaination. You might think that I'm nuts going the kubernetes route, but I wanted to play around with it and see if it is really that hard to grasp... tl;dr => It really isn't nowadays due to all the managed kubernetes services that handle a lot of the hard stuff behind the scenes.

## Baking and running a release locally

After all the hard work that has been done on [distillery](https://github.com/bitwalker/distillery) by Paul Schoenfelder (a.k.a. bitwalker), Elixir has embraced releases as part of core. So no more excuses not to use releases! And ofcourse Phoenix has gone along with this trend and is enabling deployment with releases out of the box.

So let's see how easy it is to get this up and running. A lot of guides out there omit the database part, but I'll add that here so we know how to enable that as well. For production we'll set a `DATABASE_URL` environment variable as that is most convenient to use when deploying. We will also set the `SECRET_KEY_BASE` as an environment variable. Locally we'll test our release in development mode, because setting a local release to production mode requires all kinds of extra settings that we really don't need to test this out. 

If you want to try this out while reading this, you can create a fresh Phoenix app and follow along:

```bash
mix archive.install hex phx_new 1.4.11
mix phx.new test_deployment
```

Now let's take this step by step:
- setup a releases.exs file

  ```bash
  mv config/prod.secret.exs config/releases.exs
  ```
- change `use Mix.Config` to `import Config` in `releases.exs`
  
  ```bash
  sed -i'' -e 's/use Mix.Config/import Config/g' config/releases.exs
  ```
- set `server: true` in `config/releases.exs`
  ```bash
  sed -i'' -e 's/^#.*config :test_deployment, TestDeploymentWeb.Endpoint, server: true/config :test_deployment, TestDeploymentWeb.Endpoint, server: true/g' config/releases.exs
  ```
- remove `import_config prod.secret.exs` from `config/prod.exs`
  ```bash
  sed -i'' -e 's/import_config "prod.secret.exs"//g' config/prod.exs
  ```
- create our database locally (so we can actually test it with a database). Note that we create the development db with this command
  ```bash
  mix ecto.create
  ```
- set environment variables
  ```bash
  export SECRET_KEY_BASE=$(mix phx.gen.secret)
  export DATABASE_URL=ecto://postgres:postgres@localhost/test_deployment_dev
  ```
- prepare our app
  ```elixir
  # fetch dependencies
  mix deps.get --only prod
  MIX_ENV=prod mix compile

  # compile assets
  npm run deploy --prefix ./assets
  mix phx.digest
  ```
- build our release
  ```elixir
  MIX_ENV=prod mix release
  ```
- run it!
  ```bash
  _build/prod/rel/test_deployment/bin/test_deployment start
  ```
  
After that visit http://localhost:4000 and see your fresh release shine!
    
## Deploying a release to render.com

Now let's see what it takes to put this live on `render.com`. If you are following along, make sure you have the repo you want to use on `gitlab` or `github` so you can pull that in easily.

Creating an account on render.com is easy and deploying and running your app is charged by the second, so you can safely follow along this turorial and shut the app down once done so you have an idea of the workflow involved in getting your app live on render.com. Note that signing up with `github` or `gitlab` gives you the extra benefit of being able to select the repo to deploy right from render, Which makes it even easier! 

So go to https://dashboard.render.com/select-repo?type=web and select the repository you want to deploy. After that fill in the neccessary details. So choose a descriptive name and set the environment to Elixir. You'll notice that the default settings to deploy here are `mix phx.digest` and `mix phx.server`.
In our case we don't want to use that, because we are using releases. To use releases in render we have to change these two settings.

We'll set the build command to: `build.sh`, which we will create in our repo shortly. The start command will be the command we used when testing the release locally. 
In our case this would be: `_build/prod/rel/test_deployment/bin/test_deployment start`. There are two more settings needed in the advanced setting. First one is the `SECRET_KEY_BASE` environment variable(you can just generate one with mix phx.gen.secret and paste that in here) and the other one is the database url. We'll need to create the database first for this.

### Setting up the database

To set up a database for our app go to https://dashboard.render.com/new/database and create a database with the settings you prefer. After creating the database
you can go into the settings page and copy the `External connection string`. This string should go into the advanced setting of your app as `DATABASE_URL` (exactly as we did when testing it locally). 

### Build script

The build script gives us all the power to customise building our app when deploying. In our case this means entering the commands that will be run to prepare our app for deployment. 

This is the content of our build.sh file. As you can see we are basically adding
the steps we used when creating the release on our local machine.

```elixir
#!/usr/bin/env elixir

# 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

# for auto DB migration upon deploy
MIX_ENV=prod mix ecto.migrate
```

After creating the `build.sh` file, make sure to make it executable:
```elixir
chmod a+x build.sh
```

### And..... deploy!

Once we have the database up and running and the environment variables setup we can proceed to deploy. And the beauty here is that once you push to master with the `build.sh` included it will automagically trigger a deploy on render.com

### Custom domain

Once you have your app deployed, you'll get a url generated by render to access your app. However it is fairly easy to add your custom domain in your app settings.

Alright, hope this was helpful and I certainly hope that this illustrates how straightforward it is to use releases to deploy Elixir / Phoenix apps. As promised in the next post I'll cover a deployment setup that is a bit more complex using kubernetes. That is actually also the setup that I've used to deploy [realworldphoenix.com](https://realworldphoenix.com/), so more good stuff is coming in 2020!

Happy New Year to all of you and may 2020 be the year that Elixir shines for us all! 

Until next time!
