Starting Point: A newly generated Phoenix 1.4.9 app
Goal: Set up Elixir releases and successfully deploy in under 20 minutes
Deployment is one of those things a lot of Elixir learners have complained about. It's easy to get lost the sea of options and worry that you're not doing it "correctly" or that what seems like a simple process might turn into a nightmare of configuration and hours spent on "meta" work that doesn't actually move you towards building that exciting app you've been wanting to build.
It seems there should be a straightforward way... and there are many! Some would say too many.
Should we be running mix on the server or building releases? How about putting Nginx in front of Phoenix or not? How should we decide between a VPS like AWS EC2 or a Digital Ocean droplet vs something like Heroku?
I've done all of these things. All are doable and I'm pretty happy with my current setup. But what if you don't want to manage your own servers? What if you want something that's easy, doesn't cost a fortune and just works?
A new champion has entered the arena!
If you're looking for low-hassle and just want to get started, then I recommend checking out Render. It's a still early stage startup, started by a very early Stripe employee.
It's a similar sort of promise as Heroku, as it was in its golden era. Render is fast, it's much cheaper than post acquisition Heroku and this tutorial will have you up and running in under 20 minutes.
Step one: set up Mix Releases (Elixir 1.9+)
Starting from a fresh Phoenix 1.49 app, created with mix phx.new yolo
, we need to set up the app for Elixir mix releases.
Before starting, create a local yolo_prod
database by running MIX_ENV=prod mix ecto.setup
.
Rename `prod.secrets.exs` to `releases.exs` and make these changes:
- replace the line
use Mix.Config
at the top with import Config
- uncomment the following line at the bottom:
config :yolo, YoloWeb.Endpoint, server: true
Then in `prod.exs`, make these changes:
- remove the line
import_config "prod.secret.exs"
(since the file no longer exists!)
- change the line with
url: [host: "example.com", port: 80],
to:
url: [host: System.get_env("HOSTNAME") || "localhost", port: 80],
Create a new script "build.sh
" at the base of your app
#!/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
# for auto DB migration upon deploy
MIX_ENV=prod mix ecto.migrate
Don't forget to make the script executable by running chmod a+x ./build.sh
!
Building a release locally
All we need to do is run the build script with the appropriate environment variables set locally!
export SECRET_KEY_BASE=`mix phx.gen.secret`
export DATABASE_URL="ecto://postgres:postgres@localhost/yolo_prod"
# Build the release
MIX_ENV=prod ./build.sh
You should then see the following output on your screen:
Release created at _build/prod/rel/yolo!
# To start your system
_build/prod/rel/yolo/bin/yolo start
Deploying to Render
We're almost done! Only two files need to be changed. update the following lines in them as shown below:
repo.ex
use Ecto.Repo,
otp_app: :yolo,
adapter: Ecto.Adapters.Postgres,
pool_size: 10
def init(_type, config) do
{:ok, Keyword.put(config, :url, System.get_env("DATABASE_URL"))}
end
prod.exs
url: [host: System.get_env("RENDER_EXTERNAL_HOSTNAME") || "localhost", port: 80],
Log into Render
Take your pick of Gitlab or Github to create an account and log in. Click to create a database named yolo_prod
, leave the other two fields blank and hit the create button (it takes a minute to create).
Open another tab and click "New Web Service". Select "Elixir" as your environment and set the start command to _build/prod/rel/yolo/bin/yolo start
, then finally enter the following environment variables:
- DATABASE_URL: set this to the "Internal Connection String" Render has generated for your DB in the tab where we created it
- SECRET_KEY_BASE: generate this on your local machine with
mix phx.gen.secret
and paste it in.
Finally, click "Create Web Service". It will pull your app from Gitlab or Github, build it and deploy it to their servers.
Done
Total cost: $14/month and not much of your time.