I’m using ssh on my raspberry pi, but to access it when I’m away from my home network I’ve got to have a public ip. My ISP doesn’t provide static ip for private users, so it may change whenever my ISP feels the need to do so. This of course means that I might not be able to access my raspberry pi over ssh if my ISP changes my ip address.
First of all, what is my public ip? You can find it at this address: http://www.whatsmyip.org/. Ok, but we obviously can’t check the IP from our home network when we’re not at home, right? So let’s automate it with python!
First of all, the link above gives a lot of information, but for this script we only need the ip. We have another address that provides just that: http://ip.42.pl/raw. As you can see, it only states the ip, nothing else.
To read the ip from a webpage we need to import urlopen from urllib2 like this.
from urllib2 import urlopen.
This enables us to do this:
public_ip = urlopen('http://ip.42.pl/raw').read()
public_ip variable now contains our most recent public ip. Great!
What we’re interested in is if it has changed since the last time this script was called. To check that we need to store the ip somewhere. Since we’ll only store the last public ip, it is sufficient with a text-file for this. If you were to store historical data, like all ip addresses assigned to your network by your ISP and when it was changed I would suggest you use a database like mongodb.
Back to our script, we want to store the ip in a file called “publicip.txt”. On linux, the file ending is not necessary, but I like to include them for readability.
filename = 'publicip.txt'
We also need to import os with:
This is because when we’re running the script, we want to check if the file already exists.
file = open(filename,'r+')
old_ip = file.read()
file = open(filename,'w')
What this snippet does is that it checks if the file exists. If it does, it opens it and tries to read it to get the stored ip and saves it in memory as the variable old_ip. If the file doesn’t exist it opens the file to write to it (this also creates the file). It then writes the ip we got from the website to the file and closes the file.
Ok so far, but we still have to make logic for if the file exist and contains an ip different from the one we got from the website.
if public_ip != old_ip:
file = open(filename, 'w')
This snippet basically says that if the public_ip is different from the old_ip, we open the file to write to it (the ‘w’ parameter truncates the file, meaning that the file is cleared of all contents. If you want to append, use ‘a’). We then write the new ip and close the file.
Awesome! But we also want to receive some sort of message that contains the new ip, right? Let’s use mail.
First, we need to import some libraries:
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
Then we need to open a connection to a smtpserver. We’ll use gmail for this script.
server = smtplib.SMTP('smtp.gmail.com', 587)
Next, we’ll provide some mail parameters:
username = 'email@example.com'
password = 'somethingsupersecretaboutsocks'
fromaddr = 'firstname.lastname@example.org'
toaddr = 'email@example.com'
subject = 'Public ip changed!'
Username and password should be somewhat self explanatory. the fromaddr and toaddr are addresses, in this case from me to me. Subject is going to be used for the subject-line in the mail. Using the gmail smtp server might require you to do some additional steps when creating this script, namely creating what is known as a app-password. You can find information about it here: https://support.google.com/accounts/answer/185833. It is a password for your app that doesn’t need 2 way authentication or captchas. It is perfect for this kind of automation scripts, but might provide a security risk (since it is the only authentication needed to access your google account).
The next part is creating the mail, parsing it to text and sending it like this:
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = subject
body = 'Your public ip has changed and is now: '+public_ip
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
Here we construct a msg-object of the type MIMEMultipart. It contains values for sender (‘From’), receiver (‘To’) and subject (‘Subject’). We also create a body containing a short message and the new public_ip, convert it to MIMEText and attach it to the message. Then we convert the msg from MIMEMultipart to string and send it using the server-object we created earlier.
You can see the whole script on my GitHub-page: https://github.com/TM89/public-ip-finder.
When the script is called and the ip has changed, I receive an email looking like this.
Email received from script
To run it on timed intervals, check out this post: Running script using crontab on Ubuntu
And that’s that! Let me know what you think in the comment section below!