Step by step guide on Hosting your Elixir and Phoenix apps in production on NodeChef

Deploying Elixir, Phoenix apps on NodeChef involves running a single command [nc deploy] after you complete the process of creating your application from the dashboard and configuring environment variables. You can also deploy by uploading your project folder from the dashboard if preferred over using the NodeChef CLI.

The below steps provide a complete guide on hosting your Elixir, Phoenix apps on the NodeChef bare metal cloud platform

Step 1. Create your application from the dashboard

Create a NodeChef account and verify your account by clicking on the link emailed to you after you completed the sign up form. Log into your acount. On the dashboard, click on Deployments. You will be presented with the Deploy app form. Enter a name for your app, select the 256 or 512 RAM container size and then select the desired database. You can change the RAM capacity of your container at anytime. You can freely experiment with container sizes as NodeChef charges by the hour. Choose between the US-East or EU-West data center and then click on the Launch Cluster button.

Create Elixir,Phoenix app on NodeChef

Step 2. Prepare your Phoenix app to run in the NodeChef environment

Every new Phoenix project ships with a config file config/prod.secret.exs which stores configuration. On NodeChef you can read configuration values from environment variables.

First, let’s make sure our secret key is loaded from NodeChef’s environment variables instead of config/prod.secret.exs by adding a secret_key_base line in config/prod.exs (remember to add a comma to the end of the preceding line):

config :hello, HelloWeb.Endpoint, load_from_system_env: true, url: [host: "example.com", port: 80], cache_static_manifest: "priv/static/cache_manifest.json", secret_key_base: Map.fetch!(System.get_env(), "SECRET_KEY_BASE")

Then, we’ll add the production database configuration to config/prod.exs if applicable. If you selected to create a database in Step 1, NodeChef automatically sets the environment variable "DATABASE_URL" on your executing containers.

# Configure your database config :hello, Hello.Repo, adapter: Ecto.Adapters.Postgres, url: System.get_env("DATABASE_URL"), pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), ssl: true

Now, let’s tell Phoenix to use our NodeChef URL and enforce SSL. You can find the NodeChef URL assigned to your app by clicking on App actions → Browse. You can then copy the hostname portion of the URL.

url: [scheme: "https", host: "phoenix-hello-world-1.nodechef.com", port: 443], force_ssl: [rewrite_on: [:x_forwarded_proto]],

Finally, we need to decrease the timeout for the websocket transport in lib/hello_web/channels/user_socket.ex:

defmodule HelloWeb.UserSocket do use Phoenix.Socket ... ## Transports transport :websocket, Phoenix.Transports.WebSocket, timeout: 45_000 ... end

This ensures that any idle connections are closed by Phoenix before they reach NodeChef’s 60-second timeout window.

Lastly, we’ll need to create a Procfile (a text file called “Procfile” in the root of our project’s folder) with the following line:

web: MIX_ENV=prod mix phx.server


Step 3. Setting up environment variables

You can set environment variables using a JSON file or from the dashboard. To set environment variables from the dashboard, on the task manager, find and click on App actions → Environment variables. You can then set all your environment variables and save your changes.

Create Environment variables on NodeChef

To set environment variables using a JSON file, create a file in the root of your project's folder with an example name envdev.json. You can then set your environment variables as seen below:

{ POOL_SIZE: 18, SECRET_KEY_BASE: "xvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53" }


Step 4. Deploy the app

NodeChef provides two simple ways to deploy your app: By using the NodeChef CLI to upload your project or by using an intuitive dashboard to upload your project.



Troubleshooting compilation Errors

Occasionally, an application will compile locally, but not on NodeChef. The compilation error on NodeChef will look something like this:

== Compilation error on file lib/postgrex/connection.ex == could not compile dependency :postgrex, "mix compile" failed. You can recompile this dependency with "mix deps.compile postgrex", update it with "mix deps.update postgrex" or clean it with "mix deps.clean postgrex" ** (CompileError) lib/postgrex/connection.ex:207: Postgrex.Connection.__struct__/0 is undefined, cannot expand struct Postgrex.Connection (elixir) src/elixir_map.erl:58: :elixir_map.translate_struct/4 (stdlib) lists.erl:1353: :lists.mapfoldl/3 (stdlib) lists.erl:1354: :lists.mapfoldl/3

This has to do with stale dependencies which are not getting recompiled properly. It’s possible to force NodeChef to recompile all dependencies on each deploy, which should fix this problem. The way to do it is to add a new file called elixir_buildpack.config at the root of the application. The file should contain this line:

always_rebuild=true

Native dependency loading errors

You might face dependency loading errors at runtime when loading dependencies with native components such as the example seen below.

[error] Process #PID<0.461.0> raised an exception ** (RuntimeError) An error occurred when loading Argon2. Make sure you have a C compiler and Erlang 20 installed. If you are not using Erlang 20, either upgrade to Erlang 20 or use bcrypt_elixir (version 0.12) or pbkdf2_elixir. See the Comeonin wiki for more information. (argon2_elixir) lib/argon2/base.ex:19: Argon2.Base.init/0 (kernel) code_server.erl:1333: anonymous fn/1 in :code_server.handle_on_load/5 03:33:30.190 [warn] The on_load function for module Elixir.Argon2.Base returned: {%RuntimeError{message: "An error occurred when loading Argon2.\nMake sure you have a C compiler and Erlang 20 installed.

This typically happens when you push your local deps folder as well to prod. You can place a file with name .ncignore in the root of your project folder and then enter deps in this file. This will force the CLI to exclude the deps folder when bundling the project folder to deploy.