PassengerPreStart / prespawn fails for apps not reachable via 127.0.0.1
From svnmnt on September 15, 2013 15:02:16
What steps will reproduce the problem?
- configure virtual host example.com which is only reachable on public IP and not on 127.0.0.1
- add "PassengerPreStart http(s?)://example.com"
- restart apache
- rails app is not prestarted
alternative way:
- from above
- run "ruby prespawn http://example.com " from the command line
What is the expected output? What do you see instead?
I expect, that the app would have been prestarted. I see a "Connection refused" error. Details are given below.
What version of Phusion Passenger are you using? Which version of Rails? On what operating system?
Passenger Version: 4.0.17 Rails: 4.0.0 OS: FreeBSD 8.2 Please provide any additional information below. The httpd-error.log shows:
[...]/gems/passenger-4.0.17/helper-scripts/prespawn:105:in `initialize': Connection refused - connect(2) (Errno::ECONNREFUSED)
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:105:in `new'
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:105:in `connect'
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:112:in `connect'
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:86:in `socket'
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:90:in `head_request'
from [...]/gems/passenger-4.0.17/helper-scripts/prespawn:145:in `<main>'
The problem is that the connection is made to host '127.0.0.1' which is hard coded in the prespawn script. I've attached a patch which uses request_host instead of 127.0.0.1 for the connection.
Attachment: prespawn_fix.diff
Original issue: http://code.google.com/p/phusion-passenger/issues/detail?id=949
From honglilai on September 16, 2013 04:38:42
This fix is not the proper way to do it. If the host name in request_host points to a load balancer, or a DNS entry with multiple IP addresses, or generally not the local host, then it won't work properly.
A better way would be for Passenger to parse the web server config file and to truly pre-start processes instead of using the current make-an-internal-request-to-the-web-server route.
For now, you can solve this problem locally by sending a request to the correct IP address manually.
This just appeared in my Nginx+Passenger Redmine application. I don't listen to 127.0.0.1 and configure nginx via Passenger or rather via Passengerfile.json. I can only set "address" to a single address. Any pointers how I can avoid this error? Add something to nginx.conf? Anywhere else?
You can track the progress on this issue at: https://github.com/phusion/passenger/tree/prespawn_non_localhost
Hello,
The "progress article" is no longer valid it seems.
Was this ever fixed? We're suffering from this too and don't see why this limitation is imposed :(
Something to override the behavior at least would be terrific!
It's not fixed yet, unfortunately. The limitation is due to us not knowing to which ip passenger is bound to in apache and nginx integration modes.
Why not simply have an option to resolve the hostname? :)
We don't do that because the dns resolution for a hostname might point to a load balancer not the server passenger is installed on.
Thanks for feedback, but it could at least be provided as an option, it would help us so much :)
Why not an option to specify the IP address explicitly to be used in establishing the connection?
Modified prespawn script to try to connect to @uri.host if 127.0.0.1 and ::1 both failed, works for me nicely.
If this is bad for some reason would it help to introduce support for another uri scheme - ie http_ip://192.168.1.2/ - which would basically say 'ok, i know what i'm doing, let me' and provide me with the option I need (potentially checking that this is indeed ip interface on this machine)?
Current prespawn script i'm using:
class TCPPrespawnLocation < PrespawnLocation
def request_port
@uri.port
end
def connect
TCPSocket.new('127.0.0.1', request_port)
rescue Errno::ECONNREFUSED
begin
TCPSocket.new('::1', request_port)
rescue Errno::ECONNREFUSED
TCPSocket.new(@uri.host, request_port)
end
end
end
then in my prestart I put IP on which nginx is listening on:
passenger_pre_start http://<ip>/;