# Raspberry PI

# Raspberry Pi - SD card to a USB SSD

## Install

With the new version of the OS you can just use SD Card Copier from the accessories menu.

We assume that you have already imaged and are booted up with the SD Card.

#### 1. Terminal

Open the terminal windows

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/agpimage.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/agpimage.png)

Change the boot option with this command from the terminal window

```bash
sudo raspi-config
```

Once in the menu choose `Advanced Options`

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/image.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/image.png)

Then choose the option `Boot Order`

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/VsZimage.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/VsZimage.png)

Then choose the option `NVMe/USB Boot`

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/WlCimage.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/WlCimage.png)

From the `Accessories` menu, run the copier from you SD card to the SSD as this will copy you SD to your new SSD.

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/Cezimage.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/Cezimage.png)

Reboot your Pi

r<s>pi-clone is on github and is downloaded by cloning the repository. It is a standalone script and the install is a simple copy to a bin directory. When run it checks its program dependencies and offers to install needed packages. But currently rpi-clone knows how to install only Debian packages with apt-get.</s>

<s>On a Raspberry Pi:</s>

```shell
	$ git clone https://github.com/billw2/rpi-clone.git 
	$ cd rpi-clone
	$ sudo cp rpi-clone rpi-clone-setup /usr/local/sbin
```

<s>Clone to the drive you need the drive first with </s>

```bash
lsblk
```

<s>Then clone to it</s>

```bash
sudo rpi-clone sda
```

<s>Make sure /usr/local/sbin is in your $PATH and then run rpi-clone or rpi-clone-setup with no args to print usage.</s>

