I have a Phoenix app deployed as a release. In order to allow this app to bind port 80 without running as root, I add the necessary linux capability to the beam with setcap 'cap_net_bind_service=+ep' ./erts-{version}/to/beam.smp
.
In order to find the path to beam.smp
I parse the output of elixir -v
to extract the erts version (using the Elixir installation used to build the release) and use that version number to construct the path to beam.smp
. Unfortunately this is not robust and has broken several times already because of slight changes in the output of elixir -v
.
What would be a reliable way to find the path to beam.smp
?
How about using your release to see which beam.smp
it is using?
I am sure there are better ways but one approach could be:
./bin/yourrelease eval "p = System.get_pid(); File.read_link!(:filename.join([\"/proc\", p, \"exe\"])) |> IO.puts"
The elixir code written a bit clearer is:
pid = System.get_pid()
symlink = :filename.join(["/proc", pid, "exe"])
name = File.read_link!(symlink)
IO.puts(name)
This looks what the running pid of the process is, then checks which executable is used by looking at /proc//exe
Perhaps there is an API which gives the exe straight away? But I couldn’t find any.
1 Like
Systemd afaik allows you to grant those permissions on a per unit manner. Maybe you don’t even need to set it manually.
2 Likes
Thank you both for these fantastic answers!
@cmkarlsson You gave me exactly what I was asking for. I had no idea it was possible to retrieve an executable form its PID like this. TIL I learnt something useful about /proc
!
@LostKobrakai You gave me exactly what I needed as I use systemd and hadn’t realized it could set capabilities like this. I’ve just added this to my systemd unit file and it does the trick:
AmbientCapabilities=CAP_NET_BIND_SERVICE
Again thank you so much for the Linux lesson 
1 Like