55

As part of an installation script, I want to make an "educated guess" about the machines public IP address. It should be as robust as possible, working on a variety of hosts and platforms. Here is an example:

https://gist.github.com/4669037

This script uses 3 methods and then defaults to the value of /etc/hostname. I have only tested this on Ubuntu so far. Will this be likely to work on other distributions? And are there additional methods that I could add?

Jeroen Ooms
  • 31,998
  • 35
  • 134
  • 207
  • as long as curl is installed this should work in any distribution. – Dehalion Jan 29 '13 at 23:44
  • 1
    The answer below `curl ifconfig.me` is great. But I want fallback methods in case curl is not available or the ifconfig.me site is unavailable. – Jeroen Ooms Jan 30 '13 at 02:31
  • @ruakh the example script already has `2> /dev/null` in the curl line. Wouldn't that hide the curl error? – Jeroen Ooms Jan 30 '13 at 02:33
  • @Jeroen: Whoops, sorry, I somehow didn't see that. Never mind then. :-) – ruakh Jan 30 '13 at 06:35
  • See [this answer](http://unix.stackexchange.com/a/344997/7286) which has a script trying various DNS servers and HTTP services until it gets a reply. It uses `dig` or `curl` or `wget` (in that order) depending on which one it finds in the path. The list of servers is good as of Feb. 2017. – mivk Feb 14 '17 at 19:06

14 Answers14

106
curl ipinfo.io/ip

Or

wget -q -O - ipinfo.io/ip

Or

lynx -source ipinfo.io/ip

get public ip address

You can find other ip reporting websites instead of ipinfo.io as well. To name a few:

Also, what is my ip shows more information about that ip.

Pedram
  • 921
  • 1
  • 10
  • 17
Zombo
  • 1
  • 62
  • 391
  • 407
15

curl ifconfig.me would be the best choice, in case you don't have curl:

wget -qO- ifconfig.me/ip

Kent
  • 189,393
  • 32
  • 233
  • 301
  • 1
    That site is bad, compare [ifconfig.me status](http://wheresitup.com/results/5497718d8c3dcfc65cc8c06d) versus [ipinfo.io status](http://wheresitup.com/results/549771c48c3dcfdd5cc8c06a) – Zombo Dec 22 '14 at 01:22
6

If on an AWS EC2 you can use:

curl checkip.amazonaws.com

NOTE: this service can be used from any web client.

Eric Semwenda
  • 436
  • 6
  • 16
4

How much public public IP are you looking for? What if the machine is behind NAT?

  • curl / wget / netcat (nc) <URL> which contains requester's address: should work most of the time, but may the site may be unreachable from the machine (be it firewall or temporary/permanent unavailability). You'll get the most public IP you can.

  • ifconfig: must run as root, otherwise you'd have to try /sbin/ifconfig or /usr/sbin/ifconfig as well. What if the machine has more NICs? How do you tell what IP is the right one? What if only IPv6 is used on the machine's LAN? In any case, you'll get the least public IP you can (and possibly a wrong one if more interfaces are configured on the machine - which often is the case these days with omnipresent virtualization using network tap devices and/or).

  • /etc/hostname: does not need to exist, on many systems it is /etc/HOSTNAME, and it does not contain IP address rather it should contain the hostname (usually the FQDN).

The point is, that the ways in which it can fail are numerous and you probably should consider either a) specifying more precisely what systems you are targeting or b) whether you really need to know the IP at all - is a solution that seems to work in simple cases worth using when it fails miserably in slightly more complicated setup? If you think you need the IP, prepare a way to handle failures gracefully in cases where you either don't get the IP at all or you get a wrong one.

peterph
  • 980
  • 6
  • 11
  • The script will be run as root. Feel free to suggest a better way to extract the ip from `ifconfig` :-) – Jeroen Ooms Jan 30 '13 at 02:39
  • @Jeroen I don't think there is a "better" way :( - all of them are flawed in some manner (so you can't get a 100% working solution). See updated answer. – peterph Jan 30 '13 at 11:56
  • I am not expecting a perfect solution, I want a smart guess. The user will still be able to manually modify the value later. – Jeroen Ooms Jan 30 '13 at 19:22
3

I found my personal preferred method here:

  • dig +short myip.opendns.com @resolver1.opendns.com
  • dig +short txt ch whoami.cloudflare @1.0.0.1
  • dig +short txt o-o.myaddr.l.google.com @ns1.google.com
    • dig +short txt o-o.myaddr.l.google.com @ns1.google.com | awk -F'"' '{print $2}'
Brucelin Michael
  • 475
  • 4
  • 10
2

Try this command:

