As I build more and more Pi-based systems, I find the need to add management scripts for accessing SSH, OpenVPN, and all kinds of other tools. This leads me to version 4 of the CloudFlare Dynamic DNS AutoIP updater script. It’s now hosted on GitHub.

Pulling off of GitHub:


Cloudflare-Subdomain-AutoIP-Updater

Create a private Dynamic DNS using the CloudFlare API with this script.

If you have a domain registered at CloudFlare, you can use this script to update the IP of the subdomain with a specific computer. The computer will get its IP address and send the information to CloudFlare using the API.

This script creates 3 files:

  1. an initializing script that creates and runs everything: cf_ip_script_creator.sh
  2. a script that gets all the CF details from you: cf_ip_updater_creator.sh
  3. a script that updates the subdomain IP address: cf_ip_updater.sh

Put the 3rd script (cf_ip_updater.sh) into a cron job to run every 5 or 15 minutes or so so that you can use access your system anywhere.

  sudo crontab -e
  
  */10 * * * *  nice -n 16 /home/scripts/cf_ip_updater.sh

Potential uses:

  • log into your computer anytime with SSH
  • run a portable OpenVPN server
  • keep your blog server private by using CloudFlare caching
  • whatever you can think of

Some potential issues:

  • if you fail to successfully run the script, the cat commands that append text to existing commands will force you to delete the create scripts (cf_ip_updater.sh, cf_ip_updater_creator.sh) before you run the initializing script (cf_ip_script_creator.sh) again.

You need the following information:

  • FULLDOMAIN cloudflare.com (your registered domain name)
  • SUBDOMAIN web.cloudflare.com (your subdomain linked to your system’s IP address)
  • EMAIL [email protected] (your account name)
  • KEY 9a7806061c88ada191ed06f989cc3dac (your CloudFlare API key details)
  • FILEPATH /home/path (where you want the script to be)

How to run:

  wget https://raw.githubusercontent.com/tgmgroup/Cloudflare-Subdomain-AutoIP-Updater/master/cf_ip_script_creator.sh
  chmod +X cf_ip_script_creator.sh
  sudo bash cf_ip_script_creator.sh

Dependencies:

  • The jq command requires the jq package (sudo apt install jq)
  • The dig command requires dnsutils (Debian) or bind-utils (Cent-OS) (sudo apt install dnsutils)

Read more at:

The last few days, I’ve been working on a vpn server for my home network. It’s so that my family all over the world can see the pictures of my son, which are hosted on a local server. However, I don’t want to expose those pictures to the world, hence the need for a vpn.

While using PiVPN to set up an OpenVPN server, I ran the script once and, since I hadn’t finished everything yet, I selected the Static IP option for the server. Since I was close to finishing all the setup, I wondered, how do you change the PiVPN OpenVPN config to use either a static ip address or dynamic domain name after running the initial configuration script?

It’s not difficult to change this in the ovpn config files that PiVPN generates, and OpenVPN apparently doesn’t care if the server name is an IP or a domain, so long as the client reaches the vpn server. However, I like to be a little bit of a perfectionist and it makes sense to change it to make future client configuration issues easier.

So after searching the PiVPN git page and the local /etc/ directories, I realized that the place to change the server name option was in this file:

/etc/openvpn/easy-rsa/keys/Default.txt

Just run a simple sudo nano /etc/openvpn/easy-rsa/keys/Default.txt command to edit the “remote” field:

client
dev tun
proto udp
remote Your-Domain-Name Your-Port-Number
resolv-retry infinite

Then run the pivpn add command to create a new client, and use sudo nano /home/pi/ovpns/Your-New-Client.ovpn to check to see that the domain name is being used instead of a static IP.

 

 

Photo by Nguyen Vu Hung (vuhung)

 

I talked about how to use PiVPN to set up an OpenVPN server on a Raspberry Pi at home previously, here and here. The next step for me was to use CloudFlare as a DNS server, instead of signing up for yet another internet service and having another login here or there to worry about.

This very smart guy, Tomasso Barbato, wrote up how to do it, but he includes two versions, an APIvUnknown and an APIv4 version. CloudFlare only supports the APIv4 version as of next month, I guess, so I’m copying the scripts here, as many of my referenced internet pages have gone offline in recent months. Read his page, though, so that you know what to do. I’ve also bolded the variables so that you can simply run a Replace All command in a text editor to easily adapt the scripts for your use. An enterprising hacker would create a bash script to automate all the other scripts, but…

