Deploying Elixir Phoenix applications is a broad subject but in this guide we're going to limit the process to deploying a simple greenfield app to render.com.
Render.com is described as:
Render is a unified platform to build and run all your apps and websites with free SSL, a global CDN, private networks and auto deploys from Git.
- Create a simple Elixir Phoenix application.
- Configure and deploy our new Phoenix app to Render.com
- Deployment using releases available in Elixir 1.9+
Notes on Releases
You can read the release notes for Elixir 1.9 here, but let's cover some of the important points.
Releases allow developers to precompile and package all of their code and the runtime into a single unit.
Elixir and Erlang VM are packaged within a release and don't need to be installed on the target machine. Releases have very much simplified how Elixir applications are deployed and managed in production.
If you're interested in reading about the finer details, there are also some detailed docs on Releases in Hex.
Create an App
IMPORTANT: ensure that you are running Elixir 1.9+ before continuing:
$ elixir -v
With this in mind, let's create our throwaway app:
$ mix phx.new render
Fetch and install dependencies? [Yn]
Then setup the local version:
$ cd render
$ mix ecto.create
We can start the server, but we already know what's going to happen. Let's move on.
The first step is to rename config/prod.secret.exs. We will be using environment variables to configure the app, so we won't need any secrets.
$ mv config/prod.secret.exs config/releases.exs
This will be the runtime configuration for the release. Open releases.exs and make a few changes:
This is the final version that includes the changes we need to make, and clears out the comments. Feel free to keep the comments if they'll help you understand what's going on in the config.
Next, open config/prod.exs and remove the reference to prod.secret.exs:
We're going to use a build script to give render a series of commands to run in order to deploy our app. Create a new file bin/render-build with the following content:
And set the permissions on the file:
$ chmod a+x bin/render-build
In the build script, you may have noticed we have the line that runs a migrate function in the Render.Release module. Here's the purpose:
Another common need in production systems is to execute custom commands required to set up the production environment. One of such commands is precisely migrating the database. Since we don't have Mix, a build tool, inside releases, which are a production artifact, we need to bring said commands directly into the release.
To add the custom module, create LIB_PATH/release.ex with this content:
This gives the both the migrate and rollback commands from inside the release.
Next we need to update our production config for deployment to render.com.
Open config/prod.exs and update the app's url:
RENDER_EXTERNAL_HOSTNAME is set by render automatically.
This should get us most of the way there. Let sign up on render.com and create our services.
Push to Github
To make simplify deploying to render.com, create a repo in your Github account, and push the code:
$ git init
$ git remote add origin <ssh-endpoint>
$ git add .
$ git commit -m 'Init'
$ git push origin
With our github repo ready, you can register on render.com using your Github account.
Create a DB Service:
Create Web Service:
And while that's creating, create the web service under Services -> New Web Service and select the repo created earlier. If you didn't connect your Github account, you can still do it now.
- Name: `<something-unique>`
- Environment: Elixir
- Branch: master
- Build Command: ./bin/render-build
- Start Command: _build/prod/rel/render/bin/render start
Hit create the service and it will fire off an initial attempt to deploy the app.
You'll likely see an error in the log:
Which means our app can't connect the database. This is expected because we haven't configured it yet.
We're going to configure a few environment variables necessary to run the app.
Navigate to the "Databases" section of the render.com dashboard, and select the DB you just created.
Then copy the "Internal Connection String":
Then navigate to the services section and select your newly created service.
Hit the "Environment" tab:
Where we can enter DATABASE_URL and the "Internal Connection String"
Next we can generate a new secret key using:
$ mix phx.gen.secret
And set SECRET_KEY_BASE to the output value.
Test it out
If you monitor the deployment log, there shouldn't be any issues at this point and we have our first release in production.
You can test it out by visited the service url in the browser.
In the settings section for your app you can toggle auto-deploys on commits. Any changes made to the environment variables will also trigger a deployment.
We really enjoy working with render.com and though there are many other options for deployment, we're finding that $14/mth is a small price to pay for a solid, production ready deployment pipeline.
There are many other features that we didn't get to in the guide such as PR deploys/review apps, background services and the infrastructure as code using yaml files, but maybe we'll dive deeper into these features if there's enough interest.
I hope you enjoyed this guide and let us know if you have any questions for feedback on how to improve it.