HexTxt

How to Deploy A Phoenix App in a Sub Directory

Technology
internet calculator, concurrent processing

Image generated by deepai.org -- internet calculator, concurrent processing, cybernetics

Did you know you can host multiple Elixir Phoenix web applications under the same domain without using Umbrella? While you can find people discussing hosting multiple web apps learning how though another story. At least for this beginner how to get things configured was not always obvious.

What started this adventure was a growing fascination with concurrency in programming languages. Which led to Elixir and Erlang’s concurrency capabilities catching my attention.

As I learn best when I have a project I decided to use Elixir’s Phoenix framework and LiveView to create a simple calculator. Then I thought how about a site with multiple web apps? The first of which would be the calculator project and who knows what else?

Side note: I used this tutorial for the HTML and CSS for the calculator.

If you are going to have multiple web apps the next question is how to host them. Subdomains? Directories? Plus, what about a blog to go with them? In my case I wanted to have a Hugo generated blog, too.So, I went with sub-directories for my Hugo static site and web apps and Caddy as the web server.

Setting up Caddy server was straight forward. The calculator is hosted at localhost using the Elixir server on a unique port.

Caddy does reverse proxy with the app in a directory under the site root. Not sure if the wildcard was necessary but I threw it in just in case. If I have time I will do some testing to see if a wildcard is needed here.


    handle {
        reverse_proxy /tenkey*  localhost:5000
    }

If you look online you can find plenty of information about the Caddy reverse proxy and Elixir Phoenix. What was more difficult to figure out as a beginner was the configuration in the various application files.

The two files ‘router.ex’ and ’endpoint.ex’ are found in the same directory, ‘/MyWebApp/lib/MyWebApp_web/’ which was created when you initialized your project. These files are often mentioned in tutorials. You can find lots of helpful information about them online and in the documentation.

router.ex

The ‘router.ex’ file is noted in most tutorials for beginners. Getting it right still took some time. Eventually though everything worked out. Turns out the web socket needed a route configured. As I am still learning about how all this works I don’t have in-depth understanding of why this is needed. But it did help get things running.

  scope "/", TenkeyWeb do 
    pipe_through :browser

    get "/", PageController, :home
    # Getting socket to work when web app in sub directory
    live "/tenkey", PageLive, :home               # "/tenkey" required to display tenkey app
    live "/tenkey/websocket", PageLive, :home  
  end

See reference 1. below for more information.

Next let’s take a look at ’endpoint.ex’ as this file is where the endpoints for the static files and the sockets are configured.

endpoint.ex

Two endpoints needed to be configured for my site. First was the app and the web socket used by the app. As you can see I need to configure the ‘/webapp/live’ sub-directory. I also left the ‘/live’ endpoint in the file. You might need it or you might not. I am still pretty new at this so I suggest experimenting.

Also, the asset files. CSS and JavaScript files are asset files which needed to be exposed as well. Otherwise the calculator didn’t look like a calculator and the buttons wouldn’t work! Neither will the socket for that matter.

    # Getting socket to work when web app in sub directory

    socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
    socket "/tenkey/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]

    # Serve at "/" the static files from "priv/static" directory. 
    plug Plug.Static,
    # Exposing static asset directories when web app in sub directory 
        at: "/tenkey",
        from: :tenkey,
        gzip: false,
        only: TenkeyWeb.static_paths()

See reference 1. and 2. below for more information.

config.exs

Another spot to configure static assets is in the ‘config.exs’ file.

# Configures the endpoint
config :tenkey, TenkeyWeb.Endpoint,
  # Exposing static asset directories when web app in sub directory 
  static_url: [path: "/tenkey"],  
  url: [host: "localhost"],
  render_errors: [
    formats: [html: TenkeyWeb.ErrorHTML, json: TenkeyWeb.ErrorJSON],
    layout: false
  ],
  pubsub_server: Tenkey.PubSub,
  live_view: [signing_salt: "vsvm/lgN"]

See reference 2. below for more information.

Last but not least, the configuration that finally got everything working with Caddy. Setting ‘check_origin’ in ‘prod.exs’ to allow ’localhost’ and my domain as origins finally opened up socket communication between the browser and server.

prod.exs

  # Getting socket to work when behind reverse proxy
  check_origin: ["//localhost:5000", "//example.com"]   # <===== This fixed the web socket connection problems!

See reference 3. below for more information.

After going through the research setting up the calculator in a sub-directory of the domain wasn’t a big deal. Getting there took some thinking and experimenting as I had never worked with Elixir, Phoenix, or LiveView before. Hope these notes are helpful.

References

  1. https://elixirforum.com/t/live-dashboard-behind-a-reverse-proxy-not-working-under-a-namespace/43874/10)

  2. https://ericlathrop.com/2019/12/the-usefulness-of-phoenix-s-static-path-2/

  3. https://elixirforum.com/t/websocket-connection-works-on-localhost-but-get-403-error-when-deployed-via-docker/7466/12

Share with Friends!
LinkedIn
Reddit
Hacker News