Initial setup

This should be pretty easy, but:

  1. Go to CloudFlare
  2. Add an A record to your domain through the DNS page
  3. Use your current IP address of your server for the record
  4. Read the page to learn how to do it, but use my edits for an easier time.

The important variables

FULL-DOMAIN: example.com
SUB-DOMAIN: sub.example.com

From the CloudFlare user settings page

EMAIL: Account Email:    X-Auth-Email: [email protected]
KEY: API Key:    X-Auth-Key: 9a7806061c88ada191ed06f989cc3dac

*Note: the API Key is the shorter of the two keys that you have the option of requesting

Use scripts to obtain

ZONE-ID: Zone ID (domain name): “id”: “dac9320b638f5e225cf483cc5cfdda41”
RECORD-ID: Record ID (subdomain/A record): “id”: “8ada191ed06f989cc3dac9a7806061c8”

*Note: I’m using a VARIABLE: explanation: example format here.

The scripts

Get Zone ID:
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=FULL-DOMAIN" \
  -H "X-Auth-Email: EMAIL" \
  -H "X-Auth-Key: KEY" \
  -H "Content-Type: application/json" | jq .
Get Record ID:
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE-ID/dns_records?name=SUB-DOMAIN" \
  -H "X-Auth-Email: EMAIL" \
  -H "X-Auth-Key: KEY" \
  -H "Content-Type: application/json" | jq .
Bash script for crontab
#!/bin/sh

[ ! -f /var/tmp/current_ip.txt ] && touch /var/tmp/currentip.txt

NEWIP=`dig +short myip.opendns.com @resolver1.opendns.com`
CURRENTIP=`cat /var/tmp/currentip.txt`

if [ "$NEWIP" = "$CURRENTIP" ]
then
  echo "IP address unchanged"
else
  curl -X PUT "https://api.cloudflare.com/client/v4/zones/ZONE-ID/dns_records/RECORD-ID" \
    -H "X-Auth-Email: EMAIL" \
    -H "X-Auth-Key: KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"A\",\"name\":\"SUB-DOMAIN\",\"content\":\"$NEWIP\"}"
  echo $NEWIP > /var/tmp/currentip.txt
fi

 

By using this script, I now have an OpenVPN server that is somewhat protected by CloudFlare that I can access anywhere and whenever I want, no matter if my home router reboots or if I change internet providers.

There is a caveat: CloudFlare can only protect ports that are used with HTTP HOST headers, SSH or OpenVPN or any other protocol requires the A record to disable its CloudFlare protection. This exposes your IP address somewhat, but it is also protected somewhat. There’s a tradeoff between domain name privacy and personal convenience here.

I also read that a SRV record hides the IP of an origin server better than an A record, so that’s a logical next step, but not one that I have time for right now.

 

Photo by Nguyen Vu Hung (vuhung)

 

Security@Georgeliu.me

Before, I had written about a CloudFlare auto-ip-updating script, but it required a lot of user input and a lot of user effort. Luckily, or not, I  crashed my OMV server, and I think an error ate up my PiVPN sd card. So I had to start all over!

This time, I updated the CloudFlare script to be auto-updating.

This bash script requires the following inputs in this order (INFO example):

  • FULLDOMAIN cloudflare.com
  • SUBDOMAIN web.cloudflare.com
  • EMAIL [email protected]
  • KEY 9a7806061c88ada191ed06f989cc3dac
  • FILEPATH /home/path

If you organize your inputs in this order, it is very easy to copy once and paste to get your results.

Create and Run Script

Create a script and paste the following code in:

sudo nano cf_ip_updater_creater.sh

sudo chmod +x cf_ip_updater_creater.sh
./cf_ip_updater_creater.sh
Script Code
#!/bin/sh

#Get User Data
echo -n "Enter your FULL-DOMAIN (e.g. cloudflare.com) and press [ENTER]: "
read FULLDOMAIN

echo -n "Enter your SUB-DOMAIN (e.g. web.cloudflare.com) and press [ENTER]: "
read SUBDOMAIN

echo -n "Enter your Cloudflare Email (e.g. [email protected]) and press [ENTER]: "
read EMAIL

echo -n "Enter your Cloudflare API Key (e.g. 9a7806061c88ada191ed06f989cc3dac) and press [ENTER]: "
read KEY


