MIX_ENV=Phoenix 服务器上的产品在从 PORT=80 开始时崩溃

MIX_ENV=prod on a Phoenix server crashes on starting with PORT=80

我在混音和 MIX_ENV=prodmix phoenix.server 方面遇到一些问题,启动失败。 运行 所有最新版本(Elixir 1.0.5,Phoenix 0.14.0)除了 Erlang(17.x,我认为是 17.3)在 Linode 的 Ubuntu 14.04.

$ MIX_ENV=prod PORT=80 mix phoenix.server
{"Kernel pid terminated",application_controller,"{application_start_failure,elirc_site,{{shutdown,{failed_to_start_child,'Elixir.ElircSite.Endpoint',{shutdown,{failed_to_start_child,'Elixir.Phoenix.Endpoint.Server',{shutdown,{failed_to_start_child,{ranch_listener_sup,'Elixir.ElircSite.Endpoint.HTTP'},{shutdown,{failed_to_start_child,ranch_acceptors_sup,{{badmatch,{error,eacces}},[{ranch_acceptors_sup,init,1,[{file,\"src/ranch_acceptors_sup.erl\"},{line,30}]},{supervisor,init,1,[{file,\"supervisor.erl\"},{line,243}]},{gen_server,init_it,6,[{file,\"gen_server.erl\"},{line,306}]},{proc_lib,init_p_do_apply,3,[{file,\"proc_lib.erl\"},{line,239}]}]}}}}}}}}},{'Elixir.ElircSite',start,[normal,[]]}}}"}

具体来说,我认为是跟踪的这一部分。

{{badmatch,{error,eacces}},[{ranch_acceptors_sup,init,1,[{file,\"src/ranch_acceptors_sup.erl\"},{line,30}]}

看起来您的服务器正试图绑定到一个没有 root 权限的受限端口(小于 1024)。尝试使用更高的端口,比如 Phoenix 的默认端口 4000。如果它需要在端口 80 上,要么 运行 它作为 root 或(更好)用 nginx 代理它。

正如 Nick Meharry 所指出的,您正在尝试 运行 您的 Phoenix 服务器进程在传统上在 Unix 上的端口上,只有 root 可以绑定到(低端口(<1024))。

运行 出于安全原因,不推荐您作为 root 的进程 - 接管该进程的攻击者可以获得对整个操作系统的根访问权限。

通过 运行将您的服务器连接到高端口(例如 4000)并使用简单的 iptables 规则将连接从端口 80 转发到端口 4000 来解决这个问题会更安全。请注意您计算机上的任何用户都可以绑定到端口 4000 - 因此您将失去来自低端口的额外保护。

另一种解决方案是允许某些程序(mixelixir)使用 CAP_NET_BIND_SERVICE Linux 内核功能(自 2.6.24 起可用)绑定到 1024 以下的端口) 可以使用 setcap 进行设置。但是任何用户仍然可以使用这个可执行文件,除非它们通过使用适当的文件访问权限只对特定用户可用。

我看到以下选项:

  1. 在前面使用 apache/nginx 作为 phoenix 运行ning 在其后面更高端口上的代理——Elixir 的创建者表示,在这个问题线程中通常不需要这样做.如果您已经需要 nginx 来做其他事情(比如 运行ning WP 或提供静态图像),那么就这样做吧。
  2. 运行 以 root 用户身份——简单但从安全角度来看非常糟糕的主意。
  3. 使用 IP 表——简单有效,但会破坏 ipv6
  4. 使用 setcap 赋予特定二进制文件打开较低端口的能力。

我喜欢选项 4。

为了 运行 mix phoenix.server 和类似的命令,您需要在您的 BEAM 二进制文件上 运行 setcap。您可以通过以 root 身份短暂启动服务器并执行 ps -ef | grep beam 来找到它。在我的系统上,它是 /usr/lib/erlang/erts-8.1/bin/beam.smp,所以我 运行:

sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/lib/erlang/erts-8.1/bin/beam.smp

现在可以使用 mix 命令在普通端口上启动服务器。接下来,您可能想要部署一个实际的 elixir 版本并将其 运行 作为一项服务。同样的策略有效。在您的版本创建的 run_erl 二进制文件上使用 setcap。对于我的应用程序,它是:

sudo setcap CAP_NET_BIND_SERVICE=+eip /home/ubuntu/myapp/_build/prod/rel/myapp/erts-8.1/bin/run_erl

现在 upstart 或 systemd 脚本也可以启动服务器。