rogerweb

rogerweb

Phoenix application behind AWS ALB

Hi,

I’m running a Phoenix application behind a AWS ALB (Application Load Balancer), which routes requests to different applications based on the path in the requested URL.

Requests that start with /myapp are routed to my application.

The problem is that ALB doesn’t support stripping this /myapp prefix from the actual URL that goes to Phoenix (differently from nginx, haproxy, etc) and I wouldn’t like to add this prefix (a deployment configuration) to all my routes as it can only be done in compilation time (at least without having to create a router myself which I think would be overkill; I might be wrong though).

In an attempt to overcome this issue, I’ve created a simple plug that runs before everything and removes the prefix from connection’s path_info. For instance, it turns

["myapp", "assets", "app-978a7188b69b3752fe7c58e50c7e5571.js"]

into

["assets", "app-978a7188b69b3752fe7c58e50c7e5571.js"]

Also, I configure my Endpoint to use this prefix as the path so URLs generated by the application include the prefix back and are properly routed by ALB.

# runtime.exs
config :myapp, MyAppWeb.Endpoint,
  url: [
    host: get_env("PHX_HOST", "localhost"),
    port: get_env("PHX_PORT", 4000, :int),
    path: get_env("PHX_PATH", "/") # get_env is just a helper func
  ]

It works fine for assets and regular routes, but not for sockets and anything that uses sockets like live reloading and the dashboard. Example:

17:39:09.218 [info] GET /myapp/socket/websocket
17:39:09.280 [debug] ** (Phoenix.Router.NoRouteError) no route found for GET /socket/websocket (MyAppWeb.Router)
    (myapp 1.0.0-alpha.19) lib/phoenix/router.ex:405: MyAppWeb.Router.call/2
    (myapp 1.0.0-alpha.19) lib/myapp_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2 

The plug feels like a hack and it didn’t solve my problem.

Have you guys had to deal with a similar deployment? How did you manage?

Cheers!

First Post!

Exadra37

Exadra37

If your app deployment target for production is to be behind that aws load balancer why do you want to overcome the issue in your app? Why not keeping it simple and just add the prefix?

Doesn’t the load balancer support to invoke a lambda function?

Or if your domain is with Route53 you can try to use forwarding rules:

Most Liked

aherranz

aherranz

I found a better solution using the function MyAppWeb.Endpoint.path/1 to avoid introducing a new config entry:

    <meta name="live-socket-path" content={MyAppWeb.Endpoint.path "/live"} />

And let JS fail of the meta data is not defined:

let liveSocketPath = document.querySelector("meta[name='live-socket-path']").getAttribute("content");
rogerweb

rogerweb

Unfortunately that’s not all we need to do. To demonstrate it, one can do:

  1. Start fresh with mix phx.new hello --no-ecto
  2. Apply your first point, i.e., add the path to the Endpoint:
# runtime.exs
  config :hello, HelloWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https", path: "/myapp"],
  1. Apply your second point:
// app.js
let liveSocket = new LiveSocket("/myapp/live", Socket, {params: {_csrf_token: csrfToken}})
  1. Start the application with mix phx.server

  2. Access http://localhost:4000/myapp

  3. Observe that you got a 404 not found.

This is not a surprise as the Endpoint’s documentation tells us the url config is about how URLs are generated, it is not the base path/prefix/scope for all the routes in your app.

So this config won’t make your routes to be found, unless you manually prefix them with /myapp. As per previous posts, this was not an option because the prefix is a runtime/deployment concern, but I temporarily accepted it as a workaround just to move on. So now the page and assets (and sockets added via mix phx.gen.socket and manually prefixed) are found, great, but not the live reload frame (http://localhost:4000/myapp/phoenix/live_reload/frame). And for that, it seems there is no config to be changed.

Also, Phoenix’s dashboard generates URLs with a duplicated /myapp, like http://localhost:4000/myapp/myapp/dashboard/home

That’s why I told you

Because

Where Next?

Popular in Questions Top

New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 131117 1222
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44265 214
New

We're in Beta

About us Mission Statement