For work I have both a desktop (Mac Mini) and a laptop (MacBook Pro). As one would expect I use the laptop when I need to be away from my desk and the desktop computer. A considerable amount of my work happens in the terminal. By using tmux I’m able to create a session on the desktop and then remotely access it from my laptop.
This work fantastically, until the desktop gets a new IP address and I can’t remote in. If I’m at home I can walk to the other computer, and check its IP address. Annoying but no big deal. When I’m not at home, I’m stuck.
I created a bash script that checks the current IP address against a saved one. If they match nothing happens. If they are different the script creates a draft email that has the new IP address in it. And it posts a notification that the IP address has changed.
I used a draft email since I can access my mailbox from either computer; no need to send it, just open the draft and copy the new IP address.
The script is managed through a Launch Agent. It runs every five minutes. Worst case scenario is I’d have to wait 5 minutes to get the updated IP address. I think the only time I lose the current IP address is when my Aruba RAP (remote access point) loses power and reboots, so I’m not expecting to get IP address changes email drafts too often.
Here’s the bash script. It needs to be on the PATH and executable for this to work.
1#!/usr/bin/env bash
2# vim: ft=bash
3
4# File to store previous IP
5IP_FILE="$HOME/.current_ip"
6
7# Get current local IP (adjust interface if needed)
8CURRENT_IP=$(ipconfig getifaddr en0)
9
10# Fallback if en0 doesn’t work (e.g., on Ethernet it might be en1 or enX)
11if [ -z "$CURRENT_IP" ]; then
12 CURRENT_IP=$(ipconfig getifaddr en1)
13fi
14
15# Read stored IP
16if [ -f "$IP_FILE" ]; then
17 STORED_IP=$(cat "$IP_FILE")
18else
19 STORED_IP=""
20fi
21
22# Compare and notify
23if [ "$CURRENT_IP" != "$STORED_IP" ]; then
24 echo "$CURRENT_IP" > "$IP_FILE"
25
26 # Create and save a draft email with the IP address
27 osascript <<EOF
28tell application "Mail"
29 set newMessage to make new outgoing message with properties {subject:"Desktop IP Changed", content:"The new IP address is $CURRENT_IP", visible:true}
30 tell newMessage
31 make new to recipient at end of to recipients with properties {address:"mhn@ksu.edu"}
32 end tell
33end tell
34EOF
35
36 osascript -e "display notification \"IP changed to $CURRENT_IP\" with title \"IP Monitor\""
37fi
Instead of using a cron job to manage the running of the script, the MacOS
preferred way is to use a Launch Agent.
The Launch Agent requires a plist file to define it.
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertiesList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>Label</key>
6 <string>com.user.ipmonitor</string>
7
8 <key>ProgramArguments</key>
9 <array>
10 <string>/Users/USERID/bin/bash/ip_monitor</string>
11 </array>
12
13 <key>StartInterval</key>
14 <integer>300</integer>
15
16 <key>RunAtLoad</key>
17 <true/>
18
19 <key>StandardOutPath</key>
20 <string>/tmp/ipmonitor.log</string>
21
22 <key>StandardErrorPath</key>
23 <string>/tmp/ipmonitor.err</string>
24</dict>
25</plist>
You’ll need to substitute your account ID for USERID on line 10.
The plist defines the script location, sets the interval for how often to execute it (5 minutes (300 seconds)), and defines locations for logging and error messages.
The plist needs to be copied to the user’s Library/LaunchAgent directory. I
had to create this directory on my computer.
cp com.user.ipmonitor.plist ~/Library/LaunchAgents/com.user.ipmonitor.plist
To launch the agent:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist
The start/enable the service:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist
To check if the service is running:
launchctl list | grep ipmonitor
To kick the service, if it is already loaded:
launchctl kickstart gui/$(id -u)/com.user.ipmonitor
Logs can be viewed:
tail -f /tmp/ipmonitor.log /tmp/ipmonitor.err
Make sure the plist file path is correct. Verify with:
ls -la ~/Library/LaunchAgents/com.user.ipmonitor.plist
Verify you updated the user name in the plist.
Check plist syntax
plutil -lint ~/Library/LaunchAgents/com.user.ipmonitor.plist
Ensure the script is executable:
chmod +x ip_monitor
If you still get errors after bootstrap, run:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist 2>&1
This will show the actual error message, which will help troubleshoot the issue.
I have a Git repository with the script, plist, and a detailed README: ip_monitor