问题 凤凰服务器上的MIX_ENV = prod在PORT = 80开始时崩溃


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

$ 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}]}

8385
2018-06-30 19:24


起源



答案:


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


5
2018-06-30 19:31



但是,通常没有必要在nginx后面运行Phoenix。 :) - José Valim
对。如果您不想以root身份运行应用程序级代码但绝对需要端口80/443(我认为可能就是这种情况),那就更好了。 - Nick Meharry
您还可以使用iptables(或首选防火墙)对端口进行NAT。例如:iptables -t nat -A OUTPUT -d myhostname -p tcp --dport 80 -j REDIRECT --to-ports 8080 && iptables -t nat -A PREROUTING -d myhostname -p tcp --dport 80 -j REDIRECT - 到端口8080 - diogovk


答案:


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


5
2018-06-30 19:31



但是,通常没有必要在nginx后面运行Phoenix。 :) - José Valim
对。如果您不想以root身份运行应用程序级代码但绝对需要端口80/443(我认为可能就是这种情况),那就更好了。 - Nick Meharry
您还可以使用iptables(或首选防火墙)对端口进行NAT。例如:iptables -t nat -A OUTPUT -d myhostname -p tcp --dport 80 -j REDIRECT --to-ports 8080 && iptables -t nat -A PREROUTING -d myhostname -p tcp --dport 80 -j REDIRECT - 到端口8080 - diogovk


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

以您的流程运行 root 由于安全原因,不建议使用 - 攻击者将接管整个操作系统。

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

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


5
2017-07-01 09:14





我看到以下选项:

  1. 在前面使用apache / nginx作为凤凰在其后面的更高端口上运行的代理 - Elixir的创建者,已经说过在这个非常问题的线程中通常没有必要这样做。如果你已经需要nginx用于其他东西(比如运行WP或提供静态图像),那么就这样做吧。
  2. 从安全角度来看,以简单但非常糟糕的方式运行。
  3. 使用IP表 - 简单有效,但打破了ipv6
  4. 使用setcap为特定二进制文件提供打开较低端口的能力。

我喜欢选项4。

为了奔跑 mix phoenix.server 和类似的命令,你需要运行 setcap 在你的BEAM二进制文件上。您可以通过以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版本并将其作为服务运行。同样的策略也有效。使用 setcap 在...上 run_erl 二进制你的发布创建。对于我的应用程序,它是:

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

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


5
2017-12-13 11:55



对我来说,我不得不使用 setcap on / beam not /beam.smp。这有助于测试它是否有效:运行 iex, 然后 :gen_tcp.listen(80, [])。应该得到如下结果: {:ok, #Port<0.1426>} - Vantalk