views:

8837

answers:

11

I'm in the process of maintaining a Ruby on Rails app and am looking for an easy way to find the hostname or IP address of the box I'm on (since it's a VM and new instances may have different hostnames or IP addresses). Is there a quick and easy way to do this in Ruby on Rails?

Edit: The answer below is correct but the clarification Craig provided is useful (see also provided link in answer):

The [below] code does NOT make a connection or send any packets (to 64.233.187.99 which is google). Since UDP is a stateless protocol connect() merely makes a system call which figures out how to route the packets based on the address and what interface (and therefore IP address) it should bind to. addr() returns an array containing the family (AF_INET), local port, and local address (which is what we want) of the socket.

+1  A: 

try: Request.remote_ip

remote_ip()

Determine originating IP address. REMOTE_ADDR is the standard but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR are set by proxies so check for these if REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma- delimited list in the case of multiple chained proxies; the last address which is not trusted is the originating IP.

Update: Oops, sorry I misread the documentation.

Craig
A: 

@Craig: Thanks for the quick response, but I'm not looking for the IP of the user visiting the page my app is on, I'm looking for the IP of the box my app is hosted on.

Chris Bunch
+1  A: 

Try this:

host = `hostname` # Get the hostname from the shell
puts host         # Output the hostname
John Topley
A: 

@John: That works, but since my hostname isn't set up with the DNS server it won't respond to requests for that hostname. Any ideas on getting the IP (or rather, anything easier than parsing out the response from 'ifconfig')?

Chris Bunch
+1  A: 

You will likely find yourself having multiple IP addresses on each machine (127.0.0.1, 192.168.0.1, etc). If you are using *NIX as your OS, I'd suggest using hostname, and then running a DNS look up on that. You should be able to use /etc/hosts to define the local hostname to resolve to the IP address for that machine. There is similar functionality on Windows, but I haven't used it since Windows 95 was the bleeding edge.

The other option would be to hit a lookup service like WhatIsMyIp.com. These guys will kick back your real-world IP address to you. This is also something that you can easily setup with a Perl script on a local server if you prefer. I believe 3 lines or so of code to output the remote IP from %ENV should cover you.

Jack M.
+6  A: 

From coderrr.wordpress.com:

require 'socket'

def local_ip
  orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily

  UDPSocket.open do |s|
    s.connect '64.233.187.99', 1
    s.addr.last
  end
ensure
  Socket.do_not_reverse_lookup = orig
end

# irb:0> local_ip
# => "192.168.0.127"
Titanous
Thanks a bunch! This worked perfectly for me :-)
Topher Fangio
+1  A: 

@Titanous/someone with more reputation:

Does someone want to add the explanation from Titanous link to Titanous correct answer, just to further explain it:

The above code does NOT make a connection or send any packets (to 64.233.187.99 which is google). Since UDP is a stateless protocol connect() merely makes a system call which figures out how to route the packets based on the address and what interface (and therefore IP address) it should bind to. addr() returns an array containing the family (AF_INET), local port, and local address (which is what we want) of the socket.

Craig
A: 

@Craig: Since I don't have the rep to add it to the answer, I added it to the question.

Chris Bunch
+2  A: 

A simple way to just get the hostname in ruby is:

require 'socket'
host = Socket.gethostname

The catch is that this relies on the host knowing its own name (it uses either the gethostname or uname system call), so it will not work for the original problem. Functionally this is identical to the hostname answer, without invoking an external program. The hostname may or may not be fully qualified, depending on the machine's configuration.

Tim Peters
+1  A: 

Put the highlighted part in backticks (sadly SO doesn't seem to handle the fact that backticks are legal Ruby :():

dig #{request.host} +short.strip # dig gives a newline at the end

Or just request.host if you don't care whether it's an IP or not.

Sai Emrys
A: 

Simplest is host_with_port in in controller.rb

host_port= request.host_with_port
Salil