Lesson 21

Deploying Phoenix


Now that our app is ready, the final step is to deploy it to a server where everyone can access it!

It's worth noting that there are many ways of deploying a Phoenix application. Many have cool features such as "hot reloading", which – when set up correctly – gives you zero downtime when you update your app! Distillery is one such project. However, since our app is very small, and we don't have millions of users yet, we'll keep things simple and use Heroku for now!

Heroku's welcome page

Creating your Heroku app

If you haven't already, sign up for a Heroku account (don't worry, it's free) and install the Heroku CLI on your computer.

Next, go back to your project and use the Heroku CLI to create a new Heroku app. I'm going to call mine "messengyr", but you'll have to pick something else that's unique (e.g. your-name-messengyr). We're also going to use the Elixir buildpack.

We're also going to need the Phoenix static buildpack to compile all our static assets. We'll use a special version for Phoenix 1.3 until this pull request gets merged into the official repo.

Finally, we're also going to need a Postgres database for our app, so we need to install that as an addon:

Configuring your app's settings

Before we deploy our app, we need to make sure that we're using the right production settings so that they're compatible with the Heroku environment.

In our config folder, we have a file called prod.secret.exs which is supposed to contain our production database settings for example. This is obviously very secret information (anyone who has it could edit the production database data), which is why the file isn't used in Git (it's in .gitignore). This poses a bit of a problem for Heroku however, since apps are always deployed with Git. To get around this, we will instead use environment variables to connect to our database!

Open the file config/prod.exs and comment out the last line which says import_config "prod.secret.exs". We won't need it anymore, since we don't be using that file.

If you run heroku config in your project, you should see the DATABASE_URL environment variable:

That's the database that we want to connect to in production! To use it, we edit config/prod.exs, and add a simple database configuration where we specify that we want to fetch the environment variable DATABASE_URL as the database's url:


We also have 2 secret keys that we need to generate: the secret key base (which will be used to sign all our cookies) and Guardian's secret key (which we simply set to "secret_key" in our development environment, as you might remember). We can easily generate these using mix phx.gen.secret. We then want to store the tokens under the keys SECRETE_KEY_BASE and GUARDIAN_SECRET_KEY:

Finally, we want to use these new environment variables in our configuration. We're also going to specify the URL of our app (which should be your-app-name.herokuapp.com), and make sure that we force SSL by using a rewrite engine and setting the port to 443443. Your final configuration file should look like this:


Git push!

We're now ready to deploy! If you haven't already created a Git repository for your app, you can do it with git init. Next, run the following commands to add all your changes to a new commit and deploy to Heroku:

It might take a little while to deploy your app, but hopefully you'll be created by this message in the end:


Before checking out the results, remember that we also need to run all our database migrations on our Heroku app, so that the tables that we need are created!

Now you can run heroku open and enjoy the well-earned result of your hard work!


Peter Marreck

bash>> heroku run mix.ecto.migrate Running mix.ecto.migrate on ⬢ marreckgyr... up, run.7275 (Free) bash: mix.ecto.migrate: command not found

Stefan Jarina

First: the command should be heroku run mix ecto.migrate

Stefan Jarina

Second: If you encounter this error: [error] Could not retrieve migrated versions. This error typically happens when the "schema_migrations" table, which Ecto uses for storing migrationinformation, is already used by another library or for other purposes. you need to turn off the web dyno, call ecto.migrate once again and then turn web dyno back up. The reason is, that web app uses all available connections to database and thus console command can't connect.

Peter Marreck

Messengyr.Web.Endpoint instead of Messengyr.Endpoint, no?

Stefan Jarina

Wondering why simply not change all that in prod.secret.exs (change secrets to env vars) and then just add it to github (remove from .gitignore). that way we don't need to rewrite it again.

Tristan Edwards

@stefanjarina: I suppose that works, although the whole point of prod.secret.exs is that it should contain your credentials in plain text (and therefore not be commited to GitHub).