347

I need to find my external IP address from a shell script. At the moment I use this function:

myip () {
    lwp-request -o text checkip.dyndns.org | awk '{ print $NF }'
}

But it relies on perl-libwww, perl-html-format, and perl-html-tree being installed.

What other ways can I get my external IP?

27 Answers27

563

I'd recommend getting it directly from a DNS server.

Most of the other answers below all involve going over HTTP to a remote server. Some of them required parsing of the output, or relied on the User-Agent header to make the server respond in plain text. Those change quite frequently (go down, change their name, put up ads, might change output format etc.).

  1. The DNS response protocol is standardised (the format will stay compatible).
  2. Historically, DNS services (Akamai, Google Public DNS, OpenDNS, ..) tend to survive much longer and are more stable, more scalable, and generally more looked-after than whatever new hip whatismyip dot-com HTTP service is hot today.
  3. This method is inherently faster (be it only by a few milliseconds!).

Using dig with an OpenDNS resolver:

$ dig @resolver4.opendns.com myip.opendns.com +short

Perhaps alias it in your bashrc so it's easy to remember

# https://unix.stackexchange.com/a/81699/37512
alias wanip='dig @resolver4.opendns.com myip.opendns.com +short' 
alias wanip4='dig @resolver4.opendns.com myip.opendns.com +short -4'
alias wanip6='dig @resolver1.ipv6-sandbox.opendns.com AAAA myip.opendns.com +short -6'

Responds with a plain ip address:

$ wanip # wanip4, or wanip6
80.100.192.168 # or, 2606:4700:4700::1111

Syntax