<s>Get it [HERE](https://github.com/billw2/rpi-clone "rpi-clone")</s>

<s>Video [HERE](https://youtu.be/AenM-JrG098?si=Bih_SIbOC1dQErq- "Video")</s>

# Raspberry Pi - Bash Colors

### Check you shell to be default to bash if not already:

Here's how to **set Bash as your default login shell** on Debian / Raspberry Pi OS:

#### Step1. Check current shell

Run this first to see what you're currently using:

```
echo $SHELL
```

#### Step2. Set Bash as default shell

Run the following command:

```
chsh -s /bin/bash
```

- It will ask for your password.
- Type it and press Enter.

#### Step3. Verify the change

```
cat /etc/passwd | grep ^pi:
```

You should see /bin/bash at the end of the line for the pi user.

#### Step4. Apply the change

**Log out and log back in** (or reboot):

```
logout
```

Or if you're using SSH, just close the connection and reconnect.

After logging back in, run echo $SHELL again — it should show /bin/bash.

#### Alternative method (if chsh doesn't work)

```
sudo usermod -s /bin/bash pi
```

Then log out and back in.

### Change the colors of the shell do the following steps.

#### Step 1: Better organization (recommended)

Many people keep aliases separate:

\# Create a dedicated aliases file

```
nano ~/.bash_aliases
```

<div dir="auto" id="bkmrk-once-opened-att-the-"><div data-testid="code-block"><div><div><div>Once opened att the following to it:</div><div>  
</div></div></div></div></div>```
# Safety aliases
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Convenience
alias vi='vim'
alias tailf='tail -f'

# LS colors
LS_COLORS='rs=0:di=01;44:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:'
export LS_COLORS

# Detect OS name
if [ -f /etc/os-release ]; then
    OS_NAME=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"')
else
    OS_NAME="Unknown"
fi

export PS1="\[$(tput bold)\]\[$(tput setaf 1)\]\[$(tput setab 8)\]\u\[$(tput setaf 5)\]@\[$(tput setaf 1)\]$(hostname) \[$(tput setaf 2)\]: $(uname) : \[$(tput setaf 6)\]\d \t : ${OS_NAME}\[$(tput sgr0)\]\n\[$(tput sgr0)\][\w]\$ "
```

#### Step 2: Testing the Prompt

Option 1 : Logout and back in

Option 2 : Reload:

```
source ~/.bash_aliases
```

#### Result

[![image.png](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/scaled-1680-/08Himage.png)](https://docs.sflservicesllc.com/uploads/images/gallery/2026-04/08Himage.png)

### Add VIM colors to your shell

#### Step1. Install Git (and Vim if not already installed)

```
sudo apt update
sudo apt install git vim -y
```

#### Step2. Clone the vim-colorschemes repository

```
git clone https://github.com/flazz/vim-colorschemes.git ~/.vim/
```

This will create the ~/.vim/colors/ directory with hundreds of color schemes (including desert.vim).

#### Step3. Set the desert colorscheme properly (Recommended way)

On Debian/Raspberry Pi OS, it’s better **not** to copy files to /etc/vimrc.local (that file is not always sourced reliably).

Instead, create or edit your personal ~/.vimrc file:

```
mkdir -p ~/.vim/colors
cp ~/.vim/colors/desert.vim ~/.vim/colors/   # just in case

cat > ~/.vimrc << EOF
syntax on
colorscheme desert
EOF
```

### Alternative: One-liner to do everything

Run these commands one by one:

```
sudo apt update && sudo apt install git vim -y

git clone https://github.com/flazz/vim-colorschemes.git ~/.vim/

cat > ~/.vimrc << 'EOF'
syntax on
colorscheme desert
set background=dark
EOF
```

# Raspberry Pi - Kiosk

## Configure kiosk mode

clear chrome cache

```bash
rm -rf ~/.cache/chromium ~/.config/chromium
```

New one [https://reelyactive.github.io/diy/pi-kiosk/](https://reelyactive.github.io/diy/pi-kiosk/)

[https://github.com/debloper/piosk](https://github.com/debloper/piosk)

Change hostname if not already done

```bash
sudo hostnamectl set-hostname ???
sudo reboot
```

Install the following

```shell
sudo apt install xdotool unclutter
```

Create a kiosk file

```bash
sudo nano /home/pi/kiosk.sh
```

Paste the following in for chromium

```shell
#!/bin/bash

xset s noblank
xset s off
xset -dpms

unclutter -idle 0.5 -root &

sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences

#/usr/bin/chromium-browser --noerrdialogs --disable-infobars --kiosk https://www.raspberrypi.com/ https://time.is/London &
#/usr/bin/chromium-browser --no-sandbox --window-size=1024,768 --kiosk --window-position=0,0 https://hdrcameras.onling.com:5001/webman/3rdparty/SurveillanceStation/?launchApp=SYNO.SS.App.VideoViewerVue.Instance&SynoToken=W9ZwQIG7NiF1Q &
#/usr/bin/chromium-browser --window-size=1080,720 --kiosk --window-position=0,0 https://www.hammerdownrange.com/lobby/index.php &
/usr/bin/chromium-browser --window-size=1080,720 --kiosk --window-position=0,0 https://www.hammerdownrange.com/lineup/lineup.php &
 
while true; do
   xdotool keydown ctrl+Tab; xdotool keyup ctrl+Tab;
   sleep 10
done
```

Paste the following in for firefox

```bash
# Disable screen blanking and power management (works on both X11 and Wayland via xwayland compatibility)
xset s noblank
xset s off
xset -dpms

# Hide mouse cursor (unclutter works best on X11; if you're on pure Wayland, see notes below)
unclutter -idle 0.5 -root &

# Optional: Clean any crash flags (Firefox is more forgiving, but harmless to keep)
sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.mozilla/firefox/*.default*/prefs.js 2>/dev/null || true

# Launch Firefox in kiosk mode
# -kiosk          → Fullscreen kiosk (hides UI, prevents exiting easily)
/usr/bin/firefox --kiosk --private-window https://synology.onling.com/webman/3rdparty/SurveillanceStation/login.cgi?SynoToken=nQhMc44EQyoEpeg &

# Optional: Cycle tabs / refresh every 10 seconds (your original behavior)
# If you only have one URL, you can comment this out or change it to a refresh instead
while true; do
    # Send Ctrl+Tab to cycle tabs (if you open multiple tabs)
    xdotool keydown ctrl+Tab; xdotool keyup ctrl+Tab;
    sleep 10
done
```

Make it executable

```bash
sudo chmod 777 /home/pi/kiosk.sh  
```

Make a service file to auto startup

```shell
sudo nano /lib/systemd/system/kiosk.service
```

Paste the following in

```shell
[Unit]
Description=Firefox Kiosk Mode
After=graphical.target
Wants=graphical.target

[Service]
Type=simple
Environment=DISPLAY=:0
ExecStart=/home/pi/kiosk.sh
Restart=always
RestartSec=5
User=pi
WorkingDirectory=/home/pi

[Install]
WantedBy=graphical.target
```

Make it so it auto starts and start it

```shell
sudo systemctl enable kiosk.service
sudo systemctl start kiosk.service
```

# Linux - Setup FTP and sFTP Server on Raspberry PI

### Introduction

Are you looking to set up an FTP server on your Raspberry PI, Rocky, Ubuntu or Debian-based operating system? vsftpd is a reliable and secure solution that allows you to transfer files between your computer and a remote server.

In this comprehensive guide, I’ll walk you through the process of installing and using vsftpd step by step. Whether you’re a beginner or an experienced user, this guide has got you covered.

#### Installing VSFTPD

Before we proceed let us ensure that our Raspberry Pi OS is running the latest available packages.

To update all packages on the device you will need to run the following two commands on the terminal.

```bash
sudo apt update
sudo apt upgrade -y
```

Updating all packages ensures that we shouldn’t run in to any weird issues when installing vsftpd on to our Raspberry Pi.

Once the update process has completed we can now install the software we require.

Install vsftpd to your Raspberry Pi by using the command below.

```bash
sudo apt install vsftpd
```

Before you can start using vsftpd, you need to configure it to suit your needs. To do this, we’ll need to make a few changes to the vsftpd configuration file. Open the file using the following command:

```sh
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.orig
sudo nano /etc/vsftpd.conf
```

<div class="codeblock-container" id="bkmrk-inside-the-configura"><div class="highlight"><div class="chroma">  
</div></div>Inside the configuration file, you’ll find various settings that you can customize. For example, you can enable or disable anonymous login, set up local user accounts, and define the directories accessible to each user.</div><div class="codeblock-container" id="bkmrk-">  
</div><div class="codeblock-container" id="bkmrk-change-the-following">Change the following:</div>```
# Change or enable these values
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
# Add the following to the very end
user_sub_token=$USER
local_root=/home/$USER/ftp

userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO
```

<div class="codeblock-container" id="bkmrk--1"></div>Once you’ve made the necessary changes, save the file and exit the editor. To apply the new configuration, restart the vsftpd service by running the following command:

```sh
sudo systemctl restart vsftpd
```

#### Creating a User

To make use of vsftpd, you’ll need to create user accounts that can access the FTP server. This allows you to control who can upload and download files. To create a new user account, use the adduser command followed by the desired username.

##### Script to use

Create a file in your home folder and, eg: sudo nano addFTP.sh

```bash
#!/bin/bash

# Configuration
USERNAME="$1"
PASSWORD="$2"
LOG_IDENTIFIER="create_user"  # Identifier for syslog entries
USER_LIST_FILE="/etc/vsftpd.userlist" # File to append usernames

# Function to log messages to syslog
log() {
  logger -t "$LOG_IDENTIFIER" "$1"
}

# Check if arguments are provided
if [ -z "$USERNAME" ]; then
  log "Error: Username is missing."
  exit 1
fi

if [ -z "$PASSWORD" ]; then
  log "Error: Password is missing."
  exit 1
fi

user_id=$(id -u "$USERNAME" &>/dev/null)

# Check if the user already exists
if [ ! $user_id = "" ]; then
  log "Error: User '$USERNAME' already exists."
  exit 1
fi

# Create the user
log "Creating user '$USERNAME'..."
sudo useradd "$USERNAME"

if [ $? -ne 0 ]; then
  log "Error: Failed to create user '$USERNAME'."
  exit 1
fi

# Set the password (using a non-interactive method)
log "Setting password for user '$USERNAME'..."
echo "$USERNAME:$PASSWORD" | chpasswd

if [ $? -ne 0 ]; then
  log "Error: Failed to set password for user '$USERNAME'."
  sudo userdel "$USERNAME"
  log "Cleaning up user '$USERNAME' due to password failure."
  exit 1
fi

log "User '$USERNAME' created successfully."
# Append username to the user list file
#sudo echo "$USERNAME" >> "$USER_LIST_FILE"
echo "$USERNAME" | sudo tee -a "$USER_LIST_FILE"

if [ $? -ne 0 ]; then
  log "Error: Failed to append username to '$USER_LIST_FILE'."
  sudo userdel "$USERNAME" # if the file append fails, delete the created user.
  exit 1
fi

log "Creating the ftp folder"
sudo mkdir -p /home/$USERNAME/ftp

log "Change the owner to nobody:nogroup"
sudo chown nobody:nogroup /home/$USERNAME/ftp

log "Adding the correct permissions"
sudo chmod a-w /home/$USERNAME/ftp

log "Showing the permissions on the ftp folder"
sudo ls -la /home/$USERNAME/ftp

log "Making a files folder within the '$USERNAME' folder"
sudo mkdir /home/$USERNAME/ftp/files

log "Changing the ownership on the files folder for the user"
sudo chown $USERNAME:$USERNAME /home/$USERNAME/ftp/files

log "Showing the permissions within the ftp folder"
sudo ls -la /home/$USERNAME/ftp

log "Change the user to have FTP access only"
sudo usermod -s /bin/ftponly $USERNAME

exit 0 # Exit with a zero status to indicate success.

```

Change the permissions on the file

```bash
chmod 777 addFTP.sh
```

Run like this to add a FTP user, eg: \[script\] \[username\] \[password\]

```bash
addFTP.sh steve 1E3%^fq
```

#### Enabling FTPS (FTP over SSL)

o add an extra layer of security to your FTP server, you can enable FTPS, which is FTP over SSL. This encrypts the data transferred between the client and the server, ensuring that it cannot be intercepted by unauthorized users.

To enable FTPS, we need to create an SSL certificate. Run the following command to generate the certificate:

```sh
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem
```

During the certificate generation process, you will be prompted to provide information such as the country code, state, and organization name. Once the certificate is generated, we can proceed with the configuration.

Open the vsftpd configuration file again:

```sh
sudo nano /etc/vsftpd.conf
```

Scroll down to the bottom of the file and locate the RSA certificate settings. Replace the paths with the following:

```sh
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH
```

Save the file and exit the editor. Restart the vsftpd service to apply the changes:

```sh
sudo systemctl restart vsftpd
```

Your FTP server is now configured to accept FTPS connections. You can test this by connecting to the server using an FTP client that supports FTPS.

#### Securing FTP User Access

To further enhance security, you can limit FTP users to only FTP access and disable shell access. This prevents users from accessing the command line interface on your server.

To restrict FTP user access, we need to create a limited shell. Run the following command to create the shell script:

```sh
sudo nano /bin/ftponly
```

Inside the editor, add the following line:

```sh
#!/bin/sh
echo "Limited to FTP access only"
```

<div class="codeblock-container smallButton" id="bkmrk-save-the-file-and-ex-1"><div class="codeblock-container"><div class="highlight">  
</div>Save the file and exit the editor. Next, make the shell script executable:</div><button class="copy-code drac-btn drac-btn-outline drac-text-purple drac-m-sm"></button></div>```sh
sudo chmod a+x /bin/ftponly
```

<div class="codeblock-container smallButton" id="bkmrk-to-enforce-the-limit"><div class="codeblock-container smallButton"><div class="highlight">  
</div>To enforce the limited shell, open the /etc/shells file:</div><button class="copy-code drac-btn drac-btn-outline drac-text-purple drac-m-sm"></button></div>```sh
sudo nano /etc/shells
```

<div class="codeblock-container smallButton" id="bkmrk-scroll-to-the-bottom"><div class="codeblock-container smallButton"><div class="highlight">  
</div>Scroll to the bottom of the file and add the following line:</div><button class="copy-code drac-btn drac-btn-outline drac-text-purple drac-m-sm"></button></div>```sh
/bin/ftponly
```

Save the file and exit the editor. Finally, modify the user’s account to use the limited shell:

```sh
sudo usermod -s /bin/ftponly ftpuser
```

<div class="codeblock-container smallButton" id="bkmrk-now%2C-if-the-user-tri"><div class="codeblock-container smallButton"><div class="highlight">  
</div>Now, if the user tries to access the server via SSH, they will be denied access. However, they can still connect to the FTP server using their FTP client.</div></div><div class="codeblock-container smallButton" id="bkmrk--2"></div><div class="codeblock-container smallButton" id="bkmrk-resource%3A-https%3A%2F%2Fhu">resource: [https://hub.tcno.co/linux/debian/vsftpd/](https://hub.tcno.co/linux/debian/vsftpd/)</div><div class="codeblock-container smallButton" id="bkmrk--3"></div><div class="codeblock-container smallButton" id="bkmrk--4"><button class="copy-code drac-btn drac-btn-outline drac-text-purple drac-m-sm"></button><div class="highlight"><div class="chroma">  
</div></div></div>

# Pi-Hole - Adding blocklist urls to the Gravity DB from the command-line

This is to add block list to the Gravity DB from the command line from a text file.

You will need a few things to do this

This is for allowing zmodem options if you telnet session allows it like SecurCRT that I used.

Install the following packages

```bash
sudo apt-get install lrzsz
sudo apt-get install sqlite3
```

Add the URL's per line for example

<table border="1" id="bkmrk-https%3A%2F%2Fraw.githubus" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td>https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts  
https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt  
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts  
https://v.firebog.net/hosts/static/w3kbl.txt  
https://adaway.org/hosts.txt  
https://v.firebog.net/hosts/AdguardDNS.txt  
https://v.firebog.net/hosts/Admiral.txt  
https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt  
https://s3.amazonaws.com/lists.disconnect.me/simple\_ad.txt  
https://v.firebog.net/hosts/Easylist.txt  
https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&amp;showintro=0&amp;mimetype=plaintext  
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts  
https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts  
https://v.firebog.net/hosts/Easyprivacy.txt  
https://v.firebog.net/hosts/Prigent-Ads.txt  
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts  
https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt  
https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt  
https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt  
https://s3.amazonaws.com/lists.disconnect.me/simple\_malvertising.txt  
https://v.firebog.net/hosts/Prigent-Crypto.txt  
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts  
https://bitbucket.org/ethanr/dns-blacklists/raw/8575c9f96e5b4a1308f2f12394abd86d0927a4a0/bad\_lists/Mandiant\_APT1\_Report\_Appendix\_D.txt  
https://phishing.army/download/phishing\_army\_blocklist\_extended.txt  
https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-malware.txt  
https://v.firebog.net/hosts/RPiList-Malware.txt  
https://v.firebog.net/hosts/RPiList-Phishing.txt  
https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt  
https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/generated/hosts  
https://urlhaus.abuse.ch/downloads/hostfile/  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/child-protection  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/gambling  
https://raw.githubusercontent.com/mhhakim/pihole-blocklist/master/porn.txt  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/pornblock2  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/pornblock3  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/pornblock4  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/pornblock5  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/pornblock6  
https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/porn/hosts  
https://raw.githubusercontent.com/RPiList/specials/master/Blocklisten/spam.mails

</td></tr></tbody></table>

To add these URL's you have to add them to the following file

```bash
sudo vi /etc/pihole/adlists.list
```

Then create a script and call it what ever you like and put this in

```bash
#!/bin/bash

#Get all URLs from file and add them to the gravity database
while IFS= read -r url; do
sqlite3 /etc/pihole/gravity.db "INSERT INTO adlist (address, enabled, comment) VALUES ('$url', 1, 'FROM ADLIST');
"
done < /etc/pihole/adlists.list 
```

#### Docker Users

If you place the script within the working directory of pihole container you can do the following:

```bash
docker exec -it pihole chmod +x /etc/pihole/bash_script.sh
docker exec -it pihole chmod 777 /etc/pihole/adlists.list
docker exec -it pihole ./etc/pihole/bash_script.sh
```

#### Error Check

Run the following to make sure your database is still okay and does not display any errors like these

<table border="1" id="bkmrk-2025-03-25-21%3A53%3A21." style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td><span class="hljs-number">2025</span><span class="hljs-number">-03</span><span class="hljs-number">-25</span> <span class="hljs-number">21</span>:<span class="hljs-number">53</span>:<span class="hljs-number">21.039</span> EDT \[<span class="hljs-number">1353</span><span class="hljs-operator">/</span>T9050\] ERROR: SQLite3: <span class="hljs-keyword">no</span> such <span class="hljs-keyword">table</span>: info <span class="hljs-keyword">in</span> "SELECT value FROM info WHERE property = 'updated';" (<span class="hljs-number">1</span>) <span class="hljs-number">2025</span><span class="hljs-number">-03</span><span class="hljs-number">-25</span> <span class="hljs-number">21</span>:<span class="hljs-number">53</span>:<span class="hljs-number">21.039</span> EDT \[<span class="hljs-number">1353</span><span class="hljs-operator">/</span>T9050\] WARNING: gravity\_updated(): <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">value</span> <span class="hljs-keyword">FROM</span> info <span class="hljs-keyword">WHERE</span> property <span class="hljs-operator">=</span> <span class="hljs-string">'updated'</span>; <span class="hljs-operator">-</span> <span class="hljs-keyword">SQL</span> error <span class="hljs-keyword">prepare</span>: <span class="hljs-keyword">SQL</span> logic error</td></tr></tbody></table>

If so just rebuild the database like this

```bash
sudo mv /etc/pihole/gravity.db /etc/pihole/gravity_backup.db
sudo pihole -g
```

# Prometheus - Raspberry PI Node Exporter Install

This is to install the node exporter on a raspberry pi for Prometheus to scrap.

#### Step1: Download

Install the node exporter for Prometheus on your Raspberry Pi

You will need to look at here for the current version of the node exporter from github

```bash
https://github.com/prometheus/node_exporter/releases
```

#### Step2: Install

Log into your raspberry pi

Once you have the latest located from step 1 then right click on it to get the link copied in your clipboard, for this example we are using 1.91 version

```bash
wget https://github.com/prometheus/node_exporter/releases/download/v1.9.1/node_exporter-1.9.1.linux-armv7.tar.gz
```

Now un-tar the release using this command.

```bash
tar -xvzf node_exporter-1.9.1.linux-armv7.tar.gz
```

This will un-tar the files into a sub-directory that looks like this.

<table border="1" id="bkmrk-node_exporter-1.9.1." style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td>node\_exporter-1.9.1.linux-armv7/  
node\_exporter-1.9.1.linux-armv7/node\_exporter  
node\_exporter-1.9.1.linux-armv7/NOTICE  
node\_exporter-1.9.1.linux-armv7/LICENSE</td></tr></tbody></table>

The only file we need out of the expanded tarball is the `node_exporter` binary. Copy that file to `/usr/local/bin`.

```bash
sudo cp node_exporter-1.9.1.linux-armv7/node_exporter /usr/local/bin
```

Use the chmod command to make the node\_exporter binary executable.

```bash
sudo chmod +x /usr/local/bin/node_exporter
```

#### Step 3 – Setup systemd unit file

Next step, setting up the unit file. The unit file will allow us to control the service via the `systemctl` command. Additionally it will ensure node\_exporter starts on boot.

Create a file called `node_exporter.service` in the `/etc/sytemd/system` directory. The full path to the file should be:

```bash
sudo nano /etc/systemd/system/node_exporter.service
```

Put the following contents into the file:

```bash
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
#User=pi  # Or the user you want to run it as, or leave commented out for default
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

Now lets reload systemd, enable and start the service.

```bash
sudo systemctl daemon-reload 
sudo systemctl enable node_exporter.service
sudo systemctl start node_exporter.service
sudo systemctl status node_exporter
```

#### Step4: Test

You can test if the setup works this way as well

```bash
curl http://localhost:9100
```

#### Next steps on Prometheus

Now you should add the metrics endpoint as a target to your Prometheus server. You can do this by editing the prometheus configuration file on your prometheus server. For reference mine looks like this.

```yaml
# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'
    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    static_configs:
    - targets: ['localhost:9090']

  - job_name: 'raspberry_pi'
    scrape_interval: 5s
    static_configs:
    - targets: ['pi1.sflservicesllc.com::9100','pi2.sflservicesllc.com:9100']
```

This is the standard prometheus config file. However I added the following target at the end for my Raspberry Pi:

```yaml
- job_name: 'pi1'
    scrape_interval: 5s
    static_configs:
    - targets: ['pi1.sflservicesllc.com::9100']
```

The IP address of my Raspberry Pi is `10.1.100.2`. The Port `9100` corresponds is the port used by node\_exporter.

Restart Prometheus server to start scrapping

# Raspberry PI - Uctronics panel setup

This is to setup the panel on the rack mount UCTRONICS raspberry pi holder with SSD drives

You will need to get the following from GitHub

```bash
git clone https://github.com/UCTRONICS/SKU_RM0004.git
```

Compile the download

```bash
cd SKU_RM0004
make clean && make 
```

Run this to auto configure

```bash
./deployment_service.sh   
```

Reboot your Pi

```bash
sudo reboot
```

Below Depricated

<s>You will have to modify the following file</s>

```bash
sudo nano /boot/config.txt
or
sudo nano /boot/firmware/config.txt
```

<s>At the end of the file add below the last \[ALL\] section</s>

```bash
dtparam=i2c_arm=on,i2c_arm_baudrate=400000
dtoverlay=gpio-shutdown,gpio_pin=4,active_low=1,gpio_pull=up
```

<s>You will need to get the following from GitHub</s>

```bash
git clone https://github.com/UCTRONICS/SKU_RM0004.git
```

<s>Run the following</s>

```bash
cd SKU_RM0004
make
```

<s>Edit the following file: </s>

```bash
sudo nano /etc/rc.local
```

<s>You will need to add the following after the fi and before the exit 0</s>

<table border="1" id="bkmrk-_ip%3D%24%28hostname--i%29-%7C" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td><s>\_IP=$(hostname -I) || true</s>  
<s>if \[ "$\_IP" \]; then</s>  
<s> printf "My IP address is %s\\n" "$\_IP"</s>  
<s>fi</s>

<s>&lt;&lt;&lt;HERE&gt;&gt;&gt;</s>

<s>exit 0</s>

</td></tr></tbody></table>

<s>Once modified should look like this</s>

<table border="1" id="bkmrk-%23%21%2Fbin%2Fsh--e%23%23-rc.lo" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td><s>\#!/bin/sh -e</s>  
<s>\#</s>  
<s>\# rc.local</s>  
<s>\#</s>  
<s>\# This script is executed at the end of each multiuser runlevel.</s>  
<s>\# Make sure that the script will "exit 0" on success or any other</s>  
<s>\# value on error.</s>  
<s>\#</s>  
<s>\# In order to enable or disable this script just change the execution</s>  
<s>\# bits.</s>  
<s>\#</s>  
<s>\# By default this script does nothing.</s>

<s>\# Print the IP address</s>  
<s>\_IP=$(hostname -I) || true</s>  
<s>if \[ "$\_IP" \]; then</s>  
<s> printf "My IP address is %s\\n" "$\_IP"</s>  
<s>fi</s>

<s><span data-darkreader-inline-color="" style="color: rgb(45, 194, 107);">**cd /home/pi/SKU\_RM0004**</span></s>  
<s><span data-darkreader-inline-color="" style="color: rgb(45, 194, 107);">**make clean** </span></s>  
<s><span data-darkreader-inline-color="" style="color: rgb(45, 194, 107);">**make** </span></s>  
<s><span data-darkreader-inline-color="" style="color: rgb(45, 194, 107);">**./display &amp;**</span></s>

<s>exit 0</s>

</td></tr></tbody></table>

<s>Run the following:</s>

```bash
cd /home/pi/SKU_RM0004
make clean 
make 
./display &
```

# Raspberry PI - Install NFS Server

```bash
dnf install nfs-kernel-server
```

```bash
sudo cp /etc/exports exports.org
```

```
vi /etc/exports
```

Configure NFS Exports: Edit the /etc/exports file to define the directories to be shared and the clients allowed to access them.

Export the new change

```bash
sudo nano /etc/exports
```

add a folder to share

```bash
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
/home/ftp 192.168.253.0/255.255.255.0(rw,no_subtree_check)
```

On the client side

```bash
vi /etc/fstab 
```

Add after the current drives

```bash
#Custom
192.168.253.100:/home/ftp /var/www/html/files nfs auto,default 0 0
```

# Raspberry PI- Pi-Nut Network

Installing Network UPS Tools (NUT) version 2.8.3 from source on a Raspberry Pi 4 running Raspberry Pi OS (based on Debian) requires compiling the software from the source code, as a pre-built Debian package for this specific version may not be available. Below are the detailed steps to accomplish this, tailored for a Raspberry Pi 4. These instructions assume you're using Raspberry Pi OS 64-bit (based on Debian Bullseye or later), but they should also work for 32-bit with minor adjustments.

\---

\### Prerequisites  
1\. \*\*Raspberry Pi OS\*\*: Ensure your Raspberry Pi 4 is running an up-to-date version of Raspberry Pi OS. Update the system before starting:

```bash
  sudo apt update && sudo apt upgrade -y
```

2\. \*\*Dependencies\*\*: You’ll need tools and libraries to compile NUT and support its functionality (e.g., USB, if your UPS connects via USB).  
3\. \*\*Internet Connection\*\*: Required to download the source code and dependencies.  
4\. \*\*UPS Connection\*\*: If using a USB-connected UPS, ensure it’s plugged into the Raspberry Pi before configuring NUT.

\### Step-by-Step Installation Guide

\#### 1. Install Required Dependencies  
NUT requires several development tools and libraries to build from source. Install them using:

```bash
sudo apt install -y build-essential autoconf automake libtool pkg-config \
libusb-dev libneon27-dev libsnmp-dev python3-dev python3-pip git
```

\- \*\*build-essential\*\*: Provides compilers (gcc, g++) and make.  
\- \*\*autoconf, automake, libtool\*\*: Needed to generate the configure script.  
\- \*\*pkg-config\*\*: Helps locate libraries during compilation.  
\- \*\*libusb-dev\*\*: Required for USB UPS support (common for modern UPS devices).  
\- \*\*libneon27-dev, libsnmp-dev\*\*: Optional, for network-based UPS protocols like SNMP.  
\- \*\*python3-dev, python3-pip\*\*: Optional, for Python-based NUT tools.  
\- \*\*git\*\*: Used to clone the NUT repository if needed.

If you need additional features (e.g., CGI for web interfaces), you can install `apache2` and `nut-cgi` dependencies later, as shown in some guides.\[\](https://technotim.live/posts/NUT-server-guide/)

\#### 2. Download NUT 2.8.3 Source Code  
The NUT 2.8.3 source code is available from the official NUT website or GitHub. Download the stable tarball for version 2.8.3:

```bash
wget https://networkupstools.org/source/2.8/nut-2.8.3.tar.gz
```

Verify the integrity of the downloaded file using the SHA-256 checksum (optional but recommended):

```bash
sha256sum nut-2.8.3.tar.gz
```

Compare the output with the SHA-256 sum provided on the NUT website (https://networkupstools.org/source/2.8/).\[\](https://networkupstools.org/historic/v2.8.3/download.html)

Extract the tarball:

```bash
tar -xzf nut-2.8.3.tar.gz
cd nut-2.8.3
```

Alternatively, if you prefer to clone the Git repository and check out the specific 2.8.3 tag:  
```bash  
git clone https://github.com/networkupstools/nut.git  
cd nut  
git checkout v2.8.3  
./autogen.sh  
```  
Note: The Git method requires `autoconf`, `automake`, and `libtool` to generate the configure script, as these are not included in the repository. The tarball already includes a pre-built configure script, making it simpler for most users.\[\](https://networkupstools.org/historic/v2.8.3/download.html)

\#### 3. Configure the Build  
Before compiling, configure the source tree for your system. Create a system user and group for NUT (e.g., `ups` and `nut`) to run the services securely:

```bash
sudo groupadd nut
sudo useradd -r -g nut -s /bin/false ups
```

-r : Creates a system user.  
-g nut: Assigns the user to the `nut` group.  
-s /bin/false: Prevents the user from logging in.

Now, configure the build with the appropriate user and group:  
```bash  
./configure --with-user=ups --with-group=nut --with-usb  
```  
\- `--with-user=ups` and `--with-group=nut`: Specify the user and group for NUT services.  
\- `--with-usb`: Enables USB support (common for UPS devices). Add other options like `--with-snmp` or `--with-cgi` if needed (see `./configure --help` for options).\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

If you encounter issues with missing dependencies, install them using `apt` (e.g., `sudo apt install libusb-1.0-0-dev` for USB support).\[\](https://github.com/networkupstools/nut/issues/2431)

\#### 4. Build and Install NUT  
Compile the source code:  
```bash  
make  
```  
This builds the NUT client, server, and selected drivers. If you encounter errors, check for missing dependencies or consult the NUT user manual.\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

Install the compiled programs:  
```bash  
sudo make install  
```  
This installs NUT to the default location (`/usr/local/ups`). Sample configuration files are installed with `.sample` extensions to avoid overwriting existing configurations.\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

Optionally, use `make install-as-root` to handle additional setup tasks like setting permissions and creating directories (see below).\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

\#### 5. Set Up the State Path  
Create a directory for NUT to store UPS status data and set appropriate permissions:  
```bash  
sudo mkdir -p /var/state/ups  
sudo chmod 0770 /var/state/ups  
sudo chown root:nut /var/state/ups  
```  
This ensures the `ups` user and `nut` group have access to the state path.\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

\#### 6. Configure USB Permissions (if using a USB UPS)  
If your UPS connects via USB, set permissions for the USB device to allow the `ups` user to access it. USB devices are dynamically created, so use `udev` rules to manage permissions. Create a `udev` rule:  
```bash  
sudo nano /etc/udev/rules.d/99-nut-ups.rules  
```  
Add the following (adjust `idVendor` and `idProduct` based on your UPS, which you can find using `lsusb` or `nut-scanner -U`):  
```bash  
SUBSYSTEM=="usb", ATTR{idVendor}=="051d", ATTR{idProduct}=="0002", MODE="0660", GROUP="nut"  
```  
Save and reload `udev` rules:  
```bash  
sudo udevadm control --reload-rules  
sudo udevadm trigger  
```  
Run `nut-scanner` to identify your UPS:  
```bash  
sudo nut-scanner -U  
```  
This should output details like `vendorid`, `productid`, and `driver` (e.g., `usbhid-ups`). Use these in the next step.\[\](https://technotim.live/posts/NUT-server-guide/)\[\](https://www.jeffgeerling.com/blog/2025/nut-on-my-pi-so-my-servers-dont-die)

\#### 7. Configure NUT  
NUT configuration files are installed in `/usr/local/ups/etc/`. Copy the sample files to their active versions:  
```bash  
sudo cp /usr/local/ups/etc/ups.conf.sample /usr/local/ups/etc/ups.conf  
sudo cp /usr/local/ups/etc/upsd.conf.sample /usr/local/ups/etc/upsd.conf  
sudo cp /usr/local/ups/etc/upsmon.conf.sample /usr/local/ups/etc/upsmon.conf  
sudo cp /usr/local/ups/etc/upsd.users.sample /usr/local/ups/etc/upsd.users  
sudo cp /usr/local/ups/etc/nut.conf.sample /usr/local/ups/etc/nut.conf  
```

Edit `ups.conf` to define your UPS:  
```bash  
sudo nano /usr/local/ups/etc/ups.conf  
```  
Example configuration (adjust based on `nut-scanner` output):  
```bash  
\[myups\]  
 driver = usbhid-ups  
 port = auto  
 desc = "My UPS"  
 vendorid = 051d  
 productid = 0002  
```  
Edit `upsd.conf` to allow network access:  
```bash  
sudo nano /usr/local/ups/etc/upsd.conf  
```  
Change:  
```bash  
LISTEN 127.0.0.1 3493  
```  
to:  
```bash  
LISTEN 0.0.0.0 3493  
```  
Edit `upsd.users` to define admin and monitor users:  
```bash  
sudo nano /usr/local/ups/etc/upsd.users  
```  
Example:  
```bash  
\[admin\]  
 password = myadminpassword  
 actions = set  
 actions = fsd  
 instcmds = all  
 upsmon primary

\[observer\]  
 password = myobserverpassword  
 upsmon secondary  
```  
Edit `upsmon.conf` to monitor the UPS:  
```bash  
sudo nano /usr/local/ups/etc/upsmon.conf  
```  
Example:  
```bash  
MONITOR myups@localhost 1 admin myadminpassword primary  
FINALDELAY 180  
```  
Set the NUT mode in `nut.conf`:  
```bash  
sudo nano /usr/local/ups/etc/nut.conf  
```  
Set:  
```bash  
MODE=netserver  
```

\#### 8. Start and Enable NUT Services  
Start the NUT driver and server:  
```bash  
sudo /usr/local/ups/sbin/upsdrvctl start  
sudo /usr/local/ups/sbin/upsd  
sudo /usr/local/ups/bin/upsmon  
```  
Enable services to start on boot:  
```bash  
sudo systemctl enable nut-server  
sudo systemctl enable nut-monitor  
sudo systemctl start nut-server  
sudo systemctl start nut-monitor  
```  
If `systemctl` commands fail, it may be due to missing systemd service files. Create them manually or use `make install-as-root` to generate them.\[\](https://www.jeffgeerling.com/blog/2025/nut-on-my-pi-so-my-servers-dont-die)\[\](https://networkupstools.org/docs/user-manual.chunked/ar01s05.html)

\#### 9. Verify Installation  
Check if NUT is working:  
```bash  
upsc myups@localhost  
```  
This should display UPS status details (e.g., `battery.charge`, `device.model`). If it fails, check logs in `/var/log/syslog` or `/var/log/messages` for errors.\[\](https://www.jeffgeerling.com/blog/2025/nut-on-my-pi-so-my-servers-dont-die)

\#### 10. Troubleshooting  
\- \*\*Command not found (e.g., `upsdrvctl`)\*\*: Ensure `/usr/local/ups/bin` and `/usr/local/ups/sbin` are in your PATH:  
 ```bash  
 export PATH=$PATH:/usr/local/ups/bin:/usr/local/ups/sbin  
 ```  
 Add this to `~/.bashrc` for persistence. This issue was reported in similar installations.\[\](https://forums.raspberrypi.com/viewtopic.php?t=334804)  
\- \*\*USB issues\*\*: Verify `libusb-1.0-0-dev` is installed and the `udev` rules are correct.\[\](https://github.com/networkupstools/nut/issues/2431)  
\- \*\*Service not starting\*\*: Check permissions on `/var/state/ups` and configuration files. Ensure the `ups` user has access.  
\- \*\*Driver issues\*\*: If `nut-scanner` doesn’t detect your UPS, consult the NUT hardware compatibility list (https://networkupstools.org/docs/user-manual.chunked/ar01s05.html) or try a different driver (e.g., `nutdrv\_qx`).\[\](https://www.jeffgeerling.com/blog/2025/nut-on-my-pi-so-my-servers-dont-die)

\#### 11. Optional: Install NUT CGI for Web Interface  
To monitor via a web interface:  
```bash  
sudo apt install apache2 nut-cgi  
sudo a2enmod cgi  
sudo systemctl restart apache2  
```  
Configure `/usr/local/ups/etc/hosts.conf`:  
```bash  
sudo nano /usr/local/ups/etc/hosts.conf  
```  
Example:  
```bash  
MONITOR myups@localhost "My UPS"  
```  
Access the web interface at `http://&lt;your-pi-ip&gt;/cgi-bin/nut/upsstats.cgi`.\[\](https://technotim.live/posts/NUT-server-guide/)

\---

\### Notes  
\- \*\*Why 2.8.3?\*\*: This version includes specific fixes and features not in earlier releases (e.g., improved driver support). Check the release notes for details (https://networkupstools.org/docs/release-notes.chunked/NUT\_Release\_Notes.html#\_release\_notes\_for\_nut\_2\_8\_3).\[\](https://github.com/networkupstools/nut/releases)  
\- \*\*Security\*\*: Set strong passwords in `upsd.users` and limit network access in `upsd.conf` if not needed.  
\- \*\*Upgrading\*\*: If upgrading from NUT 2.7.x, remove the old version first (`sudo apt remove nut nut-client nut-server`) to avoid conflicts.\[\](https://forums.raspberrypi.com/viewtopic.php?t=334804)  
\- \*\*Documentation\*\*: Refer to the NUT user manual (https://networkupstools.org/docs/user-manual.chunked/) for advanced configuration.\[\](https://networkupstools.org/docs/user-manual.pdf)

If you encounter specific errors, let me know the error messages, and I can provide targeted assistance!

# Raspberry PI - Error encountered raspi-firmware sense-hat

Error

<table border="1" id="bkmrk-dpkg%3A-error-processi" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td>dpkg: error processing package sense-hat (--configure):  
 dependency problems - leaving unconfigured  
Processing triggers for initramfs-tools (0.142+rpt4+deb12u3) ...  
Errors were encountered while processing:  
 raspi-firmware  
 sense-hat  
E: Sub-process /usr/bin/dpkg returned an error code (1)</td></tr></tbody></table>

These steps should make your broken system usable.

```bash
sudo umount /boot
sudo mkdir /boot/firmware
sudo sed -i "s:boot:boot/firmware:" /etc/fstab
sudo systemctl daemon-reload
sudo mount /boot/firmware
sudo apt -f install
```

# Raspberry Pi - Upgrade bulleys to trixie

First upgrade to bookworm

```bash
sudo apt update
sudo apt full-upgrade
sudo sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list
sudo sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list.d/*.list
sudo apt update
sudo apt full-upgrade
sudo reboot
```

You may get this error

[raspi-firmware or sense-hat](https://docs.sflservicesllc.com/books/raspberry-pi/page/raspberry-pi-error-encountered-raspi-firmware-sense-hat "Error")

Upgrade to trixie

```bash
sudo apt update
sudo apt full-upgrade
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list.d/*.list
sudo apt update
sudo apt full-upgrade
sudo reboot
```

If you get stuck with another error like this

<table border="1" id="bkmrk-errors-were-encounte" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 99.881%;"></col></colgroup><tbody><tr><td>Errors were encountered while processing:

 /var/cache/apt/archives/lxpanel\_0.11.1-1\_arm64.deb

</td></tr></tbody></table>

Run the following

```bash
sudo dpkg --purge --force-depends lxplug-cpu
sudo apt --fix-broken install
```

# Pi-Hole - Add DNS to your Pi-Hole from Active Directory LDAPS

This pulls DNS node names from Active Directory over LDAPS, resolves A records against the AD DNS server (dig), imports into Pi-hole's custom.list, and restarts DNS.

Make sure you have the ROOT cert on the pi-hole side:

**Certificate Trust Issue (by far the #1 cause with AD LDAPS)** Active Directory DCs usually use certificates issued by your internal Enterprise CA (or a self-signed one). Your Pi-hole doesn't trust it by default.

**Setup option:**

- **Recommended (secure)**: Export your root CA certificate from AD and trust it on the Pi-hole. 
    - On a Windows machine: Open MMC → Certificates → Trusted Root Certification Authorities → find your domain CA → Export as Base-64 encoded X.509 (.CER).
    - Copy the .cer file to Pi-hole: `/usr/local/share/ca-certificates/ad-root-ca.crt`
    - Run: `update-ca-certificates`

### How it works:

- Queries both **DomainDnsZones** and **ForestDnsZones**
- Handles hostnames with multiple IP addresses
- Improved skipping of junk records
- Proper error handling and logging
- Compatible with **Pi-hole v6** (uses systemctl restart pihole-FTL or fallback)
- Uses your domain onling.com as example (easily changeable)
- Safer password handling via file
- Backup of previous records

```bash
#!/bin/bash
# =============================================================================
# AD-to-Pi-hole DNS Sync Script (via LDAPS with LDAP fallback)
# Pulls DNS node names from Active Directory, resolves A records,
# imports into Pi-hole's custom.list, and restarts DNS.
#
# Requirements: sudo apt install -y ldap-utils dnsutils
# Run as root (or via sudo). Recommended via cron.
# =============================================================================
set -euo pipefail

# ========================== ANSI COLORS ==========================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

success() { echo -e "${GREEN}[✓] $1${NC}"; }
info()    { echo -e "${CYAN}[i] $1${NC}"; }
warn()    { echo -e "${YELLOW}[!] $1${NC}"; }
error()   { echo -e "${RED}[✗] $1${NC}"; }
header()  { echo -e "${MAGENTA}=== $1 ===${NC}"; }
# ================================================================

# ========================== CONFIGURATION ==========================
AD_DC="dom-001.local.com"
BIND_DN="CN=svcDevices,OU=Special_Users_Groups,DC=local,DC=com"
BIND_PASS_FILE="/root/.ad_bind_pass"
DOMAIN="local.com"

CUSTOM_LIST="/etc/pihole/custom.list"
BACKUP_DIR="/root/dns_backups"

# Optional: skip junk records (space-separated)
SKIP_PATTERNS="@ . _msdcs _tcp _udp _sites _gc _kerberos _kpasswd _ldap _smtp gc _domaincontroller"

# LDAPTLS settings (set to "never" only for testing)
export LDAPTLS_REQCERT=demand
# =================================================================

header "Starting Active Directory → Pi-hole DNS Sync"
echo -e "${BLUE}Started at: $(date '+%Y-%m-%d %H:%M:%S')${NC}\n"

# Create backup directory
mkdir -p "$BACKUP_DIR"
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/custom.list.${TIMESTAMP}.bak"

# Read password securely
if [ -f "$BIND_PASS_FILE" ]; then
    BIND_PASS=$(cat "$BIND_PASS_FILE")
    success "Password loaded from ${BIND_PASS_FILE}"
else
    error "Password file $BIND_PASS_FILE not found!"
    echo "Create it with:"
    echo "  echo 'YourPassword' > $BIND_PASS_FILE && chmod 600 $BIND_PASS_FILE"
    exit 1
fi

# Temporary files
TEMP_NAMES=$(mktemp)
TEMP_DOMAIN=$(mktemp)
TEMP_FOREST=$(mktemp)
TEMP_RECORDS=$(mktemp)
trap 'rm -f "$TEMP_NAMES" "$TEMP_DOMAIN" "$TEMP_FOREST" "$TEMP_RECORDS"' EXIT

# ====================== LDAP QUERY WITH FALLBACK ======================
DOMAIN_DN="DC=$(echo "$DOMAIN" | sed 's/\./,DC=/g')"

query_ldap() {
    local uri=$1
    local desc=$2

    info "Trying ${desc} (${uri})..."

    # DomainDnsZones
    info "  → Searching DomainDnsZones..."
    ldapsearch -H "${uri}" \
      -x -D "${BIND_DN}" -w "${BIND_PASS}" \
      -b "CN=MicrosoftDNS,DC=DomainDnsZones,${DOMAIN_DN}" \
      -s sub "(objectClass=dnsNode)" dc 2>"$TEMP_DOMAIN.err" | \
      grep -E "^dc:" | awk '{print $2}' | sort -u > "$TEMP_DOMAIN"

    # ForestDnsZones
    info "  → Searching ForestDnsZones..."
    ldapsearch -H "${uri}" \
      -x -D "${BIND_DN}" -w "${BIND_PASS}" \
      -b "CN=MicrosoftDNS,DC=ForestDnsZones,${DOMAIN_DN}" \
      -s sub "(objectClass=dnsNode)" dc 2>"$TEMP_FOREST.err" | \
      grep -E "^dc:" | awk '{print $2}' | sort -u > "$TEMP_FOREST"

    # Check if we got results
    if [ -s "$TEMP_DOMAIN" ] || [ -s "$TEMP_FOREST" ]; then
        success "LDAP query successful via ${desc}"
        return 0
    else
        warn "No results or error via ${desc}. Checking error output..."
        cat "$TEMP_DOMAIN.err" "$TEMP_FOREST.err" 2>/dev/null | tail -n 10
        return 1
    fi
}

# Try LDAPS first, then fallback to LDAP
if query_ldap "ldaps://${AD_DC}" "LDAPS (secure)"; then
    LDAP_SUCCESS=1
else
    warn "LDAPS failed. Falling back to plain LDAP (port 389)..."
    if query_ldap "ldap://${AD_DC}" "LDAP (fallback)"; then
        LDAP_SUCCESS=1
    else
        error "Both LDAPS and LDAP queries failed. Check credentials, network, firewall, and AD DC availability."
        exit 1
    fi
fi

# Combine and deduplicate
cat "$TEMP_DOMAIN" "$TEMP_FOREST" 2>/dev/null | sort -u > "$TEMP_NAMES"
NAME_COUNT=$(wc -l < "$TEMP_NAMES")

success "Found ${NAME_COUNT} unique DNS node names from AD."

if [ "$NAME_COUNT" -eq 0 ]; then
    error "No DNS nodes found. Please verify bind credentials and search bases."
    exit 1
fi

# ====================== RESOLVE A RECORDS ======================
header "Resolving A records against ${AD_DC}"
> "$TEMP_RECORDS"

while IFS= read -r name || [ -n "$name" ]; do
    [ -z "$name" ] && continue

    # Skip unwanted patterns
    if [[ " ${SKIP_PATTERNS} " == *" ${name} "* ]]; then
        info "  Skipping: ${name}"
        continue
    fi

    resolved=false
    for fqdn in "${name}.${DOMAIN}" "${name}"; do
        info "  Resolving: ${fqdn}"

        mapfile -t ips < <(dig @"${AD_DC}" +short +time=3 +tries=2 "${fqdn}" A 2>/dev/null | \
                          grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$')

        if [ ${#ips[@]} -gt 0 ]; then
            for ip in "${ips[@]}"; do
                echo "${ip} ${name}" >> "$TEMP_RECORDS"
                if [ "${fqdn}" != "${name}" ]; then
                    echo "${ip} ${fqdn}" >> "$TEMP_RECORDS"
                fi
            done
            success "    → ${#ips[@]} IP(s) found for ${fqdn}"
            resolved=true
            break
        fi
    done

    if ! $resolved; then
        warn "    No A record found for ${name}"
    fi
done < "$TEMP_NAMES"

sort -u "$TEMP_RECORDS" -o "$TEMP_RECORDS"
RECORD_COUNT=$(wc -l < "$TEMP_RECORDS")

success "Resolved ${RECORD_COUNT} A record entries."

# ====================== BACKUP & IMPORT ======================
header "Updating Pi-hole custom.list"

echo "Backing up current custom.list..."
if [ -f "$CUSTOM_LIST" ]; then
    cp -f "$CUSTOM_LIST" "$BACKUP_FILE"
    success "Backup created: ${BACKUP_FILE}"
else
    warn "No existing custom.list found (first run?)"
fi

info "Writing ${RECORD_COUNT} new records to ${CUSTOM_LIST}..."
cp "$TEMP_RECORDS" "$CUSTOM_LIST"
chown pihole:pihole "$CUSTOM_LIST" 2>/dev/null || true
chmod 644 "$CUSTOM_LIST"
success "Custom list updated."

# ====================== RESTART PI-HOLE ======================
header "Restarting Pi-hole DNS"
if command -v systemctl >/dev/null 2>&1; then
    systemctl restart pihole-FTL && success "Restarted via: systemctl restart pihole-FTL" || error "Failed to restart pihole-FTL"
else
    service pihole-FTL restart && success "Restarted via: service pihole-FTL restart" || error "Failed to restart pihole-FTL"
fi

# ====================== SUMMARY ======================
header "Sync Completed Successfully"
echo -e "${GREEN}Imported ${RECORD_COUNT} entries from Active Directory.${NC}"
echo -e "Total unique hostnames processed: ${NAME_COUNT}"
echo -e "Backup: ${BACKUP_FILE}"
echo ""
echo -e "${CYAN}Quick verification commands:${NC}"
echo "  pihole -q <hostname>"
echo "  sudo journalctl -u pihole-FTL -n 50 --no-pager"
echo ""
echo -e "${BLUE}Finished at: $(date '+%Y-%m-%d %H:%M:%S')${NC}"

exit 0
```

### How to Deploy

1. Save as /usr/local/bin/ad-pihole-dns-sync.sh
2. Make executable: chmod +x /usr/local/bin/ad-pihole-dns-sync.sh
3. Create the password file securely: ```
    echo 'YourActualPassword' > /root/.ad_bind_pass
    chmod 600 /root/.ad_bind_pass
    ```
4. Update AD\_DC and BIND\_DN if needed.
5. Test: sudo /usr/local/bin/ad-pihole-dns-sync.sh
6. Add to cron (example: every hour): ```
    0 * * * * /usr/local/bin/ad-pihole-dns-sync.sh >> /var/log/ad-dns-sync.log 2>&1
    ```

# Raspberry Pi - Zero 2 W RTSP Server

## Introduction

While setting up my smart home I was looking into creating a cost effective [NVR](https://en.wikipedia.org/wiki/Network_video_recorder) that would allow for a high degree of privacy and control. The choice of NVR software fell on the excellent [Frigate NVR](https://frigate.video/), it integrates well with Home Assistant and supports hardware accelerated object detection via the [little AI chip](https://coral.ai/products/accelerator) I had lying around.

The other part was having affordable, power-efficient camera hardware. There are many network-attached cameras on the market, but most of them require external services to set up/function and software wise they are black-boxes which raises considerable privacy concerns.

The choice fell on the Raspberry Pi Zero 2 running the default Raspberry Pi OS. The original Raspberry Pi Zero (v1) boards unfortunately are not suitable for streaming video in Full-HD, the CPUs were running at the limit and got too hot started heavily throttling. Fortunately the Raspberry Pi Zero 2 alleviated these issues at a similar price point (once they became available again in 2023/24).

The video to Frigate has to be an RTSP stream, to facilitate this we will be running [MediaMTX](https://github.com/bluenviron/mediamtx) via docker.

## OS Setup

To set up the boot media for the Pi Zero we run Raspberry Pi imager

1. Click `Choose device` -&gt; `Raspberry Pi Zero 2 W`.
2. Click `Choose OS` -&gt; `Raspberry Pi OS (other)` -&gt; `Raspberry Pi OS (Legacy, 32 bit) Lite`.
3. Click `Choose Storage` -&gt; Select the SD Card.
4. Click `Next` -&gt; `Edit Settings`.
5. Under `General` set desired hostname, credentials, etc.
6. Under `Services` -&gt; `Enable SSH`. 7 Click `Yes` to create the boot media for the Pi Zero.

Now we transfer the Micro-SD card to the Raspberry Pi Zero with a connected camera.

## Hardware check

We will do this part locally on the Raspberry Pi, so we need to connect a keyboard and display to it, for the Pi Zero we’ll need two adapters to connect a keyboard and a monitor:

- USB-A -&gt; micro-USB
- HDMI -&gt; micro-HDMI

Boot up the Pi Zero and wait for the initial file system resize to complete.

Once it reboots we can log in as the picam user and do a short test of whether the camera is recognized by the OS:

<div class="expressive-code" id="bkmrk-terminal-window-libc"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">libcamera-hello</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>This should open a window on top of the terminal screen for a few seconds that shows the a camera feed.

## Network Setup

We want to set a static IP that will persist on the SD Card in case I want to switch it over to another Raspberry Pi.

For this we edit the dhcp daemon config

<div class="expressive-code" id="bkmrk-terminal-window-sudo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo nano /etc/dhcpcd.conf</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Towards the bottom we should see some commented out entries we can use. We just uncomment them and change the `ip_address` to our desired IP:

<div class="expressive-code" id="bkmrk-%2Fetc%2Fdhcpcd.conf-sta"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/etc/dhcpcd.conf</span></figcaption>```
```

<div class="ec-line"><div class="code">static ip_address=192.168.1.100/24</div></div>```
```

<div class="ec-line"><div class="code">static routers=192.168.1.1</div></div>```
```

<div class="ec-line"><div class="code">static domain_name_server=192.168.1.1</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>If there are any Raspberry Pi configurations we still want to change (e.g. enabling SSH in case we haven’t yet or setting the hostname)

Once we reboot we should be able to SSH into the machine

<div class="expressive-code" id="bkmrk-terminal-window-rebo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">reboot</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>## Upgrade/Install dependencies

We will install docker from the Debian repo after updating the OS packages:

<div class="expressive-code" id="bkmrk-terminal-window-sudo-1"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo apt-get update</div></div>```
```

<div class="ec-line"><div class="code">sudo apt-get upgrade -y</div></div>```
```

<div class="ec-line"><div class="code">sudo apt-get install -y docker.io</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Now we need to add the user to the docker group so it will have the right permissions

<div class="expressive-code" id="bkmrk-terminal-window-sudo-2"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo usermod -aG docker admin</div></div>```
```

<div class="ec-line"><div class="code">newgrp docker</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>## RSTP Server setup

With docker set up we can now use it to run MediaMTX as the RTSP server, lets start it up:

<div class="expressive-code" id="bkmrk-terminal-window-dock"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">docker run --rm -it --network=host --privileged --tmpfs /dev/shm:exec -v /run/udev:/run/udev:ro -e MTX-PATHS-CAM-SOURCE=rpiCamera bluenviron/mediamtx:latest-ffmpeg-rpi</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Once we verified it runs correctly we can set up the service. Create a script to run it:

<div class="expressive-code" id="bkmrk-terminal-window-mkdi"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">mkdir -p /home/admin/src/scripts</div></div>```
```

<div class="ec-line"><div class="code">nano /home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>with the following content (note, we’re removing `-it` from the above command for this script, as we don’t run an interactive shell for the service):

<div class="expressive-code" id="bkmrk-%2Fhome%2Fadmin%2Fsrc%2Fscri"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/home/admin/src/scripts/mediamtx.sh</span></figcaption>```
```

<div class="ec-line"><div class="code">\#!/bin/bash</div></div>```
```

<div class="ec-line"><div class="code">\# Will be exposed at rtsp://[ip]:8554/cam</div></div>```
```

<div class="ec-line"><div class="code">docker run --rm --network=host --privileged --tmpfs /dev/shm:exec -v /run/udev:/run/udev:ro -e MTX_PATHS_CAM_SOURCE=rpiCamera bluenviron/mediamtx:latest-ffmpeg-rpi</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>then make it executable:

<div class="expressive-code" id="bkmrk-terminal-window-chmo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">chmod +x /home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Now we add the service:

<div class="expressive-code" id="bkmrk-terminal-window-sudo-3"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo nano /etc/systemd/system/mediamtx.service</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>with:

<div class="expressive-code" id="bkmrk-%2Fetc%2Fsystemd%2Fsystem%2F"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/etc/systemd/system/mediamtx.service</span></figcaption>```
```

<div class="ec-line"><div class="code">[Unit]</div></div>```
```

<div class="ec-line"><div class="code">Description=MediaMTX</div></div>```
```

<div class="ec-line"><div class="code">After=network.target</div></div>```
```

<div class="ec-line"><div class="code">  
</div></div>```
```

<div class="ec-line"><div class="code">[Service]</div></div>```
```

<div class="ec-line"><div class="code">ExecStart=/home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="ec-line"><div class="code">Restart=always</div></div>```
```

<div class="ec-line"><div class="code">RestartSec=3</div></div>```
```

<div class="ec-line"><div class="code">User=admin</div></div>```
```

<div class="ec-line"><div class="code">Group=docker</div></div>```
```

<div class="ec-line"><div class="code">  
</div></div>```
```

<div class="ec-line"><div class="code">[Install]</div></div>```
```

<div class="ec-line"><div class="code">WantedBy=default.target</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Then we start it and activate startup on system start.

<div class="expressive-code" id="bkmrk-terminal-window-sudo-4"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo systemctl daemon-reload</div></div>```
```

<div class="ec-line"><div class="code">sudo systemctl start mediamtx</div></div>```
```

<div class="ec-line"><div class="code">\# Check logs to see if it starts up correctly</div></div>```
```

<div class="ec-line"><div class="code">journalctl -u mediamtx -f</div></div>```
```

<div class="ec-line"><div class="code">sudo systemctl enable mediamtx</div></div>```
```

take from [here](https://www.nephridium-labs.com/guides/picam/)

</figure></div>