echo -n "Enter path to create cf_ip_updater.sh script (e.g. /home/path) and press [ENTER]: "
read FILEPATH


#Get Zone and Record IDS
ZONEID=$(curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$FULLDOMAIN" \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $KEY" \
  -H "Content-Type: application/json" | jq . | grep id | head -1 | cut -d '"' -f4)

RECORDID=$(curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONEID/dns_records?name=$SUBDOMAIN" \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $KEY" \
  -H "Content-Type: application/json" | jq . | grep id | head -1 | cut -d '"' -f4)


#Print IDS
echo "Your Zone ID:   $ZONEID"
echo "Your Record ID: $RECORDID"


#Create script
FILE="$FILEPATH/cf_ip_updater.sh"
echo "Your script name: $FILE"


cat <>$FILE
#!/bin/sh

[ ! -f /var/tmp/current_ip.txt ] && touch /var/tmp/currentip.txt

NEWIP=\$(dig +short myip.opendns.com @resolver1.opendns.com)
CURRENTIP=\$(cat /var/tmp/currentip.txt)

if [ "\$NEWIP" = "\$CURRENTIP" ]
then
  echo "IP address unchanged"
else
  curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONEID/dns_records/$RECORDID" \
    -H "X-Auth-Email: $EMAIL" \
    -H "X-Auth-Key: $KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"A\",\"name\":\"$SUBDOMAIN\",\"content\":\"\$NEWIP\"}"
  echo \$NEWIP > /var/tmp/currentip.txt
fi
EOM

chmod +x $FILE
Limitations

If you run this file more than once, it appends to the bottom of the previous run for cf_ip_updater.sh . Otherwise, I guess it’s OK.

 

Resources and References
  • http://unix.stackexchange.com/questions/45781/shell-script-fails-syntax-error-unexpected
  • http://askubuntu.com/questions/186808/every-command-fails-with-command-not-found-after-changing-bash-profile
  • http://unix.stackexchange.com/questions/48392/understanding-backtick
  • http://stackoverflow.com/questions/11710552/useless-use-of-cat
  • http://stackoverflow.com/questions/7549404/bash-script-to-pass-variables-without-substitution-into-new-script
  • http://unix.stackexchange.com/questions/238881/how-do-i-append-multiple-lines-involving-variables-to-the-end-of-a-bash-script
  • http://unix.stackexchange.com/questions/331068/append-multiple-lines-specified-as-verbatim-bash-variable-after-a-matched-line
  • http://unix.stackexchange.com/questions/147082/how-to-append-multiple-lines-to-a-file-with-bash-with-in-front-of-string
  • http://stackoverflow.com/questions/7875540/how-do-you-write-multiple-line-configuration-file-using-bash-and-use-variables
  • http://unix.stackexchange.com/questions/77277/how-to-append-multiple-lines-to-a-file-with-bash
  • http://stackoverflow.com/questions/4181703/how-can-i-concatenate-string-variables-in-bash
  • http://unix.stackexchange.com/questions/94664/how-to-echo-variables-using-cat-into-file
  • http://www.tldp.org/LDP/abs/html/here-docs.html#HERELIT
  • http://stackoverflow.com/questions/11162406/open-and-write-data-on-text-file-by-bash-shell-scripting
  • http://stackoverflow.com/questions/4662938/create-text-file-and-fill-it-using-bash
  • http://stackoverflow.com/questions/8737638/assign-curl-output-to-variable-in-bash
  • http://stackoverflow.com/questions/25320928/how-to-capture-the-output-of-curl-to-variable-in-bash
  • http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-5.html
  • http://stackoverflow.com/questions/840536/how-to-use-environment-variable-inside-a-quoted-string-in-bash-script
  • http://unix.stackexchange.com/questions/148285/extract-value-between-double-quotes
  • http://unix.stackexchange.com/questions/166359/how-to-grep-the-output-of-curl

An OMV server running OMV 3 (Erasmus) may experience a loss of wifi (wlan0) due to drivers being removed from the backports package.

Run the code below to download the broadcom wifi controller drivers and re-enable wifi (wlan0) (from OMV forums)

wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.bin
wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.txt
sudo mv brcmfmac43430-sdio* /lib/firmware/brcm/
sudo reboot

 

Consequently, this is also a good time to learn about wireless network troubleshooting tools:

ifconfig -a
iwconfig
sudo iwlist wlan0 scan
sudo ifdown wlan0 && sudo ifup -v wlan0