(Abbreviated from https://ss64.com/bash/dig.html):

usage:  dig [@global-dnsserver] [q-type] <hostname> <d-opt> [q-opt]
q-type   one of (A, ANY, AAAA, TXT, MX, ...). Default: A.

d-opt    ...
         +[no]short          (Display nothing except short form of answer)
         ...

q-opt    one of:
         -4                  (use IPv4 query transport only)
         -6                  (use IPv6 query transport only)
         ...

The ANY query type returns either an AAAA or an A record. To prefer IPv4 or IPv6 connection specifically, use the -4 or -6 options accordingly.

To require the response be an IPv4 address, replace ANY with A; for IPv6, replace it with AAAA. Note that it can only return the address used for the connection. For example, when connecting over IPv6, it cannot return the A address.

Alternative servers

Various DNS providers offer this service, including OpenDNS, Akamai, and Google Public DNS:

# OpenDNS (since 2009)
$ dig @resolver3.opendns.com myip.opendns.com +short
$ dig @resolver4.opendns.com myip.opendns.com +short
80.100.192.168

OpenDNS IPv6

$ dig @resolver1.ipv6-sandbox.opendns.com AAAA myip.opendns.com +short -6 2606:4700:4700::1111

Akamai (since 2009)

$ dig @ns1-1.akamaitech.net ANY whoami.akamai.net +short 80.100.192.168

Akamai approximate

NOTE: This returns only an approximate IP from your block,

but has the benefit of working with private DNS proxies.

$ dig +short TXT whoami.ds.akahelp.net "ip" "80.100.192.160"

Google (since 2010)

Supports IPv6 + IPv4, use -4 or -6 to force one.

$ dig @ns1.google.com TXT o-o.myaddr.l.google.com +short "80.100.192.168"

Example alias that specifically requests an IPv4 address:

# https://unix.stackexchange.com/a/81699/37512
alias wanip4='dig @resolver4.opendns.com myip.opendns.com +short -4'

$ wanip4 80.100.192.168

And for your IPv6 address:

# https://unix.stackexchange.com/a/81699/37512
alias wanip6='dig @ns1.google.com TXT o-o.myaddr.l.google.com +short -6'

$ wanip6 "2606:4700:4700::1111"

Troubleshooting

If the command is not working for some reason, there may be a network problem. Try one of the alternatives above first.

If you suspect a different issue (with the upstream provider, the command-line tool, or something else) then run the command without the +short option to reveal the details of the DNS query. For example:

$ dig @resolver4.opendns.com myip.opendns.com

;; Got answer: ->>HEADER<<- opcode: QUERY, status: NOERROR

;; QUESTION SECTION: ;myip.opendns.com. IN A

;; ANSWER SECTION: myip.opendns.com. 0 IN A 80.100.192.168

;; Query time: 4 msec

Timo Tijhof
  • 7,170
  • 21
    you are right it's too fast.. – Rahul Patil Jul 09 '13 at 16:24
  • sounds like a good approach, but as of now, for my current IP in indonesia, it returns no result, whereas http based mechanisms are working. – mc0e Oct 19 '14 at 05:17
  • 5
    @Krinkle that's an excellent answer. Is there an equivalent for myip.opendns.com in Googles Public DNS ? – Kannan Mohan Oct 26 '14 at 05:11
  • 16
    I found this to be ~19x faster than curl http://canhazip.com. See http://askubuntu.com/a/427092/2273 – Adam Monsen Mar 10 '15 at 21:09
  • 4
    Love this clean / no dependencies approach much better than all other proposals, unless you're bound to port 80 – binaryanomaly Mar 14 '15 at 15:27
  • 1
    Very useful answer, working great when programmatically doing a DNS lookup as well. I would definitely rely on resolver1.opendns.com more than the random "getmyip" type websites. The only thing I don't like is any official documentation on this feature, though I trust it won't disappear anytime soon. I would also like to know if any other DNS servers have a similar feature, like Googles? – Nicholi Mar 24 '15 at 23:20
  • This didn't work for me on my rackspace cloud server.. it returned the LAN IP for some reason, whereas using whatismijnip.nl (the next answer) worked correctly. I'm not sure why this is but this is certainly worth taking into account. – John Hunt Apr 14 '15 at 10:28
  • Are there any other providers for this method? Also, how does it compare to the nslookup . ifcfg.me method as in Eun's comment above? Isn't that also using DNS? – James Haigh Apr 29 '15 at 08:23
  • 3
    @JamesHaigh < they are plenty of providers, see http://serverfault.com/a/560059 – bufh Jun 11 '15 at 21:31
  • 2
    It's more elegant to put bash aliases in ~/.bash_aliases instead directly placing them in ~/.bashrc. – patryk.beza Jul 25 '15 at 11:22
  • 3
    upvoted for sheer elegance and flawless reasoning. (however, for super pointless geek mode, i changed the cmd order to match the man page) – underscore_d Sep 28 '15 at 20:09
  • 1
    Upvoted because it has the least dependencies. Dig seems to be present on almost any system in comparison to curl, externalip, wget, .... etc. – cb0 Oct 29 '15 at 08:24
  • 6
    Please note that in some cases the routers that provide NAT will also translate DNS responses (you can take a look at http://wiki.nil.com/Network_address_translation_of_DNS_responses); in this case you should fallback to some answer that recommends other approach than DNS. – Razvan Stefanescu Oct 30 '15 at 16:20
  • 2
    This doesn't work when behind my company proxy. – wisbucky Mar 27 '17 at 18:07
  • ip route get 8.8.8.8 | head -1 | cut -d" " -f8 should do. – tonythomas01 Feb 07 '18 at 13:20
  • 1
    @tonythomas01 ip route get 8.8.8.8 | awk '{print $NF; exit}' – jfs Apr 17 '18 at 08:30
  • can you elaborate on that command scheme ? do other servers also support "myip." ? – elig Sep 19 '18 at 22:34
  • @elig The protocol being used is standard DNS. The name "myip" is not part of this principle, rather it is only the name of a specific OpenDNS.com service. If other providers also offer this service, they may use a different subdomain name. – Timo Tijhof Sep 21 '18 at 15:53
  • 1
    For IPv6: dig +short myip.opendns.com AAAA @resolver1.ipv6-sandbox.opendns.com – Martin Sep 29 '18 at 11:01
  • This is so fast! But what is wan though? – attomos Oct 05 '18 at 03:41
  • No longer get a response on DiG 9.12.3 on OSX. Someone has the same problem? – lony Nov 10 '18 at 18:02
  • @lony I've had the same issue. I've updated the command to explicitly request the "AAAA" record over DNS (previously implied), and now it works again. This also matches recommendations from the OpenDNS support community. – Timo Tijhof Nov 13 '18 at 01:41
  • 2
    You will probably want to add +tcp to the dig command, to prevent funny results from intermediate boxes – V13 Nov 13 '18 at 02:03
  • I assumed AAAA is only needed if I use IPv6. Even with it, I do not have a consistent result both at work and at home. Sometimes it works with and sometimes without :( – lony Nov 13 '18 at 12:07
  • The myip.opendns.com method is no longer working (at least for me). – starbeamrainbowlabs Dec 12 '20 at 13:12
  • 1
    @starbeamrainbowlabs Thanks, I've updated it to use resolver4.opendns.com instead of resolver1.opendns.com. Be sure to check the "Alternatives servers" as well! – Timo Tijhof Dec 16 '20 at 00:03
195

NOTE: This is about external IP address (the one that the servers on the Internet see when you connect to them) - if you want internal IP address (the one that your own computer is using for connections, which may be different) see this answer.

TL;DR - Fastest methods in 2015

The fastest method using DNS:

dig +short myip.opendns.com @resolver4.opendns.com

or using externalip:

externalip dns

The fastest using HTTP:

curl -s http://whatismyip.akamai.com/

or using externalip:

externalip http

The fastest using HTTPS with a valid cert:

curl -s https://4.ifcfg.me/

or using externalip:

externalip https

Using telnet:

With nc command:

nc 4.ifcfg.me 23 | grep IPv4 | cut -d' ' -f4

or using externalip:

externalip telnet

With telnet command:

telnet 4.ifcfg.me 2>&1 | grep IPv4 | cut -d' ' -f4

Using FTP:

echo close | ftp 4.ifcfg.me | awk '{print $4; exit}'

or using externalip:

externalip ftp

All of the above can be run using my externalip script as:

externalip dns
externalip http
externalip https
externalip telnet
externalip ftp

Now a long story...

There are a lot of options of different servers providing the external IP especially via HTTP posted here or elsewhere.

I made a benchmark to see if any of them are better than the others and I was surprised by the results. E.g. one of the most widely recommended ifconfig.me was almost always the slowest for me, sometimes taking many seconds to respond. Many don't work over HTTPS, or do work but have invalid certificates. Some have very inconsistent response times.

Benchmarks

HTTP and HTTPS

This is the source of my externalip-benchmark script that I used:

You can run it yourself to see which services mentioned here are worth using:

wget https://raw.githubusercontent.com/rsp/scripts/master/externalip-benchmark
chmod a+x externalip-benchmark
./externalip-benchmark

My results that I got on 2015-04-03 from Warsaw - the addresses have been changed to protect the innocent:

Best http response times:

0.086s http://ip.tyk.nu/ - answer='172.31.133.7'
0.089s http://whatismyip.akamai.com/ - answer='172.31.133.7'
0.091s http://tnx.nl/ip - answer='172.31.133.7'
0.117s http://ifcfg.me/ - answer='172.31.133.7'
0.156s http://l2.io/ip - answer='172.31.133.7'
0.317s http://ip.appspot.com/ - answer='172.31.133.7'
0.336s http://ident.me/ - answer='172.31.133.7'
0.338s http://ipof.in/txt - answer='172.31.133.7'
0.347s http://icanhazip.com/ - answer='172.31.133.7'
0.496s http://curlmyip.com/ - answer='172.31.133.7'
0.527s http://wgetip.com/ - answer='172.31.133.7'
0.548s http://curlmyip.com/ - answer='172.31.133.7'
0.665s http://bot.whatismyipaddress.com/ - answer='172.31.133.7'
0.665s http://eth0.me/ - answer='172.31.133.7'
1.041s http://ifconfig.me/ - answer='172.31.133.7'
1.049s http://corz.org/ip - answer='172.31.133.7'
1.598s http://ipecho.net/plain - answer='172.31.133.7'

Best https response times:

0.028s https://curlmyip.com/ - answer=''
0.028s https://curlmyip.com/ - answer=''
0.029s https://l2.io/ip - answer=''
0.029s https://tnx.nl/ip - answer=''
0.072s https://whatismyip.akamai.com/ - answer=''
0.113s https://ipecho.net/plain - answer=''
0.117s https://ident.me/ - answer=''
0.207s https://ip.tyk.nu/ - answer='172.31.133.7'
0.214s https://ipof.in/txt - answer='172.31.133.7'
0.259s https://ifcfg.me/ - answer='172.31.133.7'
0.289s https://corz.org/ip - answer=''
0.436s https://ip.appspot.com/ - answer='172.31.133.7'
0.448s https://bot.whatismyipaddress.com/ - answer=''
0.454s https://eth0.me/ - answer=''
0.673s https://icanhazip.com/ - answer='172.31.133.7'
5.255s https://ifconfig.me/ - answer=''
10.000s https://wgetip.com/ - answer=''

(Note: there are some fast responses with empty content - those are invalid.)

Best average ping times:

10.210 //whatismyip.akamai.com/
36.820 //tnx.nl/ip
37.169 //ip.tyk.nu/
39.412 //ipof.in/txt
40.967 //ident.me/
41.257 //ipecho.net/plain
43.918 //ifcfg.me/
45.720 //l2.io/ip
64.749 //ip.appspot.com/
123.412 //corz.org/ip
134.245 //wgetip.com/
157.997 //icanhazip.com/
161.613 //curlmyip.com/
162.100 //curlmyip.com/
268.734 //ifconfig.me/
999999 //bot.whatismyipaddress.com/
999999 //eth0.me/

Here are the results that I got on 2015-04-03 from Amsterdam:

Best http response times:

0.021s http://ipecho.net/plain - answer='172.31.13.37'
0.027s http://tnx.nl/ip - answer='172.31.13.37'
0.035s http://whatismyip.akamai.com/ - answer='172.31.13.37'
0.039s http://ifcfg.me/ - answer='172.31.13.37'
0.045s http://l2.io/ip - answer='172.31.13.37'
0.142s http://ident.me/ - answer='172.31.13.37'
0.144s http://ipof.in/txt - answer='172.31.13.37'
0.150s http://ip.appspot.com/ - answer='172.31.13.37'
0.150s http://ip.tyk.nu/ - answer='172.31.13.37'
0.170s http://icanhazip.com/ - answer='172.31.13.37'
0.190s http://eth0.me/ - answer='172.31.13.37'
0.191s http://wgetip.com/ - answer='172.31.13.37'
0.301s http://curlmyip.com/ - answer='172.31.13.37'
0.330s http://bot.whatismyipaddress.com/ - answer='172.31.13.37'
0.343s http://curlmyip.com/ - answer='172.31.13.37'
0.485s http://corz.org/ip - answer='172.31.13.37'
3.549s http://ifconfig.me/ - answer='172.31.13.37'

Best https response times:

0.004s https://curlmyip.com/ - answer=''
0.012s https://curlmyip.com/ - answer=''
0.012s https://tnx.nl/ip - answer=''
0.016s https://ipecho.net/plain - answer=''
0.071s https://whatismyip.akamai.com/ - answer=''
0.096s https://ifcfg.me/ - answer='172.31.13.37'
0.097s https://ident.me/ - answer=''
0.187s https://corz.org/ip - answer=''
0.187s https://ip.appspot.com/ - answer='172.31.13.37'
0.189s https://ip.tyk.nu/ - answer='172.31.13.37'
0.195s https://eth0.me/ - answer=''
0.253s https://l2.io/ip - answer=''
0.300s https://ipof.in/txt - answer='172.31.13.37'
0.324s https://bot.whatismyipaddress.com/ - answer=''
0.512s https://icanhazip.com/ - answer='172.31.13.37'
1.272s https://ifconfig.me/ - answer=''
10.002s https://wgetip.com/ - answer=''

Best average ping times:

1.020 //ipecho.net/plain
1.087 //whatismyip.akamai.com/
5.011 //ip.appspot.com/
6.942 //ident.me/
7.017 //ipof.in/txt
8.209 //tnx.nl/ip
11.343 //ip.tyk.nu/
12.647 //ifcfg.me/
13.828 //l2.io/ip
81.642 //icanhazip.com/
85.447 //wgetip.com/
91.473 //corz.org/ip
102.569 //curlmyip.com/
102.627 //curlmyip.com/
247.052 //ifconfig.me/
999999 //bot.whatismyipaddress.com/
999999 //eth0.me/

(The 999999 pings mean 100% packet loss.)

DNS

For a comparison here are times that other methods take - tested on 2015-06-16 from Warsaw and Amsterdam.

Using:

time dig +short myip.opendns.com @resolver1.opendns.com

usually takes (real wall clock time) about:

  • 0.035s from Warsaw
  • 0.015s from Amsterdam

There are actually four resolvers that can be used this way:

  • resolver1.opendns.com
  • resolver2.opendns.com
  • resolver3.opendns.com
  • resolver4.opendns.com

They all give the same response times in Warsaw and Amsterdam but this may not be the case in other locations.

Using 208.67.222.222 - the IP of resolver1.opendns.com instead of its domain name is faster:

  • 0.023s from Warsaw
  • 0.009s from Amsterdam

but may not work in the future if the IP ever changes (though it may be unlikely for a well known DNS resolver - maybe I should use the IP in my externalip script - please comment).

Telnet

Telnet with nc or telnet command (see above) usually takes:

  • 0.103s from Warsaw
  • 0.035s from Amsterdam

(There is no noticeable difference between nc and telnet commands.)

FTP

  • 0.104s from Warsaw
  • 0.036s from Amsterdam

Domain names

All of the methods will be faster (especially when run for the first time) when IP addresses will be used instead of the domain names of the given services (except with HTTP that can use host-based virtual servers and not work with bare IP - not tested) but will stop working when the services change the IP address so it may be faster but less future-proof.

Comments

If you see some interesting results from your location, or if you think that some other hosts should be recommended instead of those that I've chosen, please post a comment. If there is any important service missing, please comment or post an issue on GitHub. I'd like to keep this post updated with a current choice of best-performing services.

Timo Tijhof
  • 7,170
rsp
  • 3,416
  • 2
    Did you benchmark the myip.opendns.com DNS method as in Krinkle's answer? Currently it seems that it's winner-by-default due to being unaware of any other providers for this method, but it would still be useful to compare with the other methods. – James Haigh Apr 29 '15 at 08:16
  • @JamesHaigh Thanks for the suggestion. I added DNS and other methods (telnet, ftp) to the answer. The fastest method seems to be DNS using directly the IP address (instead of the domain name) of the resolver. – rsp Jun 16 '15 at 15:13
  • You should add/test http://canhazip.com / https://canhazip.com as well (HTTP and HTTPS). – xxdesmus Aug 22 '15 at 16:15
  • You can add http://myip.addr.space/ to your list. I built this myself as I wasn't particularly satisfied with any of the others I had seen at the time. – Michael Hampton May 07 '16 at 04:07
  • Sometimes I get different results using dig +short myip.opendns.com @resolver1.opendns.com (36.86.63.180), dig -4 @ns1-1.akamaitech.net -t a whoami.akamai.net +short (118.98.115.34), and curl http://canhazip.com (36.71.64.71). How can I decide which one is correct? – Sutandiono Sep 12 '16 at 03:10
  • On 14 Feb 2017, these aslo worked: 4.ifcfg.me, alma.ch/myip.cgi, api.infoip.io/ip, api.ipify.org, canhazip.com, checkip.amazonaws.com, ipinfo.io/ip, myip.addr.space, smart-ip.net/myip. The following did not work: corz.org/ip, curlmyip.com, ifcfg.me, ifconfig.me, ip.appspot.com. – mivk Feb 14 '17 at 13:17
  • 4.ifcfg.me is down, at least currently. – Torsten Bronger Aug 22 '18 at 06:35
  • telnet/nc with 4.ifcfg.me is not working anymore as of 2018 – elig Sep 19 '18 at 22:38
  • The only method that works now is http – Seamus Feb 21 '19 at 11:09
82
 curl -s http://whatismijnip.nl |cut -d " " -f 5

Replaced site with dutch working one.

  • 2
    @MaciekSawicki Is the -s option really necessary in this case? I tried with/without it in my fedora 15 - bash 4.2.10(1) and it worked in both ways. – ztank1013 Oct 15 '11 at 14:05
  • 4
    Doesn't seem to work anymore via CLI, but going to the webpage from a web browser works. I'm using openSUSE 12.1 x64. – SaultDon Aug 16 '12 at 16:13
  • 5
    whatismyip.com has removed the free service to check external IP. So, I'm afraid this is no longer correct. icanhazip.com still works. – daSong Jan 17 '13 at 10:20
  • @daSong Don't you mean whatismyip.org? – Cory Klein Nov 25 '13 at 19:30
  • Some alternatives: curl ifconfig.me, curl icanhazip.com, curl ipecho.net/plain, curl ifconfig.co, but remember that using this for automation is highly insecure (the owners of these sites can always change the output later in the future without you knowing), so use the dig method instead if you can. – Mahn Jan 08 '20 at 18:25
59

Since whatsmyip.org and ifconfig.me have already been mentioned:

curl -s icanhazip.com
joschi
  • 834
23

Amazon AWS

curl https://checkip.amazonaws.com

Sample output:

123.123.123.123

Also works on browser: http://checkip.amazonaws.com

I like it because:

  • it returns just the plaintext IP in the reply body, nothing else
  • it is from a well known provider which is unlikely to go offline anytime soon
Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
19

You can use ifconfig.me as alternative to whatismyip.org.

curl -s http://ifconfig.me

Also ifconfig.me has some additional functional. To find out what else information you can receive visit the website.

Chris Down
  • 125,559
  • 25
  • 270
  • 266
14
wget -O - -q http://whatismyip.org/
ztank1013
  • 2,221
  • 2
  • 14
  • 14
  • 3
    I was not able to get my IP like this, just gives it as:<img src='ipimg.php'/> – Yuugian Apr 04 '13 at 13:38
  • Got it working with some decent lot of regex magic, but it wasn't easy. Should you insist on using this service, be sure to wrap that line into a script: $ curl -s http://whatismyip.org | grep -o '\([[:digit:]]\{1,3\}\.\)\{3\}[[:digit:]]\{1,3\}' – syntaxerror Feb 01 '16 at 02:40
  • In 2023, this returns 403 Forbidden. – RonJohn Apr 01 '23 at 07:48
9
curl ident.me

OR

curl ifconfig.me

OR

curl https://tnx.nl/ip

OR

curl ipecho.net/plain

OR

curl whatismyip.akamai.com

OR

curl icanhazip.com

OR

curl wgetip.com

OR

curl ip.tyk.nu

OR

curl bot.whatismyipaddress.com

Reference

9
netcat icanhazip.com 80 <<< $'GET / HTTP/1.1\nHost: icanhazip.com\n\n' | tail -n1
  • Blank output here, although the site works. Any idea why? I am behind a proxy, if that's relevant, but wget icanhazip.com works. – l0b0 Apr 04 '13 at 11:23
  • @l0b0 Try to omit the | tail -n1 part and see what you get from the proxy – Eugene Yarmash Apr 04 '13 at 13:18
  • Nothing, just exit code 1. Ditto for netcat icanhazip.com 80. Looks like it ignores $http_proxy and friends, because specifying the proxy and port with -x just resulted in a hanging process. – l0b0 Apr 04 '13 at 14:05
  • @l0b0: netcat proxy 3128 <<<$'GET http://icanhazip.com/ HTTP/1.0\n\n' | tail -n 1 for a basic HTTP proxy (assuming it's running on port 3128). You will obviously get the IP address of the proxy back, though. – tripleee Jul 04 '13 at 04:07
  • 1
    HTTP 1.0 does not have the Host: request header - name-based virtual hosting was one of the major improvements in HTTP 1.1. Either change the request to specify HTTP/1.1, or remove the Host header (I recommend the former). – user Jul 04 '13 at 07:39
  • @MichaelKjörling actually, HTTP 1.0 does have the Host header, unlike HTTP 0.9. The change in HTTP 1.1 is that the Host header was made mandatory. – mc0e Oct 19 '14 at 05:23
  • @mc0e Citation needed. RFC 1945 does not seem to mention any Host: header, although from a google search it appears that some server and proxy software make use of it if it exists. Section 7.1 of that RFC allows for extension-header so the use of a Host: header is not disallowed in HTTP 1.0, although as far as I can tell it is not specified by the HTTP 1.0 standard either. That said, yes, HTTP 1.1 did make it mandatory (RFC 2616 section 14.23). – user Oct 19 '14 at 13:08
  • @MichaelKjörling Hmm. Looking into this, I can't find much to supportthat position, and I guess my memory of it is hazy. Maybe what I'm remembering was a period where HTTP/1.1 had been announced, but not generally implemented, but the host header was adopted by apps that claimed to be HTTP/1.0. I wanted to check the changelog for Squid just now, but can't find much that's older than version 2.4. – mc0e Oct 19 '14 at 13:42
  • The earliest reference I've found is that Apache 1.1b3 was using the host header for virtualhosts which was around june 1996. (ref) RFC 1945 (HTTP/1.0 formalisation) was published in May 1996. It's worth understanding that when RFC 1945 came out, the actual practice was well ahead of the formal specs. To put this in perspective, this is about when the FORM tag was new in HTML. Netscape and IE defined the defacto standard. Netscape 2.0 introduced support for the Host header (and the FORM tag) in late 1996 I think? – mc0e Oct 19 '14 at 14:19
  • @mc0e It's quite possible that you are correct in that the Host header was generally used by UAs and servers at that time, but that doesn't mean that HTTP 1.0 specified the header. Which I believe means we are pretty much in agreement. – user Oct 19 '14 at 14:32
  • Yes, you're right. Should I delete that comment, or is the discussion worth keeping the context? RFC formalisation of the mandatory Host header goes back to at least RFC2068 though in jan 97. I haven't found anything on when apps started to claim to use HTTP/1.1. – mc0e Oct 19 '14 at 14:51
9

If after reading all these suggestions you want to read even more, here is an arguably over-engineered Bash script.

It contains a list of DNS and HTTP servers which seem to work fine as of February 2017.

If you have dig, it first tries DNS which is almost an order of magnitude faster that the various HTTP services.

It exits at the first reply it gets.

If you don't have dig or if all DNS servers failed, it then tries the HTTP services until it gets a reply.

The servers are listed alphabetically, but are shuffled before use to avoid always using the same one.

#!/bin/bash

## Get my external IP

timeout=2   # seconds to wait for a reply before trying next server
verbose=1   # prints which server was used to STDERR

dnslist=(
    "dig +short            myip.opendns.com        @resolver1.opendns.com"
    "dig +short            myip.opendns.com        @resolver2.opendns.com"
    "dig +short            myip.opendns.com        @resolver3.opendns.com"
    "dig +short            myip.opendns.com        @resolver4.opendns.com"
    "dig +short    -t txt  o-o.myaddr.l.google.com @ns1.google.com"
    "dig +short -4 -t a    whoami.akamai.net       @ns1-1.akamaitech.net"
    "dig +short            whoami.akamai.net       @ns1-1.akamaitech.net"
)

httplist=(
    4.ifcfg.me
    alma.ch/myip.cgi
    api.infoip.io/ip
    api.ipify.org
    bot.whatismyipaddress.com
    canhazip.com
    checkip.amazonaws.com
    eth0.me
    icanhazip.com
    ident.me
    ipecho.net/plain
    ipinfo.io/ip
    ipof.in/txt
    ip.tyk.nu
    l2.io/ip
    smart-ip.net/myip
    tnx.nl/ip
    wgetip.com
    whatismyip.akamai.com
)



# function to shuffle the global array "array"
shuffle() {
   local i tmp size max rand
   size=${#array[*]}
   max=$(( 32768 / size * size ))
   for ((i=size-1; i>0; i--)); do
      while (( (rand=$RANDOM) >= max )); do :; done
      rand=$(( rand % (i+1) ))
      tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp
   done
}


## if we have dig and a list of dns methods, try that first
if hash dig 2>/dev/null && [ ${#dnslist[*]} -gt 0 ]; then
    eval array=( \"\${dnslist[@]}\" )
    shuffle

    for cmd in "${array[@]}"; do
        [ "$verbose" == 1 ] && echo Trying: $cmd 1>&2
        ip=$(timeout $timeout $cmd)
        if [ -n "$ip" ]; then
            echo $ip
            exit
        fi
    done
fi


# if we haven't succeeded with DNS, try HTTP

if [ ${#httplist[*]} == 0 ]; then
    echo "No hosts in httplist array!" >&2
    exit 1
fi

# use curl or wget, depending on which one we find
curl_or_wget=$(if hash curl 2>/dev/null; then echo "curl -s"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi);

if [ -z "$curl_or_wget" ]; then
    echo "Neither curl nor wget found. Cannot use http method." >&2
    exit 1
fi

eval array=( \"\${httplist[@]}\" )
shuffle

for url in "${array[@]}"; do
    [ "$verbose" == 1 ] && echo Trying: $curl_or_wget  "$url" 1>&2
    ip=$(timeout $timeout $curl_or_wget "$url")
    if [ -n "$ip" ]; then
        echo $ip
        exit
    fi
done

Sample usage (I called the script myip):

$ myip
Trying: dig +short -t txt o-o.myaddr.l.google.com @ns1.google.com
"151.101.65.69"

$ ip=$(myip); echo "IP = '$ip'"
Trying: dig +short myip.opendns.com @resolver1.opendns.com
IP = '151.101.65.69'

Comment out the verbose variable at the top of the script to avoid printing the server used.

Update: this script is now also on Github where I might update it when needed:
https://github.com/mivk/myip

mivk
  • 3,596
7

I prefer to use curlmyip.com It's as simple as:

curl curlmyip.com

It's short and simple to remember.

  • For use in bash —the intent of the OP—, you cannot do without the -s option mentioned in other answers. – Serge Stroobandt Jul 20 '14 at 11:53
  • 4
    @SergeStroobandt Yes you can. All the -s switch does is run it in silent mode, ie. error messages won't be displayed. So it comes down to how he wants his script to handle errors. The command itself will return an IP address as reliably as using the -s. – Garrett Fogerlie Jul 24 '14 at 22:48
  • 1
    So far, this site was the most reliable one in multiple tests. – Capt. Crunch Dec 12 '14 at 09:05
4

This always works for me, I use it in my conky to get my IP address.

wget -q -O - checkip.dyndns.org | sed -e 's/[^[:digit:]\|.]//g'
jasonwryan
  • 73,126
  • +1 Albeit looking so clumsy, this approach has been a life-saver for me too a few times. Because Internet is not WWW. You can have internet access, but you may (commonly in server rooms) be doomed to a non-GUI console, and in this case it's important to remember by heart one of the checkIP service URLs. And as this one is pretty common, it's only seemingly compilcated, as you will be more likely to remember the DynDNS one than the one of amazonaws. That is, if you have NO way to google for it. (not even lynx). – syntaxerror Feb 01 '16 at 02:24
3

Since I don't rely on the connection or on the service, I use the following code, which tries to get the IP using different services (feel free to add more):

# Get my ip address and put in a file
declare -a arr=("ipecho.net/plain" "ident.me" "tnx.nl/ip" "ip.appspot.com" "https://shtuff.it/myip/short/")
IP=$(curl -s --retry 3 --retry-delay 10 ipecho.net/plain)

while [ -z "$IP" ] # If no IP found yet, keep trying!
do
    sleep 30
    IP=$(curl -s --retry 3 --retry-delay 10 ${arr[$((  RANDOM % ${#arr[@]}  ))]})  
done

echo -n "$IP" >  /root/clientIP.txt #puts ip address in clientIP.txt
echo "Our address is $IP" 

To add more robustness (e.g. if one of the services changes their format), you could check that $IP is a valid IP using the following function:

# Verify that the parameter passed is an IP Address:
# http://zindilis.com/blog/2013/05/10/bash-check-that-string-is-ip.html
# @Author: Marios Zindilis
# @License: Creative Commons Attribution-ShareAlike 4.0 International License.
# @Date: 2013-05-10
function is_IP() {
if [ `echo $1 | grep -o '\.' | wc -l` -ne 3 ]; then
        echo "Parameter '$1' does not look like an IP Address (does not contain 3 dots).";
        exit 1;
elif [ `echo $1 | tr '.' ' ' | wc -w` -ne 4 ]; then
        echo "Parameter '$1' does not look like an IP Address (does not contain 4 octets).";
        exit 1;
else
        for OCTET in `echo $1 | tr '.' ' '`; do
                if ! [[ $OCTET =~ ^[0-9]+$ ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' is not numeric).";
                        exit 1;
                elif [[ $OCTET -lt 0 || $OCTET -gt 255 ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' in not in range 0-255).";
                        exit 1;
                fi
        done
fi

return 0;
}
3

ifcfg.me supports:

curl ifcfg.me
nslookup . ifcfg.me
telnet ifcfg.me
ftp ifcfg.me
finger @ifcfg.me

IPv4 and IPv6, even more stuff with curl: ifcfg.me/?

Eun
  • 131
  • 4
3

If you want to use HTTPS to avoid some potential pitfalls:

_result=$(wget -qO- https://ipcheckit.com/)
_result="${_result##*Your IP address is<br><b>}"
printf '%s\n' "${_result%%</b></p>*}"
Chris Down
  • 125,559
  • 25
  • 270
  • 266
2

I run a cloud service for my family and I made this quick script I run in a cron every morning at 5 because I am cheap an will not buy a static IP.

It grabs the public IP, and emails it to my users. Made it email in hyperlink format so my Mom does not have to type the ports or anything. Maybe someone else can use it to.

#!/bin/bash
ipvariable=$(wget http://ipecho.net/plain -O - -q);

echo "Today the location is http://$ipvariable:123456/foldertheyreach" | mail -s   "From your friendly cloud service provider" user1@someemail.com, user2@ect.com
jasonwryan
  • 73,126
Will
  • 21
  • 1
2

This will show the current ip address in a popup window:

zenity --info --text "$(curl -s icanhazip.com)"
basic6
  • 6,255
2

Here is another alternative that depends on hosts who's business resolves around managing dynamic IP rather that "public service" sites that may go away or change format.

  1. Register your server at one of the many free dynamic dns services (e.g. no-ip.com) This will give you a DNS entry like xxx.no-ip.org.
  2. Install the service's dynamic update tool (reports IP changes to service).

To get the IP address in a script, just do:

external_ip=`dig +short xxx.no-ip.org`

Great for use in cron job to check if dynamic IP has changed and some configuration entries need to be changed.

Mat
  • 52,586
  • 1
    Dynamic update tool needs to know the external ip address (some folk song about a hole in a bucket) – Jasen Jan 01 '21 at 06:23
1

I have setup a service that returns IP address as JSON / XML or plain text. You can find them here

http://ipof.in/txt

Same URL with /json and /xml will give you other formats as well

If you want HTTPS you can use the same URLs with https prefix. The advantage being that even if you are on a Wifi you will get the public address.

So a simple alias myip="curl https://ipof.in/txt" will get your IP

vivekv
  • 11
  • 2
1

Alternatively you could use STUN which was invented to answer this question in an automated way and is used extensively in internet communications e.g. by SIP and WebRTC.

Using a stunclient (on debian/ubuntu do apt-get install stuntman-client) simply do:

$ stunclient stun.services.mozilla.com
Binding test: success
Local address: A.B.C.D:42541
Mapped address: W.X.Y.Z:42541

where A.B.C.D is the IP address of your machine on the local net and W.X.Y.Z is the IP address servers like websites see from the outside (and the one you are looking for). Using sed you can reduce the output above to only an IP address:

stunclient stun.services.mozilla.com |
    sed -ne "s/^Mapped address: \(.*\):.*$/\1/p"

For an alternative STUN lookup using nothing but basic command line tools see my answer on AskUbuntu (intended as a fun exercise, not for production use).

1

If any of you host an Internet-facing webserver, you can just make a simple page that will show the requester's IP address, e.g. in PHP:

<?php

    echo $_SERVER['REMOTE_ADDR'];   

?>

Deploy this on your server. e.g. at http://mydomain.com/whatismyip.php Then use the standard curl trick to retrieve it:

curl -s http://mydomain.com/whatismyip.php

Note that if your server does any redirects (such as, from HTTP to HTTPS) you'll get the redirect response rather than your IP address. So address the curl request correctly.

The advantage of this approach is that the service won't move or disappear out from under you, as happens so often with free services. Disadvantage is obviously that it will likely be slower, unless you have some high-end hosting.

0

The w3m Plaintext-Browser is great for the bash. You can use grep and tail to shorten the reply as follows:

w3m -no-cookie -dump "http://www.whatismyip.com/" | grep -A 1 -m 1 "Your IP:" | tail -n 1
HalosGhost
  • 4,790
McPeppr
  • 169
0

Using a DNS request even behind a NAT router translating DNS addresses, this can work :

$ dig +short -t txt o-o.myaddr.l.google.com @ns1.google.com | cut -d'"' -f2
x.y.z.t

or, you can use the HTTP request method instead :

$ curl -s ipinfo.io/ip
x.y.z.t
SebMa
  • 2,149
0

Only ip.tyk.nu returned the correct IP by http, without https. Here are a few more http sites that return our public IP, and can do https. I learned here that using https instead of http on a wireless link will bypass ISP mangling of the IP, as several people said. Erwin Hoffman added "curve" encrypted dns to dnscache, which I could try with dig, since I have that here.

myip() shell func to consult a list of http sites or use https:

# ~/bin/.bash/.ifaces https://pastebin.com/DiPUdqPJ

myip() { [[ "$1" =~ -s ]] && s='https://' || s='' ( for site in ipaddr.pub/cli ipecho.net/plain icanhazip.com ifconfig.me
ipconfig.in/ip ident.me bot.whatismyipaddress.com diagnostic.opendns.com/myip
checkip.amazonaws.com trackip.net/ip api.ipify.org tnx.nl/ip ip.tyk.nu
l2.io/ip wgetip.com do echo "$site " wget -qO- ${s}$site echo done wget -qO- ${s}checkip.dyndns.org |
sed -n -E '/IP Address/s/^.:[\t ]+([^<]+).$/checkip.dyndns.org \n\1/p' ) |
sed -n -E '/^$/d;H;${g;s/^[\n]+//;s/( )\n/ /g;p;}' wget -qO- ${s}ipinfo.io | sed '1s/.*/ipinfo.io:/;$d;' }

myip (without https):

ipaddr.pub/cli 166.137.143.2 ipecho.net/plain 166.137.143.2 icanhazip.com 166.137.143.2 ifconfig.me 166.137.143.2 ipconfig.in/ip 166.137.143.2 ident.me 166.137.143.2 bot.whatismyipaddress.com 166.137.143.2 diagnostic.opendns.com/myip 166.137.143.2 checkip.amazonaws.com 166.137.143.2 trackip.net/ip 166.137.143.2 api.ipify.org 166.137.143.2 tnx.nl/ip 166.137.143.2 ip.tyk.nu 107.77.201.2 (without https but this one gets it) l2.io/ip 166.137.143.2 wgetip.com 166.137.143.2 checkip.dyndns.org 166.137.143.2 ipinfo.io: "ip": "166.137.143.2", "hostname": "mobile-166-137-143-2.mycingular.net", "city": "Dallas", "region": "Texas", "country": "US", "loc": "32.7831,-96.8067", "org": "AS20057 AT&T Mobility LLC", "postal": "75270", "timezone": "America/Chicago", "readme": "https://ipinfo.io/missingauth"

myip -s (with https):

ipaddr.pub/cli 107.77.201.2 ipecho.net/plain 107.77.201.2 icanhazip.com 107.77.201.2 ifconfig.me 107.77.201.2 ipconfig.in/ip 107.77.201.2 ident.me 107.77.201.2 bot.whatismyipaddress.com 107.77.201.2 diagnostic.opendns.com/myip 107.77.201.2 checkip.amazonaws.com 107.77.201.2 trackip.net/ip 107.77.201.2 api.ipify.org 107.77.201.2 tnx.nl/ip 107.77.201.2 ip.tyk.nu 107.77.201.2 l2.io/ip 107.77.201.2 wgetip.com 107.77.201.2 ipinfo.io: "ip": "107.77.201.2", "hostname": "mobile-107-77-201-2.mobile.att.net", "city": "Dallas", "region": "Texas", "country": "US", "loc": "32.7831,-96.8067", "org": "AS20057 AT&T Mobility LLC", "postal": "75270", "timezone": "America/Chicago", "readme": "https://ipinfo.io/missingauth"

BobDodds
  • 31
  • 3
0

you can do it using only bash like this

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 a TCP 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
  • 3,761
0

All of the above answers assume that the local machine has a domain name that can be resolved by a dns server.

This answer helps if

  • the local machine does not have a domain name that can be resolved by a dns server
  • you want to be independent from a domain name
  • you want the LAN ip address in the local network not the WAN ip of your router

This can be used in a shell script:

# Determine relevant network interface (e.g. eth0 on Linux, en0 on Mac)
INTERFACE=`ifconfig | grep -Eo '^e[a-z]+0: flags=.*' | grep -Eo '^e[a-z]+0'`
# Determine the external ip on this interface
HOSTIP=`ifconfig $INTERFACE | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*'` 

Does not work on Windows though.

not2savvy
  • 263
0

Use curl to hit shtuff.it's ip service

curl -s https://shtuff.it/myip/short