I want to run a bunch of phoenix applications on unix domain sockets, and put a nginx reverse proxy in front of them. Plug.Cowboy can listen on a unix domain socket by passing a {:local PATH} to the ip parameter of the endpoint, and it works. Except there is a permission problem. The socket file is created with 0755 permission so my reverse proxy cannot connect to it.
Is there anyway to create the socket file with a more relaxed permission? I don’t want to change my umask. I can make it work by changing the permission manually after the application is up, but that kind of sucks.
I know that it sucks, but this is what manpage says:
When creating a new socket, the owner and group of the socket file are set according to the usual rules. The socket file has all permissions enabled, other than those that are turned off by the process umask(2).
The owner, group, and permissions of a pathname socket can be changed (using chown(2) and chmod(2)).
I understand, but I don’t have a good place to chmod the file. Before the endpoint start, there is no file. How do I know the enpoint has started, and to chmod accordingly? starting a Task to poll the file until it exists? that sucks.
I found another problem when using a Unix socket. It does not delete the file on start. I can do that in my startup script no problem, but what if the Endpoint crashed, but the whole BEAM process does not crash, the file will be there and preventing the Endpoint to startup.
About 2nd problem - there is no direct solution for that. It would highly depend on how you manage startup of your application. If you are using systemd then you could use cleanup action that runs after process shuts down or you could use socket activation instead. It highly depends on your configuration there.
For the second problem, my fear is the endpoint can crash then is restarted by the supervisor. Because the socket file would still be there, it will crash again into an endless loop. Systemd won’t know because the whole beam process is still there.
I think the best solution is to patch cowboy, so it will rm the socket file on startup, and make the permission to the socket file wide open. Http over unix domain socket is unspeced and only used behind reverse proxy. IMHO, it make the most sense this way.
Would it work to write a “GenServer sandwich” around the Endpoint? The first GS would do nothing on boot, but would register to receive callback on shutdown and delete the file. The second would set permissions on startup and do nothing on shutdown.
You could define the 3 processes in a supervisor so that if any of them crash, they all shutdown and reboot. There’s no patching involved in this approach.
If you do that via systemd.socket then systemd will be responsible for creating and deleting socket, so it will not end in endless loop.
You can do it on your own in Application.start/2 callback instead of patching Cowboy. Or as I said, you can do it via ExecStartPost= or ExecStopPost= directives.
Thanks @hauleth and @sb8244 . Let me try to contact the cowboy author and send a PR first. I think patching cowboy will provide least surprise for future users and I cannot think of any downsides.
I don’t know. The Cowboy maintainer does not want to have a default with permission wide open, and I think he has a point. So someone would have to pass the option from Phoenix to Plug to Cowboy then finally to Ranch.
Yes, that’s what I am looking for - whether there’s already an established way of passing appropriate options. Also, I did some tests and (at least by default) it seems that the socket is not removed so does this (automatic removal) require passing some options too?
I re-checked the linked issue thread and found “we added a post_listen_callback transport option in Ranch 2.1” there. Yet mine is 1.8:
Because cowboy >= 2.6.1 and < 2.9.0 depends on ranch ~> 1.7.1 and cowboy >= 2.9.0 depends on ranch 1.8.0, cowboy >= 2.6.1 requires ranch ~> 1.7.1 or 1.8.0.
And because plug_cowboy >= 2.2.0 depends on cowboy ~> 2.7, plug_cowboy >= 2.2.0 requires ranch ~> 1.7.1 or 1.8.0.
And because your app depends on plug_cowboy ~> 2.5, ranch ~> 1.7.1 or 1.8.0 is required.
so that explains the ineffectiveness of the chmod part. How did you resolve this? What were your set of dependencies when testing this feature?