简体   繁体   中英

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

I am having some issues with mix, and MIX_ENV=prod with mix phoenix.server , where it fails on starting. Running all latest (Elixir 1.0.5, Phoenix 0.14.0) except Erlang (17.x, 17.3 I think) on Linode's 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,[]]}}}"}

Specifically I think its this part of the trace.

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

It looks like your server is attempting to bind to a restricted port (less than 1024) without root privileges. Try using a higher port, like Phoenix's default of 4000. If it needs to be on port 80, either run it as root or (better) proxy it with nginx.

As Nick Meharry pointed out you are trying to run your Phoenix server process on a port that traditionally on Unix, only root can bind to (low ports (<1024)).

Running your process as root is not recommended because of security reasons - an attacker who would take over the process could get root access to the whole operating system.

It's more secure to work around this by running your server on a high port (for instance, 4000) and use a simple iptables rule to forward the connections from port 80 to port 4000. Note that any user on your machine can bind to port 4000 - so you lose the extra protection from the low ports.

Another solution is to allow certain programs ( mix , elixir ) to bind to ports below 1024 using CAP_NET_BIND_SERVICE Linux kernels capability (available since 2.6.24) which can be set using setcap . But then still any user can use this executables unless they are available only to a certain user by using proper file access rights.

I see the following options:

  1. Use apache/nginx in front as a proxy for phoenix running on a higher port behind it—The creator of Elixir, has said there's usually no need to do that in this very question thread. If you already need nginx for something else (like running WP or serving static images), then just do this.
  2. Run as root—simple but very bad idea from a security perspective.
  3. Use IP tables—simple and effective, but breaks ipv6
  4. Use setcap to give specific binaries the power to open lower ports.

I like option 4.

In order to run mix phoenix.server and similar commands, you need to run setcap on your BEAM binary. You can find it by briefly starting the server as root and doing ps -ef | grep beam ps -ef | grep beam . On my system, it's /usr/lib/erlang/erts-8.1/bin/beam.smp , so I ran:

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

Now the server can be started on a normal port with mix commands. Next, presumably you're going to want to deploy an actual elixir release and run it as a service. The same strategy works. Use setcap on the run_erl binary your release created. For my app it was:

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

Now an upstart or systemd script can launch the server, too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM