WHY
Since ISP (Internet Service Provider) started to change public IPs at will, I wanted to have sort of a control center network appliance that would monitor things like Public IP changes and possibly other things (like speed tests, checking if certain external sites are up, etc.) utilizing existing, unused, and, probably soon, outdated hardware.
WHAT
- Raspberry Pi 1 Model B+ Board
- Clear acrylic case for RPi Model B+
- 8GB SD card
- Old iPhone 1A adapter (works fine for Model 1b)
- Micro USB to USB Cable
- RJ45 Ethernet cable
HOW
Prepare RPi SD Card
- Download Raspberry Pi OS Lite (at the time of writing Kernel version 5.00 released on March 4th 2021)
- Download Balena Etcher or similar software to copy image to SD card (Raspberry Pi Imager did not work for me but was my first choice)
- Plug SD Card into your Windows / OSX / Linux host machine and copy downloaded image to SD Card
- Once downloaded, navigate to the SD Card (you might have more than one drive mounted / available under windows) and create an empty file named ssh (this will ensure that SSH server on headless Raspberry Pi (RPi) will start on the first boot
First Time Setup
- On windows I have download and installed wonderful Cygwin that provides a large collection of GNU and Open Source tools to provide functionality similar to a Linux distribution on windows. If using Windows 10, you might want to look into much heavier but "out of box" option called WSL2.
- Unmount SD Card and plug it into RPi (via SD adapter if required), plug in RJ45 for wired internet connection (other side should go to your router), and then plug in Power cable. RPi lights will be lit.
- Identify an IP address of newly built RPi using either your Router's DHCP list of IPs (RPi MAC addresses would start with B8-27-EB or use one of the utilities like Adafruit Pi Finder, nmap, Angry IP Scanner (try older version with a single executable ipscan.exe), or just type in something like "ping -4 raspberrypi.local" at the command prompt.
Sample Naming
- RPi hostname: raspberry ==> headless_horseman
- RPi IP Address: 192.168.1.123
- SSH Port: 22 ==> 7522
- Sample Sudo User / Pass: mysudouser / Pwd.926!
- Sample SSH User / Pass: mysshuser / T3n.F0ur!
- SSH Public key file on Host machine: ~/.ssh/id_rsa-headless_horseman.pub
First Time Login
- Using Cygwin or WSL2 (from windows) or Terminal (on OSX / Linux), connect to RPi (default user "pi" with default password "raspberry"):
- user@host $ ssh pi@192.168.1.123
- To enable SSH for the future boots one can use "sudo raspi-config" or via command line:
- pi@192.168.1.123 $ sudo systemctl enable ssh # enable ssh
- Change default "pi" password (optional - user will be removed):
- pi@192.168.1.123 $ passwd
- Change default hostname:
- pi@192.168.1.123 $ sudo vi /etc/hostname
- To add users:
- pi@192.168.1.123 $ sudo adduser mysshuser # add user for non-sudo SSH access
- pi@192.168.1.123 $ sudo adduser mysudouser sudo # add user for sudo non-SSH access
- pi@192.168.1.123 $ sudo usermod -aG sudo mysudouser # OPTIONAL: add user to sudo group (covered by adduser with 'sudo' group name at the end)
- Remove ability for ssh user to browse sudo user folder:
- pi@192.168.1.123 $ sudo chmod 0750 /home/mysudouser
- Modify SSH Config to Allow / deny certain users and change default port (append at the end):
- pi@192.168.1.123 $ sudo vi /etc/ssh/sshd_config
- Port 7522 # Change Port to 7522 from default 22
- AllowUsers mysshuser # allow SSH
- DenyUsers mysudouser # sudo user to be denied SSH
- PermitRootLogin=no # do not allow root login via ssh
- SSH Server needs to be restarted for changes to take effect. Status can be queried as well:
- pi@192.168.1.123 $ sudo systemctl restart ssh
- pi@192.168.1.123 $ sudo systemctl status ssh
Setup Host machine for Passwordless SSH login
- In terminal in the host machine (cygwin, wsl2, terminal, etc.) key needs to be available or generated (accept default empty value for passphrase by pressing ENTER):
- user@host $ mkdir -p ~/.ssh && cd ~/.ssh
- user@host $ ssh-keygen -f id_rsa-headless_horseman
- Copy public key to RPi (target is ~/.ssh/authorized_keys):
- user@host $ ssh-copy-id -i ~/.ssh/id_rsa-headless_horseman -p 7522 mysshuser@192.168.1.123
- Create configuration file for SSH to avoid supplying parameters every time:
- user@host $ vi ~/.ssh/config
- Host headless_horseman
- HostName 192.168.1.123
- User mysshuser
- Port 7522
- IdentityFile ~/.ssh/id_rsa-headless_horseman
- Connect to RPi:
- user@host $ ssh headless_horseman
- mysshuser@headless_horseman $ su - mysudouser
- Delete pi user
- mysudouser@headless_horseman $ sudo userdel -r pi
- Create scripts folder:
- mysudouser@headless_horseman $ mkdir -p ~/scripts
- mysudouser@headless_horseman $ mkdir -p ~/scripts
- Install fail2ban
- mysudouser@headless_horseman $ sudo apt-get update
- mysudouser@headless_horseman $ sudo apt-get -y install fail2ban
- mysudouser@headless_horseman $ sudo vi /etc/fail2ban/jail.local
- [ssh]
- enabled = true
- port = 7522
- filter = sshd
- logpath = /var/log/auth.log
- bantime = 900
- banaction = iptables-allports
- findtime = 900
- maxretry = 3
- mysudouser@headless_horseman $ sudo systemctl restart fail2ban
- mysudouser@headless_horseman $ sudo iptables -L -n --line #check banned addresses
- mysudouser@headless_horseman $ sudo iptables -D fail2ban-ssh 1 #unban line number 1
- mysudouser@headless_horseman $ ln -s -T /var/log/fail2ban.log ~/scripts/fail2ban.log
- Modify prompt and ls alias
- mysudouser@headless_horseman $ vi ~/.profile
- export PS1="\[\033[0;33m\][\D{%Y-%m-%d}][\t]\[\033[0;36m\] [\u\[\033[0;37m\]@\[\033[0;36m\]\h:\[\033[0;32m\]\w]\[\033[0m\] \n$ "
- alias ls='ls -laFh --color=auto'
- Script: update.sh
- mysudouser@headless_horseman $ vi ~/scripts/update.sh
- #!/bin/bash
- sudo apt update;
- sudo apt -y upgrade;
- sudo apt -y autoclean;
- sudo apt -y autoremove;
- sudo shutdown -r
- mysudouser@headless_horseman $ chmod +x ~/scripts/update.sh
- mysudouser@headless_horseman $ sudo crontab -e
- 30 23 * * WED /bin/bash /home/mysudouser/scripts/update.sh
- Script: myutil.py
- mysudouser@headless_horseman $ vi ~/scripts/myutil.py && chmod +x ~/scripts/myutil.py
- #!/usr/bin/env python3
def getip(networkCardName):
import subprocess
return subprocess.getoutput("ip addr show " + networkCardName + " | grep -Po 'inet \K[\d.]+'")
def getips():
import re
import subprocess
# get ip(s) from ifconfig
found_ips = []
ips = re.findall( r'[0-9]+(?:\.[0-9]+){3}', subprocess.getoutput("/sbin/ifconfig"))
for ip in ips:
if ip.startswith("255") or ip.startswith("127") or ip.endswith("255"):
continue
found_ips.append(ip)
return ", ".join(found_ips)
def emailsend(subjectPart, messagePart):
import time
import smtplib
import socket
from datetime import datetime
current_utc = datetime.utcnow().isoformat() + 'Z'
####--[CONFIGURATION]
server = 'smtp.gmail.com'
server_port = '587'
username = 'MYEMAIL@gmail.com'
password = 'MYGMAILPA$$'
fromaddr = 'DEVOPS <MYEMAIL@gmail.com>'
toaddr = 'TARGET_EMAIL@domain.com'
subject = 'DEVOPS | ' + socket.gethostname() + ' | ' + subjectPart
message = 'DEVOPS | ' + socket.gethostname() + ' | <br>' + messagePart + '<br><br><br>Email Generated On: ' + current_utc
####--[/CONFIGURATION]
headers = [
"Subject: " + subject,
"From: " + fromaddr,
"To: " + toaddr,
"MIME-Version: 1.0",
"Content-Type: text/html"
]
headers = "\r\n".join(headers)
server = smtplib.SMTP(server + ":" + server_port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(username,password)
server.sendmail(fromaddr, toaddr, headers + "\r\n\r\n" + message)
server.quit()
def get_script_path():
import os
import sys
return os.path.dirname(os.path.realpath(sys.argv[0])) - Script: ipcheck.py
- mysudouser@headless_horseman $ vi ~/scripts/ipcheck.py && chmod +x ~/scripts/ipcheck.py
- #!/usr/bin/env python3
import json, os
import urllib.request
import myutil
from datetime import date
today = date.today()
formatted_date = today.strftime("%Y%m%d")
script_dir = myutil.get_script_path()
# Create a script on external web site (mydomain.com) named ipcheck.php as follows
# <?php
# header('Content-Type: application/json');
# $ip=$_SERVER["REMOTE_ADDR"];
# $arr=array( "ip" => $ip );
# echo json_encode($arr);
# ?>
ipcheck_url = "https://mydomain.com/ipcheck.php"
ipcheck_log = script_dir + "/ipcheck_changes-py.log"
lastip_filename = script_dir + "/ipcheck_lastip-py.txt"
lastip = "unknown"
if os.path.isfile(lastip_filename):
with open(lastip_filename, 'r') as f:
lastip = f.read()
data = json.loads(urllib.request.urlopen(ipcheck_url).read())
currentip = data["ip"]
if lastip != currentip:
with open(lastip_filename, 'w') as f:
f.write(currentip)
with open(ipcheck_log, 'a') as f:
f.write(formatted_date + " " + currentip + '\n')
subject = "Public IP address change"
message = "Old IP: " + lastip + " / New IP: " + currentip
myutil.emailsend(subject, message)
- mysudouser@headless_horseman $ sudo crontab -e
- */1 * * * * /usr/bin/python3 /home/mysudouser/scripts/ipcheck.py
- Script: i_am_alive_email.py
- mysudouser@headless_horseman $ vi ~/scripts/i_am_alive_email.py && chmod +x ~/scripts/i_am_alive_email.py
- #!/usr/bin/env python3
import time
import myutil
# wait for interface to initialize before parsing ifconfig
time.sleep(1)
subject = "IP address(es)"
# ifconfig will show networkCardName
networkCardName = "eth0"
message = myutil.getip(networkCardName)
myutil.emailsend(subject, message) - mysudouser@headless_horseman $ sudo crontab -e
- 33 03 * * * /usr/bin/python3 /home/mysudouser/scripts/i_am_alive_email.py
No comments:
Post a Comment