How to get the beam executable of a deployed release?

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 :slight_smile:

1 Like