4

I need to forward the traffic from Http to Https, SSL is on the load balancer so all I need to do is forward the header by using the plug_ssl so in my prod.exs I added:

config :web, Web.Endpoint,
  force_ssl: [rewrite_on: [:x_forwarded_proto]]

in my prod.exs and remove everything else on config :web, Web.Endpoint

It doesn't work.

What am I doing wrong?

Do I need to put the force_ssl in my router?

Thank you in advance.

Mr H
  • 5,254
  • 3
  • 38
  • 43

2 Answers2

3

You will probably need to enable the force_ssl plug only for your endpoints that are not used for health check or something related to that.

I had a similar problem with the k8s Ingress on GKE and the solution was to put the force_ssl on router only for my application routes, and let /healthz (which was configured as my health check route) using HTTP.

An example of config/prod.exs:

# Tells if we need to enforce SSL for our endpoints.
# Only production/staging should enforce
config :my_app, force_ssl: true

config :my_app, MyAppWeb.Endpoint,
  load_from_system_env: true,
  url: [host: "${APP_HOST}", port: 80],
  server: true,
  http: [port:  "${PORT}"],
  url: [scheme: "https", host: "${APP_HOST}", port: 443],
  secret_key_base: "${SECRET_KEY_BASE}"

And here is an example of lib/my_app_web/router.ex:

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  # This route will NOT enforce SSL
  get("/healthz", MyAppWeb.HealthCheckController, :show)

  pipeline :api do
    plug(:accepts, ["json"])

    if Application.get_env(:my_app, :force_ssl) do
      plug(Plug.SSL, rewrite_on: [:x_forwarded_proto], host: nil)
    end
  end

  scope "/", MyAppWeb do
    pipe_through(:api)

    # My routes will go here, and will be enforced if the
    # application flag `force_ssl` is enabled.
  end
end

This is a little bit tricky to debug. If you are using kubernetes, try to use the kubectl describe ingress YOUR-INGRESS-HERE, and always check the headers for your requests and responses while doing the tests.

Philip Sampaio
  • 672
  • 6
  • 9
0

Usually healthchecker calls your server directly using local network, not the domain your app is on. This way you can put your local address into exclude option.

This is what I did:

config :my_app, MyApp.Endpoint,
  force_ssl: [rewrite_on: [:x_forwarded_proto], exclude: ["localhost", "${IP_ADDRESS}"]],

Where IP_ADDRESS I got from environement variable (it depends on your deployment type on how you obtain it) using distillery. However when you don't use distillery you can just obtain environement variables this way:

config :my_app, MyApp.Endpoint,
  force_ssl: [rewrite_on: [:x_forwarded_proto], exclude: ["localhost", System.get_env("IP_ADDRESS")]],
Kelu Thatsall
  • 2,494
  • 1
  • 22
  • 50