wget -O - -q icanhazip.com
MCurbelo
  • 4,097
  • 2
  • 26
  • 21
2

Using only bash (with help from icanhazip.com ):

exec 3<>/dev/tcp/icanhazip.com/80 
echo -e 'GET / HTTP/1.0\r\nhost: icanhazip.com\r\n\r' >&3 
while read i
do
 [ "$i" ] && myip="$i" 
done <&3 
echo "$myip"

bash opens open a socket to icanhazip and sends an http request, the IP address is returned on the last non-empty line of the data returned. (previous lines are http headers)

This avoids the need for http client like wget or curl.

Jasen
  • 11,837
  • 2
  • 30
  • 48
1

This solution doesn't work if you're behind nat or something. It helps without a 3rd party service. It works if the machine has the connection on it, like a server, or a ppp connection.

  • Not an exactly correct answer to question, but probably helps other people (like me)
  • Requires to be root in most (or all?) cases

You can get the (first) default route from route -n, find the interface it uses, and find the ip it has.

MAINIF=$( route -n | grep '^0\.0\.0\.0' | head -n 1 | awk '{print $NF}' )
IP=$( ifconfig $MAINIF | { IFS=' :';read r;read r r a r;echo $a; } )
Furkan Mustafa
  • 794
  • 7
  • 12
1

I use IPGrab because it's easy for me to remember.

curl http://ipgrab.io
Incogma
  • 61
  • 1
  • 1
0

Use curl to hit shtuff.it IP service

curl http://shtuff.it/myip/short
Zombo
  • 1
  • 62
  • 391
  • 407
Chris Montanaro
  • 16,948
  • 4
  • 20
  • 29
0

Use ipify API:

curl 'https://api.ipify.org?format=json'

Bash script:

#!/bin/bash

ip=$(curl -s https://api.ipify.org)
echo "My public IP address is: $ip"
RiccardoCh
  • 1,060
  • 1
  • 13
  • 24
  • `curl -s https://api.ipify.org` adds whitespace characters on the end. See [here](https://stackoverflow.com/a/68216522/3362244) for fix. – teuber789 Jul 01 '21 at 20:33
0

I was getting whitespace characters at the end of other commands:

$ curl -s https://api.ipify.org
255.255.255.255%

I found that using jsonip.com combined with jq got rid of this. This way, parsing the IP address is as easy as a jq expression:

$ curl -s https://jsonip.com | jq -r '.ip'
255.255.255.255

See this jq play.

teuber789
  • 1,527
  • 16
  • 28
0

The most reliable way is asking an outside web server to tell you what is your IP address, and the most reliable DNS servers in the world right now are owned by Cloudflare.

Here is what we are using in SlickStack:

SYSTEM_DIG_IPV4_ADDRESS=$(dig whoami.cloudflare ch txt @1.1.1.1 +short | awk -F'"' '{print $2}')
SYSTEM_DIG_IPV6_ADDRESS=$(dig whoami.cloudflare ch txt @2606:4700:4700::1111 +short | awk -F'"' '{print $2}')

Simplified from our previous method of checking the network interface:

SYSTEM_NETWORK_INTERFACE_IPV4=$(ip route get 1.1.1.1 | head -n1 | awk '{print $5}')
SYSTEM_NETWORK_INTERFACE_IPV6=$(ip -6 route get 2606:4700:4700::1111 | head -n1 | awk '{print $5}')
SYSTEM_NETWORK_INTERFACE_IPV4_SHOW=$(ip addr show "${SYSTEM_NETWORK_INTERFACE_IPV4}" | grep "inet " | awk '{ print $2;exit }' | cut -d/ -f1)
SYSTEM_NETWORK_INTERFACE_IPV6_SHOW=$(ip addr show "${SYSTEM_NETWORK_INTERFACE_IPV6}" | grep "inet6 " | awk '{ print $2;exit }' | cut -d/ -f1)

Ref: https://github.com/littlebizzy/slickstack/issues/171

Jesse Nickles
  • 1,435
  • 1
  • 17
  • 25
  • Thanks to @Brucelin for inspiring me to look for simpler methods, and this guy on GitHub for some other similar examples: https://gist.github.com/rkalkani/7428a8769f7cc6710c58680938dc5833 – Jesse Nickles Mar 07 '23 at 12:26
0

you can quickly get both external IPv4 and IPv6 in one shot :

curl -m 120 -w '\n' -sfL 'api{4,6}.ipify.org'   
xxx.15.xxx.255
2603:7000:xxxx:xxxx:xxxxx:xxxx:974a:84a9

-m 120 -w '\n' -sfL ::

- max time 120 seconds

- newlines after each URL

- silent
- fail fast
- follow redirects
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11