Deploy Phoenix 1.6 / Elixir 1.3 on Render.com: A Working Guide

Alvin Rapada
5 min readDec 21, 2021

Spent almost a week fixing errors after errors trying to deploy my Phoenix/Elixir App on render.com. So I decided to write my journey to hopefully help noobs like me.

Note that this blog is for noobs (like me), so I had to really tell what needs to be done (dumb down things), kinda like what I want some blogs to be written, for me to understand it well enough so I don’t have to experience this again 😂 . If you think you’re too smart for this, I’m sorry and if there’s anything wrong with how I understand things, feel free to correct and enlighten me 🙏. Anyways, let’s get started.

Preparing your Phoenix/Elixir App for Deployment

You can follow this tutorial: Deploy a Phoenix App with Mix Releases and if everything works, you can skip this portion.

BUT if it doesn't (Just like mine) there are things I needed to change to make it work.

  • First is the build.sh , here’s mine:
#!/usr/bin/env bash# exit on error
set -o errexit
# Initial setup
mix deps.get --only prod
MIX_ENV=prod mix compile
# Compile assets
npm install --prefix ./assets
MIX_ENV=prod mix assets.deploy
# Build the release and overwrite the existing release directory
MIX_ENV=prod mix release --overwrite
# Run migrations
_build/prod/rel/alvin_and_eloisa/bin/alvin_and_eloisa eval "Release.migrate"
# Run seeds
MIX_ENV=prod mix run priv/repo/seeds.exs

As you notice, I'm compiling my assets using both npm and mix, For some reason, when using mix assets.deploy alone, esbuild is not compiling my app.csson production, and when I'm using npm my JS is not compiling, So I figured I can use both to compile both and when I tried it, It worked! 😂

Also, you may want to comment the Run seed block after running it successfully the first time, to avoid duplicate data on your production database.

  • Next is mix.exs.
defp aliases do
[
setup: ["deps.get", "ecto.setup", "cmd --cd assets npm install"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.deploy": [
"cmd --cd assets npm run deploy",
"esbuild default --minify",
"phx.digest"
]

]
end

Had to edit my alias for assets.deploy to do npm run deploy which will run the deploy script on our package.json below.

  • package.json , add the scripts block to compile my app.css, I’m using TailwindCSS by the way.
{
"scripts": {
"deploy": "NODE_ENV=prod tailwindcss --postcss --input=css/app.css --output=../priv/static/assets/app.css --minify"
},
"dependencies": {
"cogo-toast": "2.0.1",
"onmount": "^1.3.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-phoenix": "file:../deps/react_phoenix"
},
"devDependencies": {
"@babel/preset-env": "^7.16.4",
"@babel/preset-react": "^7.16.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.5",
"postcss-cli": "^8.3.1",
"postcss-import": "^14.0.2",
"tailwindcss": "^3.0.7"
}
}

Creating Database and Web Service on Render

There's not much I can tell about this process, it's pretty easy to do and I have not encountered any problems doing this.

Web services: You can check the full documentation here.
Databases: You can check the full documentation here.

Setting up Environment Variables

On the render dashboard, select the web service you just created and go to the Environment tab and click the Add Environment Variablebutton to add environment variables.

Database Url
Create a variable named DATABASE_URL, then go to the database service you created, and copy the Internal Connection String and paste it on the value textbox.

Secret Key Base

Create a variable named SECRET_KEY_BASE , then in your terminal, run mix phx.gen.secret , copy the result and paste it on the value textbox.

Customizing Elixir and Erlang/OTP versions

You can check here for the list of Elixir and Erlang versions supported by render, mine are:

  • ELIXIR_VERSION: 1.13.1
  • ERLANG_VERSION:24.1.7

You need to make sure your versions are correct and ideally equal to your local setup, I’ve had issues with these when deploying my app on production not realizing that the default elixir version on render is 1.9.4.

Adding Custom Domain with hostinger

Once you got your domain on hostinger, go to your web service settings (on render) and click Add Custom Domain. Input the domain you bought and after that will something like this below:

It is basically telling you to add these DNS records pointing your domain to the render web server, so let's do that. Inside your hostinger account, go to the DNS/Nameservers tab of the domain you just bought and add a DNS record.

Hostinger doesn’t have ANAME and ALIAS records so I ended up adding just these three below. After you are done, go back to the settings page of your web service (on render) and click verify, it may take a couple of minutes to verify but if for some reason it fails (like mine), delete the record on hostinger and add it again (that’s what I did).

Types   Name  Pointing to
CNAME www yourwebsite.onrender.com
CNAME * yourwebsite.onrender.com
A @ 216.24.57.1

NOTE: When your custom domain was added to your web service make sure to also add it to your check_origin in prod.exs .

config :your_app, YourAppWeb.Endpoint,
url: [host: System.get_env("RENDER_EXTERNAL_HOSTNAME") || "localhost", port: 80],
check_origin: [
"
https://yourdomain.com/",
"//yourdomain.com"
]
,
cache_static_manifest: "priv/static/cache_manifest.json"

this will prevent you from having some WebSocket issues and DB Connection errors like this ⬇️

Conclusion

Considering that this is the first time I’ve deployed a Phoenix/Elixir App, I can’t say that I enjoyed it BUT it’s a great experience and it is sure as hell a satisfying one, especially when you figured all things out and you see your website working properly, I had a blast!!

You can check the issues I’ve encountered here and feel my pain throughout the whole process.

If you find this helpful, I’d appreciate a coffee 😊

Happy Coding!!

--

--