Here is a step-by-step guide to creating a robust `systemd` service and timer for your ChangeIP update script on a Raspberry Pi. ### Step 1: Refine and Place the Script The original script is designed for interactive use or a simple cron job. We'll make a few small tweaks to make it better for a non-interactive system service. The main changes are: 1. Remove the hardcoded credentials. 2. Have it read credentials from environment variables. 3. Direct its output to standard output (`stdout`) so `systemd`'s journaling system can capture it, which is more efficient than managing a separate log file. First, create the script file. ```bash sudo nano /usr/local/bin/changeip-update.sh ``` Now, paste the following **modified** script into the editor: ```bash #!/bin/bash # A script to update a ChangeIP.com DDNS record. # Modified for use with systemd. Credentials are now passed via environment variables. # Logging is handled by redirecting echo to stdout for journalctl. # These variables are still useful for the script's internal logic. IPPATH=/tmp/current_ip TMPIP=/tmp/new_ip # --- Configuration (Credentials should be in the environment file) --- # CIPUSER is read from the environment # CIPPASS is read from the environment CIPSET=1 # DDNS SET 1 or 2. Ensure your domains are in this set on ChangeIP.com. # Get the current public IP address NEW_IP=$(curl -s 'https://ip.changeip.com' | grep 'IPADDR' | cut -d'=' -f2) # Exit if we couldn't get the new IP if [ -z "$NEW_IP" ]; then echo "Error: Could not retrieve new IP address from changeip.com." >&2 exit 1 fi echo "$NEW_IP" > "$TMPIP" # If the old IP file doesn't exist, create it to trigger an initial update. if [ ! -f "$IPPATH" ]; then touch "$IPPATH" fi # Compare old IP with new IP. if diff -q "$IPPATH" "$TMPIP" > /dev/null then # IPs are the same. No update needed. echo "IP address has not changed: $NEW_IP. No update performed." else # IPs are different. Trigger an update. echo "IP address has changed. Old: $(cat $IPPATH), New: $NEW_IP. Updating..." # Perform the update using credentials from the environment. UPDATE_RESPONSE=$(curl -s "https://nic.changeip.com/nic/update?u=$CIPUSER&p=$CIPPASS&set=$CIPSET") echo "Update response from ChangeIP: $UPDATE_RESPONSE" # Store the new IP for the next check. mv "$TMPIP" "$IPPATH" fi exit 0 ``` After pasting the script, make it executable: ```bash sudo chmod +x /usr/local/bin/changeip-update.sh ``` ### Step 2: Create a Secure Environment File for Credentials This file will hold your credentials. `systemd` will load this file before running the script, keeping the credentials out of the main script and process list. 1. **Create the environment file:** ```bash sudo nano /etc/default/changeip ``` 2. **Add your credentials to this file:** ```ini # ChangeIP Credentials CIPUSER="YOUR_EMAIL" CIPPASS="YOUR_PASSWORD" ``` *Note: The script is configured for `CIPSET=1`. Ensure domains are configured in **Set 1** in your ChangeIP.com account settings.* 3. **Set strict permissions on the file** so only the `root` user can read it: ```bash sudo chmod 600 /etc/default/changeip ``` ### Step 3: Create the `systemd` Service File The service file tells `systemd` *what* to run. 1. **Create the service unit file:** ```bash sudo nano /etc/systemd/system/changeip.service ``` 2. **Paste the following configuration:** ```ini [Unit] Description=ChangeIP Dynamic DNS Update Service After=network.target [Service] Type=oneshot User=root EnvironmentFile=/etc/default/changeip ExecStart=/usr/local/bin/changeip-update.sh [Install] WantedBy=multi-user.target ``` * `After=network.target`: Ensures the network is up before running. * `Type=oneshot`: Indicates that this is a short-running task, not a long-running daemon. * `EnvironmentFile`: This is the key to securely loading your credentials. ### Step 4: Create the `systemd` Timer File The timer file tells `systemd` *when* to run your service, replacing the need for cron. 1. **Create the timer unit file:** ```bash sudo nano /etc/systemd/system/changeip.timer ``` 2. **Paste the following configuration:** ```ini [Unit] Description=Run ChangeIP DDNS update every 5 minutes [Timer] OnBootSec=2min OnUnitActiveSec=5min Unit=changeip.service [Install] WantedBy=timers.target ``` * `OnBootSec=2min`: Runs the service 2 minutes after the Pi boots up. * `OnUnitActiveSec=5min`: Runs the service every 5 minutes after the last time it was run. * `Unit=changeip.service`: Specifies which service this timer controls. ### Step 5: Enable and Start the Timer Now, you just need to tell `systemd` to load these new files and enable the timer. 1. **Reload the `systemd` daemon** to make it aware of the new files: ```bash sudo systemctl daemon-reload ``` 2. **Enable the timer** to start automatically on boot: ```bash sudo systemctl enable changeip.timer ``` 3. **Start the timer now:** ```bash sudo systemctl start changeip.timer ``` ### Step 6: Verify and Monitor the Service You can now check that everything is working as expected. * **Check the status of the timer** to see when it will run next: ```bash systemctl list-timers ``` You should see `changeip.timer` in the list. * **View the logs** from your service. All the `echo` statements from the script are automatically captured by the journal. ```bash sudo journalctl -u changeip.service -f ``` * Use `-f` to follow the log in real-time. * Press `Ctrl+C` to exit the log view. You have now successfully converted the script into a modern, secure, and reliable service on your Raspberry Pi.