SSL for Custom Domains: Phoenix

Hello!

I’m having trouble serving a Phoenix application to a custom domain appropriately behind Fly’s reverse proxy.

I have generated certifications for the root domain and the wildcard domain, and I can actually ‘make’ the domain work if I give my OTP application the following configuration at compilation in its production environment:

config :my_app, MyAppWeb.Endpoint,
  ...
  force_ssl: [
    host: "example.com:443",
    rewrite_on: [:x_forwarded_host, :x_forwarded_port, :x_forwarded_proto]
  ]

… which is fine, but if I understand what’s happening right, this seems like it’s brittle; I thought the configuration was going to be something like this, instead:

config :my_app, MyAppWeb.Endpoint,
  ...
  force_ssl: [
    rewrite_on: [:x_forwarded_host, :x_forwarded_port, :x_forwarded_proto]
  ]

… which does serve appropriately to my_app.fly.dev, but not to the custom domain.

Any help at all is greatly appreciated!

(For what it’s worth, I’m willing to embrace the idea that I should actually manually set the force_ssl[:host] configuration if that’s right! I think I need a sanity pass on that more than anything, though, for someone more versed in this stuff to give me the green light to do that!)

Our config looks like this, prod.exs:

config :fly, FlyWeb.Endpoint,
  url: [host: "example.com", port: 80],
  cache_static_manifest: "priv/static/cache_manifest.json",
  force_ssl: [
    host: nil,
    rewrite_on: [:x_forwarded_port, :x_forwarded_proto],
    hsts: false, # maybe true when we use this for real
  ]

And in runtime.exs:

  config :fly, FlyWeb.Endpoint,
    server: true,
    url: [host: "fly.io"],

This seems to work fine! I don’t know if it’s the best possible way to do it, but it did require us putting a single url.host value in the endpoint config.

1 Like

I do recall trying some combination of {:host, nil} and difference combinations of {:rewrite_on, [...]} a couple of times, but I’ll fuss around with this tomorrow and see what I come up with! :heart:

1 Like

Oh I remember why we did it this way! Setting host: nil seems to make it work for any hostname. The Endpoint config is necessary for CORS and generated emails and things.

For other people facing SSL issues - you might want to add force_https to your services section in fly config file:

  [[services.ports]]
    handlers = ["http"]
    port = 80
    force_https = true
1 Like