logicmason
What's the best way to serve restricted ports (e.g. 80, 443) with Phoenix?
Hi there, I’m working through my first release with elixir/phoenix. I’ve built a release with distillery and found that it crashes when I start it since it’s trying to access port 80 and linux restricts ports under 1024. Starting and running the server as root would work but I’m not going to do that.
In the past, working with other stacks the solutions I’ve used have been:
-
Use apache/nginx which do have elevated permissions to start but then drop them.
-
Use rails or node (or what ever I’m building with) on a higher port and run nginx in front as a proxy. (though Jose has said there’s usually no need to run Phoenix behind nginx)
-
Use IP tables (and break ipv6)
Based on what I’ve seen online, the best solution may be to use setcap to give the binary permission to use the port. However I’ve tried that on erl, mix, iex and elixir and still can’t get the server to bind to port 80.
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/lib/erlan/bin/erl
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/lib/elixir/bin/mix
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/lib/elixir/bin/iex
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/lib/elixir/bin/elixir
$ MIX_ENV=prod PORT=80 mix phoenix.server
06:10:14.161 [error] Failed to start Ranch listener Myapp.Endpoint.HTTP in :ranch_tcp:listen([port: 80]) for reason :eacces (permission denied)
Any suggestions?
Most Liked
voltone
The executable that’s actually opening the port is the BEAM VM. Start iex in one window, then run ps aux | grep beam in another to see the details of the process. In my case, the executable is /usr/lib/erlang/erts-7.2/bin/beam.smp. Try setting the capabilities on that file instead.
Update: confirmed on Ubuntu 14.04.
$ sudo setcap 'cap_net_bind_service=+ep' /usr/lib/erlang/erts-7.2/bin/beam.smp
$ iex
Erlang/OTP 18 [erts-7.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.2.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :gen_tcp.listen(443, [])
{:ok, #Port<0.1426>}
iex(2)>
logicmason
Got it! I had to use setcap on a file distillery created called run_erl. On my system it was:
sudo setcap CAP_NET_BIND_SERVICE=+eip /home/ubuntu/myapp/_build/prod/rel/myapp/erts-8.1/bin/run_erl
Now I can start the web server from its run script and with just sudo start myapp (since I’d already created the /etc/init/myapp.conf script)
Wow this was a bit of a rabbit but it should be easier for the next person searching on google. Thanks @voltone
I’ll definitely keep your idea in mind too, @bobbypriambodo. Nginx is always a possibility in the future if I need it for filtering spammy requests to “admin.php” and other non-existent URLs that seem to be popular for bots to hit.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