If any of these show an error or do not show the wlan0 interface, you may have a driver issue, such as the one with OMV and the RPi3 backport repository.

References: 1, 2, 3, 4

 

While updating my RPi for a Cloudflare auto-ip-updater script, I ran into an issue where the dig command couldn’t be found. Also, the dnsutils package containing dig was not in the Raspbian repository. So, you can easily replace the dnsutils package with the knot-dnsutils package, and you get dig back. Install with sudo apt-get install knot-dnsutils.

 

Look for more here: 1, 2, 3

About Boot Mode

The Raspberry Pi 3 can now be booted from a compatible USB drive. It works pretty well, but there are no noticeable differences in speed between a good SD card and a good USB drive. Primarily, cost may be a factor, as good USB drives are generally cheaper than good SD cards. Not all USB drives are supported–my Sandisk Ultra Fit worked, but my Trancend JetFlash did not.

Read the official documentation to learn how to set it up.

 

Boot Mode and Updates

I used apt-get update/upgrade to update my Raspberry Pi, which wiped out the boot mode. Make sure not to upgrade the bootloader, or save an edited bootable sd card to reapply the boot mode edits.

 

sudo mkdir /mnt/target
 sudo mount /dev/sda2 /mnt/target/
 sudo mkdir /mnt/target/boot
 sudo mount /dev/sda1 /mnt/target/boot/

cd /mnt/target
 sudo mount --bind /dev dev
 sudo mount --bind /sys sys
 sudo mount --bind /proc proc
 sudo chroot /mnt/target

sudo BRANCH=next rpi-update

exit
 sudo umount dev
 sudo umount sys
 sudo umount proc

sudo reboot

Official forums also have some more information.

I previously created a RPi3 OMV server to share some pictures and movies across the network. But I configured the underlying Debian  to check for updates outside of OMV, which means it probably upgraded to Debian 8 Jessie instead of staying with Debian 7 Wheezy. Since OMV was based on version 2 (Stoneburner), it crashed everything.

So I started again. This time, I wanted to be sure I didn’t crash everything, so I installed OMV 3 (Erasmus) on Raspbian Lite (Jessie). What a headache! OMV reconfigures a bunch of things I didn’t want it to, especially sshd configs and wifi configs.

The first issue was that I couldn’t login through ssh. To fix that, add your user to the root or ssh group in the OMV web interface. You also want to check the sshd config to make sure that root can’t login and make other security changes.

Then, I rebooted the Pi and it was gone from my network. I couldn’t understand why, as I was working remotely, but when I got home, I saw it was still running and could bring up a locally connected display. It just wasn’t connecting to the internet. Trying ifconfig -a will give you an idea if it is connected or not.

To fix that, I had to go into the /etc/network/interface file and add back a bunch of wifi lines:

allow-hotplug wlan0
auto wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Now it’s working…again…I hope.

Servers@GeorgeLiu.me

Did you ever get this code while using FreeFileSync: “Windows Error Code 1314: A required privilege is not held by the client.“?

I did. Many times. I thought it was a Linux file permission error on my Raspberry Pi 3 OMV setup, and I chmodded and chowned an unbelievable amount of times, to no effect. And then, while setting up a new temporary NAS on a Raspberry Pi 3, I found a new page: “Windows Error Code 1314: A required privilege is not held by the client.

If you don't really need to copy file system permissions, 
turn them off in global settings.

I solved the problem!

The following is an OpenVPN autologin script for my portable Raspberry Pi Kodi media center. It starts an OpenVPN connection on boot.

 

Dependencies

  • The Expect package
  • A folder containing an OpenVPN configuration file
  • A folder for the script (I put it in the same OpenVPN folder)

 

Script Creation

sudo apt-get install expect
sudo nano autovpnscript.sh
chmod +x autovpnscript.sh

 

Contents

#!/usr/bin/expect

set password "Password-For-OpenVPN-Connection\r"
set config "Path-To-OpenVPN-Config-File(*.ovpn)"

cd /Path-To-OpenVPN-Config-Folder

spawn openvpn $config
expect "Enter Private Key Password:"
send $password
#interact
expect eof
exit

 

Add to Crontab

sudo crontab -e
@reboot /Path-To-Script-Folder/autovpn.sh

 

Stop OpenVPN

sudo killall openvpn

 

 

References – 1, 2, 3, 4, 5, 6