View Source CozyProxy (cozy_proxy v0.4.1)

Proxy requests to other plugs.

Usage

A CozyProxy instance is an isolated supervision tree and you can include it in application's supervisor:

# lib/demo/application.ex
def start(_type, _args) do
  children = [
    # ...
    {CozyProxy, Application.fetch_env!(:demo, CozyProxy)}
  ]

  opts = [strategy: :one_for_one, name: Demo.Supervisor]
  Supervisor.start_link(children, opts)
end

Above code requires a piece of configuration:

config :demo, CozyProxy,
  server: true,
  adapter: Plug.Cowboy,
  scheme: :http,
  ip: {127, 0, 0, 1},
  port: 4000,
  backends: [
    %{
      plug: HealthCheckPlug,
      path: "/health-check"
    },
    %{
      plug: DemoWebAPI.Endpoint,
      path: "/api"
    },
    %{
      plug: DemoAdminWeb.Endpoint,
      path: "/admin"
    },
    %{
      plug: DemoWeb.Endpoint,
      path: "/"
    }
  ]

When using CozyProxy with Phoenix endpoints, it's required to configure the path of endpoints to a proper value. And it's better to configure :server option of endpoints to false, which avoids them serving requests bypassing CozyProxy. For example:

config :demo, DemoWeb.Endpoint,
  url: [path: "/"],
  server: false

config :demo, DemoWebAPI.Endpoint,
  url: [path: "/api"],
  server: false

config :demo, DemoAdminWeb.Endpoint,
  url: [path: "/admin"],
  server: false

Options

  • :server - start the web server or not. Default to false. It is aware of Phoenix startup arguments, if the application is started with mix phx.server or iex -S mix phx.server, this option will set to true.
  • :backends - the list of backends. Default to []. See following section for more details.
  • :adapter - the adapter for web server, Plug.Cowboy and Bandit are available. Default to Plug.Cowboy.
  • adapter options - all other options will be put into an keyword list and passed as the options of the adapter. See following section for more details.

About :backends

A valid :backends option is a list of maps, and the keys of maps are:

  • :plug:
    • required
    • typespec: module() | {module(), keyword()}

    • examples:
      • HealthCheckPlug
      • {HealthCheckPlug, []}
      • ...
  • :method:
    • optional
    • typespec: String.t()
    • examples:
      • "GET"
      • "POST"
      • ...
  • :host:
    • optional
    • typespec: String.t() | Regex.t()

    • examples:
      • "example.com"
      • ...
  • :path:
    • optional
    • typespec: String.t()
    • examples:
      • "/admin"
      • "/api"
      • ...
  • :rewrite_path_info:
    • optional
    • typespec: boolean()
    • default: true
    • examples:
      • true
      • false

The order of backends matters

If you configure the backends like this:

config :demo, CozyProxy,
  backends: [
    %{
      plug: DemoUserWeb.Endpoint,
      path: "/"
    },
    %{
      plug: DemoUserAPI.Endpoint,
      path: "/api"
    },
    %{
      plug: DemoAdminWeb.Endpoint,
      path: "/admin"
    },
    %{
      plug: HealthCheck,
      path: "/health"
    }
  ]

The first backend will always match, which may not what you expected.

If you want all backends to have a chance to match, you should configure them like this:

config :demo, CozyProxy,
  backends: [
    %{
      plug: HealthCheck,
      path: "/health"
    },
    %{
      plug: DemoUserAPI.Endpoint,
      path: "/api"
    },
    %{
      plug: DemoAdminWeb.Endpoint,
      path: "/admin"
    },
    %{
      plug: DemoUserWeb.Endpoint,
      path: "/"
    }
  ]

About adapter options

In the section of Options, we said:

all other options will be put into an keyword list and passed as the options of the adapter.

It means the all options except :server, :backends, :adapter will be passed as the the options of an adapter.

Take Plug.Cowboy adapter as an example. If we declare the options like:

config :demo, CozyProxy,
  backends: [
    # ...
  ],
  adapter: Plug.Cowboy,
  scheme: :http,
  ip: {127, 0, 0, 1},
  port: 4000,
  transport_options: [num_acceptors: 2]

Then following options will be passed to Plug.Cowboy when initializing CozyProxy:

[
  scheme: :http,
  ip: {127, 0, 0, 1},
  port: 4000,
  transport_options: [num_acceptors: 2]
]

For more available adapter options:

Summary

Functions

Returns a specification to start this module under a supervisor.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

start_link(opts)