Skip to content
View in the app

A better way to browse. Learn more.

Unraid

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

bmartino1 User scripts

Featured Replies

I have quite a few user scripts that I run from stable to pre release.

so here I will list all my user scripts unraid Pearl commands...
Mainly for script prosperity...

Some are adaptions and pulls from this forum and not my work, others have or had separate forum topics...
Also adding for devs as some are needed in prerelease bug reports.

  • Author

AppleSambaCleanup 

*This is a adaption, as downloading the user script plugin came with some default scripts.

When Apple Devices connect to Samba, They can leave behind broken and bad ds store data... this script is aimed to remove that data.

I run this script once a month to help clean up apple smb data..

https://crontab.guru/
cron:
0 0 1 */3 *

 

#!/bin/bash

# Define the base directory where your Samba shares are located
BASE_DIR="/mnt/user"

# Print a message indicating the start of the search and deletion
echo "Searching for (and deleting) .DS_Store files in $BASE_DIR"
echo "This may take a while..."

# Use the find command to search for and remove all .DS_Store files
find "$BASE_DIR" -type f -name ".DS_Store" -exec rm -f "{}" \;

# Confirm completion
echo "Cleanup completed. All .DS_Store files have been removed from $BASE_DIR."


#echo "Searching for (and deleting) .DS_Store Files"
#echo "This may take a awhile"
#find /mnt/user -maxdepth 9999 -noleaf -type f -name ".DS_Store" -exec rm "{}" ;


 

  • Author

bringbackmc

Since betas 3 v7 I run this at first array start...

started from unrad v7 beta 3:


as older version of mc ran in unraid had a move into directory when close feature...

adds custom script code to /etc/profile to bring back a function of mc that was in earlier version of unraid.

 

#!/bin/bash
# Script to add mc_cd function to /etc/profile if not already present

# Check if the mc_cd function is already in /etc/profile
if ! grep -q "mc_cd()" /etc/profile; then
    # Echo the mc_cd function and alias into /etc/profile
    echo "
    # Custom mc_cd function for Midnight Commander
    mc_cd() {
        # Create a temporary file to store the last directory
        MC_TMPFILE=\"/tmp/mc-last-dir.$$\"

        # Run Midnight Commander with the -P flag to store the last directory on exit
        mc -P \"\$MC_TMPFILE\"

        # After mc exits, read the last directory from the temp file
        if [ -f \"\$MC_TMPFILE\" ]; then
            LAST_DIR=\$(cat \"\$MC_TMPFILE\")
            rm -f \"\$MC_TMPFILE\"
            if [ -d \"\$LAST_DIR\" ]; then
                echo \"Changing to directory: \$LAST_DIR\"
                cd \"\$LAST_DIR\"
            else
                echo \"Invalid directory: \$LAST_DIR\"
            fi
        else
            echo \"mc did not create the directory file.\"
        fi
    }

    alias mc='mc_cd'
    " >> /etc/profile
fi


 

Edited by bmartino1

  • Author

DockerLogsCleanup

Warning some doctors need to be restarted. Stop start in order to re-engage logs and the capability of logging.

When running a pihole docker i hit my unraid docker image size and borked due to a spam in the logs.

Atm I have this scheldued to run once every 3 months:

https://crontab.guru/
cron:
0 0 1 */3 *

This will erase the largets docker logs and 
Turnacate and cleanup docker logs

 

#!/bin/bash

# Define the directory where Docker container logs are stored
LOG_DIR="/var/lib/docker/containers"

# List and calculate the size of the log files in the container directory, filter out directories and sort by size
echo "Listing top 60 largest Docker log files:"
du -ah $LOG_DIR | grep -v "/$" | grep ".log" | sort -rh | head -60

# Automatically proceed with cleanup without prompt
echo "Proceeding with log file cleanup..."
du -ah $LOG_DIR | grep -v "/$" | grep ".log" | sort -rh | head -60 | while read -r size file; do
    echo "Truncating $file..."
    cat /dev/null > "$file"
done

echo "Log cleanup completed."

 

Edited by bmartino1
Warning...

  • Author

DockerMaintenance 

Warning this will kill any and all non-running dockers... Docker Image volume maintenance Prune commands

The docker prune commands... 
https://docs.docker.com/reference/cli/docker/system/prune/
https://docs.docker.com/reference/cli/docker/image/prune/
https://docs.docker.com/reference/cli/docker/container/prune/

For general Maintence of docker services i run as i test alot and have hit and filled.
This orgianly was a pre sent script to handled docker dangling images...

 

#!/bin/bash

# Script to prune dangling Docker images and clean up

echo "Starting Docker maintenance..."

#Docker Unraid Check if dangling images exist
docker rmi $(docker images --quiet --filter "dangling=true")

# Prune dangling Docker images
echo "Pruning dangling Docker images..."
docker image prune -f

# Automatically prune unused containers, networks, and volumes
echo "Pruning unused containers, networks, and volumes..."
docker system prune -f --volumes

echo "Finished Docker maintenance."

 

  • Author

Ensure_TailScaleRoute
TailScaleVPN funnel route to guarantee subroute router...

I run this at first startup of the array

Tailscale is new to me. Not sure if my routes save if a reboot Since i had to run this command to 

#!/bin/bash
tailscale up --accept-routes --accept-dns=false --advertise-routes=%IP/CDRsubnet

*If using true. dockers may need extra parm --dns=8.8.8.8
Mainly A VPN to connect to my sytmes unless i funnel or use tsdproxy...

Edited by bmartino1

  • Author

Fix_Hosts
Script to run to replace default unraid host file. to fix dns and brodcast netbios
I9 run this script at first array boot...
 

#!/bin/bash
sleep 5
rm /etc/hosts
cp /boot/config/hosts /etc/hosts
chmod 644 /etc/hosts


Do to a unifi dns and hostname issues, FCP would constantly nag at me that the dns server for unraid and would need a route for itself.

I found this incredibly stupid and especial anything when unraid with the macvlan would bug and change its mac address for the docker network
This is a carry over script while i fixed hostnames, dns and other netbios traffic on my network...

nslookup should work with the first dns server and find my unriad box. As a temp fix i decided to add the ip address of my static unraid to its host file 1 to fix servers, and 2 to ignore/ shut the error in FCP... This was a workaround and the original forum post is lost as I did talk about it and decided fine this here is a permeant work around an F** it as this should have been in there to begin with... Even default Debian Linux installs have a hostname to localhost 127.0.0.1 ...

sadly echoing the data into the host file didn't restart the unraid networking. I have found that if i remvoe the host file and chmod it back then the host file would reset on unraid...

So since i set unraid to use pihole first. and now use pihole as a dns muticast for netbios...
I technly don't need this script now to run but keep it for other scripts ... But to help assit unraid pihole dns and unfi i maintain it..

my host file i replace curently:
 

#Search Domains:
127.0.0.1       localhost
127.0.0.1       localhost.localdomain
255.255.255.255 broadcasthost
::1             local
127.0.0.1       local
::1             lan
127.0.0.1       lan
::1             localdomain
127.0.0.1       localdomain
#IPV6:
::1             ip6-localhost ip6-loopback
fe00::0         ip6-localnet
ff00::0         ip6-mcastprefix
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters
ff02::3         ip6-allhosts
#fe80::1%lo0    localhost

#Unraid needed:
127.0.0.1 BMM-Unraid.localdomain
127.0.0.1 BMM-Unraid
#54.149.176.35     keys.lime-technology.com
^ May need to cat again and check since bet updates may have changed...

#Other Docker Services
192.168.2.254 BMM-Unraid
#teh static ip and docekr host name of all my unraid dockers...



This was later adapted to fix my orginal post on unraids messed up smb.conf...


 

  • Author

RestartShareServices

Original made for samba config replacement. The Devs took my suggestion! :)
now I can fix and use my true samba config without overwriting core smb stuff they use and do for the web ui. I can now safely remove and edit the smb.conf with my override config...

so I currently run this script to replace and run my own samba...
*depending on settings, this affect multiple services...
Form rpc to nfs to avahi mdns...
 
User script example:

#!/bin/bash

# -----------------------------------------------------------------------------
# Purpose:
#   Root-lock critical service config files using chattr +i so Unraid does not
#   overwrite them on boot or service restart.
#
#   This script is SAFE to re-run. If a file is immutable, it will be unlocked,
#   updated, and re-locked automatically.
#
# Notes:
#   - Currently ONLY Samba is active.
#   - Avahi and NFS are kept for future use and remain commented.
#   - Designed for Unraid (Slackware-based rc scripts).
# -----------------------------------------------------------------------------

sleep 30

# -----------------------------------------------------------------------------
# Safety helpers
# -----------------------------------------------------------------------------

ensure_mutable() {
    local file="$1"

    if [ -e "$file" ]; then
        if lsattr "$file" 2>/dev/null | grep -q 'i'; then
            echo "[INFO] Removing immutable flag from $file"
            chattr -i "$file"
        fi
    fi
}

ensure_immutable() {
    local file="$1"

    if [ -e "$file" ]; then
        echo "[INFO] Applying immutable flag to $file"
        chattr +i "$file"
    fi
}

# -----------------------------------------------------------------------------
# Avahi (MDNS)
# -----------------------------------------------------------------------------
# Avahi is used with macOS for mDNS discovery and sometimes requires manual
# editing for VLAN setups. Helpful for Samba and Apple OS shares.
#
# Currently DISABLED — retained for future use.
# -----------------------------------------------------------------------------

# AVAHI_CONF="/etc/avahi/avahi-daemon.conf"

# Stop the service
# /etc/rc.d/rc.avahidaemon stop

# ensure_mutable "$AVAHI_CONF"

# rm -f "$AVAHI_CONF"
# cp /boot/config/avahi-daemon.conf "$AVAHI_CONF"
# chown root:root "$AVAHI_CONF"
# chmod 644 "$AVAHI_CONF"

# Root lock so Unraid does not replace or edit the file
# ensure_immutable "$AVAHI_CONF"

# Start the service
# /etc/rc.d/rc.avahidaemon start

# -----------------------------------------------------------------------------
# Samba (SMBD / NMBD)
# -----------------------------------------------------------------------------
# Unraid ships Samba pre-packaged (Slackware).
# We override smb.conf and root-lock it to prevent regeneration.
# -----------------------------------------------------------------------------

SMB_CONF="/etc/samba/smb.conf"

# Stop the service
/etc/rc.d/rc.samba stop

# Ensure the file can be modified
ensure_mutable "$SMB_CONF"

# Replace the Samba configuration
rm -f "$SMB_CONF"
cp /boot/config/smb-override.conf "$SMB_CONF"

# Permissions
chown root:root "$SMB_CONF"
chmod 644 "$SMB_CONF"

# Root lock so Unraid cannot rewrite it
ensure_immutable "$SMB_CONF"

# Start the service
/etc/rc.d/rc.samba start

# -----------------------------------------------------------------------------
# NFS / RPC
# -----------------------------------------------------------------------------
# NFS exports are often rewritten by Unraid. Root locking prevents this.
#
# Currently DISABLED — retained for future use.
# -----------------------------------------------------------------------------

# EXPORTS="/etc/exports"

# Stop services
# /etc/rc.d/rc.nfsd stop
# /etc/rc.d/rc.rpc stop

# ensure_mutable "$EXPORTS"

# rm -f "$EXPORTS"
# cp /boot/config/exports.conf "$EXPORTS"
# chown root:root "$EXPORTS"
# chmod 644 "$EXPORTS"

# Root lock so Unraid cannot rewrite it
# ensure_immutable "$EXPORTS"

# Reload exports
# exportfs -ra

# Start services
# /etc/rc.d/rc.rpc start
# /etc/rc.d/rc.nfsd start


My example smb overide conf:
 

#root@BMM-Unraid:/boot/config# cat smb-override.conf 
# /boot/config/smb-override.conf
# This file is copied to /etc/samba/smb.conf by your boot script.

[global]
    ####################################################################
    # Base identity / names (Unraid-generated)
    ####################################################################
    include = /etc/samba/smb-names.conf
#some items are duplicates that are expresed again in this file. (devs were kind enoth to move item to smb.conf so we can use the webui options and include this file without incident TY Devs!!!)
	
    ####################################################################
    # Auth / guest behaviour
    ####################################################################
    security = user
    map to guest = Bad User
    guest account = nobody
    null passwords = yes

#Differenec in user controls... lets go unraid default... this is saved more for AD plugin and other edits that may be required...
#    passdb backend = smbpasswd
#    unix password sync = yes
#    pam password change = no
#    passwd program = /usr/bin/passwd %u
#    passwd chat = *Enter\snew\s*\spassword:* %n\n \
#                  *Retype\snew\s*\spassword:* %n\n \
#                  *password\supdated\ssuccessfully*
#unraid ignores unix sync outright now...

    #Unraid default - Keep user controls in the web ui and not the /etc/shadow nor samba smpasswd files that can get erased at reboot...
    unix password sync = no
    pam password change = no
    passdb backend = smbpasswd

    # Browser / master role
    domain master = no
    local master = yes
    preferred master = yes
    os level = 200

    ####################################################################
    # Protocol / network
    ####################################################################
    server min protocol = SMB2
    # server max protocol = SMB3
    server signing = Auto

    # NetBIOS behaviour
    disable netbios = yes
    # interfaces and bind interfaces only are handled in smb-names.conf
    #bind interfaces only = yes
    #interfaces = 192.168.1.254/24

    ####################################################################
    # Logging
    ####################################################################
    logging = syslog@0
    max log size = 1000

    ####################################################################
    # Printing disabled
    ####################################################################
    show add printer wizard = No
    disable spoolss = Yes
    load printers = No
    printing = bsd
    printcap name = /dev/null

    ####################################################################
    # POSIX + performance
    ####################################################################
    aio read size = 0
    aio write size = 0
    use sendfile = Yes
    wide links = Yes
    unix extensions = No

    acl allow execute always = Yes

    ####################################################################
    # Compatibility knobs
    ####################################################################
    ntlm auth = Yes
    smb3 directory leases = no

    ####################################################################
    # Default fruit / macOS tuning
    ####################################################################
    vfs objects = catia fruit streams_xattr
    fruit:encoding = native
    fruit:nfs_aces = No

    ####################################################################
    # Hook for extra config from Unraid GUI
    ####################################################################
    include = /boot/config/smb-extra.conf


[global]
    ####################################################################
    # Hooks for Unassigned Devices + normal array shares
    ####################################################################
    include = /etc/samba/smb-unassigned.conf
    include = /etc/samba/smb-shares.conf


#######################################################################
# MANUAL SHARES FOR REMOTE PVE DATASETS (NFS via Unassigned Devices)
# Every client op is forced to run as root:root on disk.
#######################################################################

#Example of a forced root share(we can use samba to force wirte as this user/group to are sahre... (would be nice to have a area on the /boot/samba for custom per share options to be included...)
[Samba_Share_Name]
    path = /mnt/user/samba
    browseable = yes
    read only = no
    guest ok = yes
    writeable = yes
    acl map full control = yes
    acl allow execute always = yes
    map archive = yes
    map system  = yes
    map hidden  = yes
    create mask        = 0775
    force create mode  = 0777
    directory mask     = 0777
    force directory mode = 0777
    force user  = root
    force group = root
    vfs objects = catia fruit streams_xattr
    fruit:encoding = native

#example Apple Time Machine (let apple define quota not unraid...)
[TimeMachine]
    path = /mnt/user/TimeMachine
    browseable = yes
    read only = no
    guest ok = no
    # time machien requires a samba user connected!
    valid users = samba_user root
    writeable = yes
    acl map full control = yes
    acl allow execute always = yes
    map archive = yes
    map system  = yes
    map hidden  = yes
    create mask        = 0660
    force create mode  = 0669
    directory mask     = 0770
    force directory mode = 0770
    force user  = root
    force group = root
    vfs objects = catia fruit streams_xattr
    fruit:encoding = native
    # If you want Unraid to advertise this as a Time Machine target:
    fruit:time machine = yes
    # If you want unraid asigned size quota
    ; fruit:time machine max size = 0
    fruit:metadata = stream
    fruit:resource = stream
    fruit:locking = none
    # ACL + extended attributes
    ea support = yes
    store dos attributes = yes


As there are some things I don't like with the default shipped config, others things that should still be in the main smb.conf and the include files only have global settings from the webui and not other 3rd paty static commands...

so, This functional and work as I want it to add better security and a functional smb/nfs server to my unraid system...
why this breaks on other IDK/IDC. Each network is different... alot of things can be set in a smb conf too much really, and unraids has had a half standard shipped smb approach to it... (while secure and great for first time users, it hinders advance users and the needs to edit how unraid shares work...)

Having built and maintained samba servers across a multitude of OS... for more than 20 years...
https://www.samba.org/samba/docs/4.9/man-html/smb.conf.5.html

I'd rather write my own smb config... sadly not all smb settings will work due to the limited Slackware prepackaged binary missing libs and other samba feature such as security like fips... It wasn't worth my time for a temp spin up.... nor try to go in for extra install and or a plugin to add a full samba with libs.


Sadly... Fips / Ad / ldap / pam ... not all of these features are working in unraid samba... missing libs and samba helper systems... (See plugin and other post on te forum if you want other Samba helpers...)
Especial with Vlans... sometimes one may want to edit the Avahi config... similar to host stop service remove file copy file form config folder set proper permission and start service with your configurations...

*Sometimes it just editing or adding interface and bind options for samba...

Example Avahi Config edit:

root@BMM-Unraid:~# cat /etc/avahi/avahi-daemon.conf 
# This file is part of avahi.
#
# avahi is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# avahi is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with avahi; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.

# See avahi-daemon.conf(5) for more information on this configuration
# file!

[server]
#host-name=foo
#domain-name=local
#browse-domains=0pointer.de, zeroconf.org
use-ipv4=yes
use-ipv6=no
allow-interfaces=eth0
#deny-interfaces=eth1
#check-response-ttl=no
#use-iff-running=no
#enable-dbus=yes
#disallow-other-stacks=no
#allow-point-to-point=no
#cache-entries-max=4096
#clients-max=4096
#objects-per-client-max=1024
#entries-per-entry-group-max=32
ratelimit-interval-usec=1000000
ratelimit-burst=1000

[wide-area]
enable-wide-area=yes

[publish]
#disable-publishing=no
#disable-user-service-publishing=no
#add-service-cookie=no
#publish-addresses=yes
publish-hinfo=no
publish-workstation=no
#publish-domain=yes
#publish-dns-servers=192.168.50.1, 192.168.50.2
#publish-resolv-conf-dns-servers=yes
#publish-aaaa-on-ipv4=yes
#publish-a-on-ipv6=no

[reflector]
#enable-reflector=no
#reflect-ipv=no
#reflect-filters=_airplay._tcp.local,_raop._tcp.local

[rlimits]
#rlimit-as=
#rlimit-core=0
#rlimit-data=8388608
#rlimit-fsize=0
#rlimit-nofile=768
#rlimit-stack=8388608
#rlimit-nproc=3


 *Look into root locking a file where root cant edit the file to apply the above to avahi ... attrib....+i to prevent root level edits and -i to unlock and make edits once more ....
--Was reluctant to share as the devs in the script have stuff that purges and writes the root file sin /etc for these services... and it wouldn't be hard to add a check attrib of +i and for the devs to add the -i action to there configs to undo this...

Edited by bmartino1
NEW INFO! Data - typo

  • Author

syslog-notify 
*this was actual a scirpt some on else on the forum shared(thanks!) and i modfied for my needs to quickly scan the syslog if a error of any kind occurred base on keywords, also to ignore certain one as i knew about them, but they are kernel level drive issues and not much could be done about them... (as we can leverage cron and are own notification outside of unraids notification systems...)

 

#!/bin/bash# ###################################### Name:        Syslog notify v1.3# Description: Creates notification if log contains errors or its size exceeds 90% of the available space# Author:      Marc Gutt# #####################################

# ###################################### Settings# #####################################

# get most recent syslog file
syslog_file=$(ls -t /var/log/syslog{.[0-9],} 2>/dev/null | head -n 1)

# words that should cause a notification
words="corrupt|error|fail|tainted"

# store line number of last found error in this file
log_file="/tmp/syslog-notify-last-error-line-number.log"

# ignore these phrases (you can't use more than 4 wildcards per line!)
ignore_lines=('kernel: CIFS: VFS: \\*\* error -9 on ioctl to get interface list' # unsolvable message from UD plugin'sshd[*]: Read error from remote host * port *: Connection reset by peer' # interrupted ssh connection'sshd[*]: Read error from remote host * port *: Connection timed out' # interrupted ssh connection'ACPI Error: Aborting method \_SB.PCI0.GPP3.PTXH.RHUB.POT3._PLD due to previous error (AE_AML_UNINITIALIZED_ELEMENT) (20220331/psparse-529)' #known acpi table bug)

# ###################################### Script# #####################################

# make script race condition safeif [[ -d "/tmp/${0//\//_}" ]] || ! mkdir "/tmp/${0//\//_}"; then echo "Script is already running!" && exit 1; fi; trap 'rmdir "/tmp/${0//\//_}"' EXIT;

# obtain line number of last checkif [[ -f "$log_file" ]]; then
  line_number_start=$(cat "$log_file")# syslog has been truncatedif [[ $line_number_start -gt $(grep -c ^ "$syslog_file") ]]; then
    line_number_start=0
  fi
# store last line number on first execution
else
  line_number_start=$(grep -c ^ "$syslog_file")
  line_number_start=$((line_number_start-100))
  echo "$line_number_start" > "$log_file"
fi

# parse logs
EOL=$'\n'
errors=""while read -r line; do# ignore specific linesfor ignore_line in "${ignore_lines[@]}"; do
    IFS=\* read -r one two three four <<< "$ignore_line"
    if [[ $line == *"$one"*"$two"*"$three"*"$four" ]]; then
      continue 2
    fi
  done
  # remember last line
  last_line="$line"# combine multiple error messages
  errors="$errors$EOL$line"
done < <(tail -n +"$((line_number_start+1))" "$syslog_file" | grep -iP "($words)")

# create notification for new errorsif [[ $errors ]]; then
  # remember line number of last error
  line_number_start=$(grep -nFx "$last_line" "$syslog_file" | cut -f 1 -d ":")
  echo "$line_number_start" > "$log_file"# send notification/usr/local/emhttp/webGui/scripts/notify -i "alert" -s "syslog $(echo "$errors" | grep -ioP "($words)" | tr '[:upper:]' '[:lower:]' | sort -u | xargs)" -d "${errors:1}"exit
else
  # store last line number if no error has been found
  line_number_start=$(grep -c ^ "$syslog_file")
  echo "$line_number_start" > "$log_file"
fi

# create notificaton if log exceeds usage of 90%
log_size=$(df | grep -oP "[0-9]+(?=% /var/log)")if [[ ! -f /tmp/syslog-notify.size ]] && [[ $log_size -gt 90 ]]; then
  touch /tmp/syslog-notify.size
  /usr/local/emhttp/webGui/scripts/notify -i "alert" -s "log utilizes more than 90%!" -d "$(du -h /var/log/* | sort -h | tail)"
elif [[ -f /tmp/syslog-notify.size ]]; then
  rm /tmp/syslog-notify.size
fi


Many thanks to 

 

Edited by bmartino1

  • Author

*Then a must have that i think shouild exist as a web UI option such as scrub...
Orginaly found on the forum... as well.

zfs-snapshot 
Auto Snap Shot for zfs and shadow copies - helps protect checksum and "bit rot"

 

#!/bin/bash

#v0.3 - Updated for new datasets and recursive snapshots
########################simple-snapshot-zfs#######################
###################### User Defined Options ######################

# List of ZFS datasets
DATASETS=("vm-zfs/Backups" "vm-zfs/Backups" "vm-zfs/Backups")
# this is done to all of my datasets...
#pool/dataset

# Set Number of Snapshots to Keep
SNAPSHOT_QTY=5

###### Don't change below unless you know what you're doing ######
##################################################################

timestamp=$(date "+%Y-%m-%d-%H:%M")
echo "Starting Snapshot ${timestamp}"
echo "_____________________________________________________________"

# Function to create snapshot if there is changed data
create_snapshot_if_changed() {
  local DATASET="$1"
  local WRITTEN
  WRITTEN=$(zfs get -H -o value written "${DATASET}")

  if [[ "${WRITTEN}" != "0" ]]; then
    local TIMESTAMP
    TIMESTAMP="$(date '+%Y-%m-%d-%H%M')"
    # Use -r for recursive snapshots
    zfs snapshot -r "${DATASET}@${TIMESTAMP}"
    echo "Recursive snapshot created: ${DATASET}@${TIMESTAMP}"
  else
    echo "No changes detected in ${DATASET}. No snapshot created."
  fi
}

# Function to prune snapshots
prune_snapshots() {
  local DATASET="$1"
  local KEEP="${SNAPSHOT_QTY}"
  
  local SNAPSHOTS=( $(zfs list -t snapshot -o name -s creation -r "${DATASET}" | grep "^${DATASET}@") )
  local SNAPSHOTS_COUNT=${#SNAPSHOTS[@]}

  echo "Total snapshots for ${DATASET}: ${SNAPSHOTS_COUNT}"

  local SNAPSHOTS_SPACE
  SNAPSHOTS_SPACE=$(zfs get -H -o value usedbysnapshots "${DATASET}")
  echo "Space used by snapshots for ${DATASET}: ${SNAPSHOTS_SPACE}"

  if [[ ${SNAPSHOTS_COUNT} -gt ${KEEP} ]]; then
    local TO_DELETE=$((SNAPSHOTS_COUNT - KEEP))
    for i in "${SNAPSHOTS[@]:0:${TO_DELETE}}"; do
      zfs destroy "${i}"
      echo "Deleted snapshot: ${i}"
      echo "_____________________________________________________________"
    done
  else
   echo "_____________________________________________________________"
  fi
}

# Iterate over each dataset and call the functions
for dataset in "${DATASETS[@]}"; do
  create_snapshot_if_changed "${dataset}"
  prune_snapshots "${dataset}"
done

echo "----------------------------Done!----------------------------"


Was orginaly looking into auto shadow copies with samba...
also talked on the forum... I doubt it the way smb and missing slack libs have been going...
Another fourm topic lost on the forum...

all data set the above is set your own this one wil ldo them all:

 

Edited by bmartino1
example mutiple datasets "vm-zfs/Backups" is a place holder

  • Author

gihub-login-creation 

This is used to help me recreate ssh keys as i have them default dead after making github repos...

 

#!/bin/bash
#cleanup old dead keys
rm /root/.ssh/*
#create a new key
ssh-keygen -t ed25519 -C "[email protected]"
#display key
cat /root/.ssh/id_ed25519.pub
#copy that to account login for latter auth for git commands to push pull comit


I can then look at the log and get new data and a key when needed.
https://github.com/settings/keys

one then makes a new ssh/GPG key to authenticate for git pul git push terminal commands...

Edited by bmartino1

  • 1 month later...
  • Author

v7 changes to docker and networking see https://forums.unraid.net/topic/178033-bmartino1-user-scripts/page/2/#findComment-1610752 for updated script to set

no bridging, no bonding. Fix vhost service IP due to vhost getting a privatized MAC address and set a static assigned within the taps network.

In my case eth0 is 192.168.2.x/24 and my machine is set to 192.168.2.254. With bridge off and bonding off (as this machine doesn't need it)

My unifi network complains and i get phantom devices on Unraids Reboot. DHCP snooping and other layer 2/layer3 announces due to how unraids uses a bridge tap for docker and virtual machines. So I treat the vhost0@eth0 network tap as a service that I want a separate IP address assigned to.

By default in v7 with br0 "bridging enabled macvlan will use shim bridge to make the macvlan connection... by default unraid ships with docker networks using ipvlan. Pro cons to each...
The ipvlan type is best when connection to the physical network is not needed. Please read this on implementing an ipvlan network.

The macvlan type of network allows direct connection to the physical network. Please read this on implementing a macvlan network.

use ip a to see your interfaces. you will see chost#/shim-br# @ interface and will see that he ip address for your br#/eth# is the same which is the problem... so treat it as its own service.

 
#!/bin/bash
# Reset and configure vhost0 interface
#(vhost for non bridge) shim-br0 is the new default

sleep 20
#Disk array needs started, docker needs started for this to fix the bridge and set an ip...

ip link set shim-br0 down
# Bring vhost0 down

ip addr flush dev shim-br0
# Remove any existing IPs

#use static IP?:
ip addr add 192.168.1.256/24 dev shim-br0
# Assign the desired IP

#To use dhcp coment out the ip addre line.

ip link set shim-br0 up       
# Bring vhost0 up
#!/bin/bash# Reset and configure vhost0 interface

ip link set vhost0 down
# Bring vhost0 down

ip addr flush dev vhost0
# Remove any existing IPs

#use static IP?:
ip addr add 192.168.1.254/24 dev vhost0
# Assign the desired IP
#To use dhcp coment out the ip addre line.

ip link set vhost0 up       
# Bring vhost0 up

*chose one dhcp or static IP was able to get both working in beta...


unfi example in logs:
image.thumb.png.2647be8269fc87dd899f623f2fc52c4d.png


image.thumb.png.79c981e8d7abd37f6cc59318da2d3f5b.png
image.png

More a networking / unifi issues... as unifi is overzelaus in its ip snooping...

Note this requires unraid advanced docker settings enabled:
image.png

Edited by bmartino1
Data - typo

  • Author

Unraid in a VM I want a swap file... plugin has issues and can break due to adding a swap file to a qemu vdisk...

image.png

So lets rebuild and make a swap file...

First stop the array!
the array needs to be stoped!
image.png

Then run theses commands!

as we will be rebooing after making are wap file...

identify your disk. since i'm using a usb registered as /dev/sda as my usb is vm passed for unraid...
My vdisk shows up as /dev/sdb

(Earlier we mountied and disk and formated it as btrfs 1 disk pool called cache)
image.png

lsblk


these commands are saved for code prosperity.
sdb 110G disk

└─sdb1 100G part

You must mount /dev/sdb1, NOT /dev/sdb

mkdir -p /mnt/cache
mount -t btrfs /dev/sdb1 /mnt/cache
mount | grep /mnt/cache

as the arry is off this mounts our vm cace disk...

Now to save and create the swap file..We Create the swap subvolume (REQUIRED on BTRFS) and disable Copy on Write!!!

btrfs subvolume create /mnt/cache/swap
btrfs subvolume list /mnt/cache
lsattr /mnt/cache | grep swap

*You must see a C.

Create the 2 GB swapfile (SAFE METHOD)

fallocate -l 2048M /mnt/cache/swap/swapfile
mkswap /mnt/cache/swap/swapfile
swapon /mnt/cache/swap/swapfile
swapon --show
free -h

You should now see a 2 GB swap file...

no plugin stillahve and use... add to go file:
swapon /mnt/cache/swap/swapfile


As I get into werid areas where this should work and it doen'ts this is a work around to get it to work... as once again the plugin refused to make the corect btrfs sub coume nor make the swap file...

########################################################################################################################################################################################################################################################################
Old Orginal Data for post responses..:
plugins a bit old... and needs some work...

image.png.6f40282fb0707270e5d4078ab96bef47.png
I use it on a btrfs sytem to fix some docker and swappiness issues...

 

May need to reach out to primeeval_god on some updates and fixes...
image.thumb.png.5b9a11b55e9afc1b838003191ad4a48b.png

 

swap file broken, more then usual?
Dec 3 17:37:08 BMM-Unraid rc.swapfile[14459]: Starting swap file during array mount ... Dec 3 17:37:08 BMM-Unraid rc.swapfile[14474]: Swap file /mnt/cache/swapfile is on a BTRFS file system but does not have the No_COW attribute.


Lets fix it with this script:

#!/bin/bash

# Show current swap status
swapon --show

# Turn off all swap files
swapoff -a

# Remove existing swap file
rm -f /mnt/cache/swapfile

# Ensure No_COW is set on the cache directory
chattr +C /mnt/cache/

# Create a new 2GB swap file
dd if=/dev/zero of=/mnt/cache/swapfile bs=1M count=2048

# Set correct permissions
chmod 600 /mnt/cache/swapfile

# Format the swap file
mkswap /mnt/cache/swapfile

# Activate the swap file
swapon /mnt/cache/swapfile

# Show swap status to confirm it's active
swapon --show


So Lets fix swap:

image.thumb.png.ec12b694dbd4cc63f1179643d23aa6da.png

more on there support:
 

 

Edited by bmartino1
Data- Info - Scritp workaround fixes -- More for VM quirks

2 hours ago, bmartino1 said:

plugins a bit old... and needs some work...

image.png.6f40282fb0707270e5d4078ab96bef47.png
I use it on a btrfs sytem to fix some docker and swappiness issues...

 

May need to reach out to primeeval_god on some updates and fixes...
image.thumb.png.5b9a11b55e9afc1b838003191ad4a48b.png

 

swap file broken, more then usual?
Dec 3 17:37:08 BMM-Unraid rc.swapfile[14459]: Starting swap file during array mount ... Dec 3 17:37:08 BMM-Unraid rc.swapfile[14474]: Swap file /mnt/cache/swapfile is on a BTRFS file system but does not have the No_COW attribute.


Lets fix it with this script:

 

The script should not be necessary. The error message is because you specified "/mnt/cache"  as the location for the swapfile on a BTRFS drive. As the help text for the swapfile location notes you need to choose a non-existing directory name. The plugin will then create a subvolume at that location with the proper options for the swapfile.

  • Author
Just now, primeval_god said:

The script should not be necessary. The error message is because you specified "/mnt/cache"  as the location for the swapfile on a BTRFS drive. As the help text for the swapfile location notes you need to choose a non-existing directory name. The plugin will then create a subvolume at that location with the proper options for the swapfile.

I even made a seperate share and set 

image.png.22021f65e6a89f9401d3cd1cd869a7d8.png

COW to no for a share called swap
image.thumb.png.cf1176aedcb061f5b04333825f490a8e.png

 

I haven't seen this work without that above script.

  • Author
Just now, primeval_god said:

You must specify a folder that does not exist and let the plugin create the folder.

I'm telling you it would never make that folder... this was the workaround 

  • Author

For me its more errors with dockers that sometimes complain about swap and wanting a unraid host level swap file... Here is a revised script for zfs... which would shutup the docker error with a file created but not running...

 

script is atm a backup for a different machine.. 
poolname enterprise
dataset swapfile

2GB vdev

 

while the swap plugin was meant for use on cache disk btrfs. I have found a way to make and use swap on a zfs only pool system...
 

working with plugin the two main errors with trying to use zfs and swap are 1 zfs doesn't support the attribute +C (copy on right...) when directed at a folder within a dataset or on the dataset itself... Since it appears the plugin is strictly expecting a file-based swap and not a ZFS zvol. Since ZFS doesn't natively support traditional swap files, some adjustments need to be made either to the plugin or the configuration to make this work.

 

*If fallocate is not available on your system (it might not be in Unraid's shell), use dd with conv=notrunc to ensure no sparse regions are created


On a zfs only with plugin at command step: 

# Activate the swap file swapon /mnt/cache/swapfile/swapfile (cache the pool name and swapfile the dataset swapfile the vdev)

 

So the plugin can crete a file no proble but cant activate due to error with COW (copy on write...) so at the swapfile in a dataset without the option copy on write in the directly off would have swapon error  "it appears to have holes..." The error "it appears to have holes" suggests that the ZFS file system is still creating a sparse file despite attempts to disable Copy-On-Write otherwise known as (sync=disabled) also we could use fallocate. This happens because ZFS inherently handles files differently from other file systems like EXT4 or XFS....

 

ZFS zvol volumes are raw block devices, so they avoid all the pitfalls of file-based swap on ZFS datasets. This eliminates issues related to Copy-On-Write, sparse files, and the holes error...

 

So remove the swap plugin. and use this startup script.

 

#!/bin/bash

# Show current swap status
swapon --show

# Turn off all swap files
swapoff -a

# Destroy existing ZFS swapfile dataset if it exists
echo "Destroying existing ZFS swapfile dataset (if it exists)..."
zfs destroy -r -f enterprise/swapfile

# Create a new ZFS dataset with disabled sync for the swapfile
echo "Creating new ZFS dataset for swapfile..."
zfs create -o sync=disabled enterprise/swapfile

# Verify ZFS dataset properties
echo "Checking ZFS dataset properties..."
zfs get sync,compression enterprise/swapfile

# Create a ZFS zvol for swap
echo "Creating a 2G ZFS zvol for swap..."
zfs create -V 2G enterprise/swapfile/swapfile

# Format the zvol as swap space
echo "Formatting the zvol as swap..."
mkswap /dev/zvol/enterprise/swapfile/swapfile

# Enable the swap
echo "Activating the swap..."
swapon /dev/zvol/enterprise/swapfile/swapfile

# Verify the swap is active
echo "Verifying the swap..."
swapon --show

#set swappiness defualt 60 atleast 10 rec servers
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl vm.swappiness=10



Using swap on ZFS (or any disk-backed storage) can be a double-edged sword, especially on ZFS, due to its unique Copy-On-Write (CoW) nature. Below are some considerations for why you might want (or not want) swap on ZFS-based disks, and alternative approaches to handle swap efficiently in Unraid.

 

Reasons to Use Swap on ZFS:

 

Handling Memory Overcommitment: If your system is running out of RAM (especially with Docker containers and VMs), swap provides a fallback mechanism to prevent processes from crashing.

 

Avoiding Out-of-Memory (OOM) Errors: Unraid might kill processes if the system runs out of memory. Having swap prevents abrupt service interruptions due to OOM kills.

 

Temporary Relief for High Memory Loads: Swap provides temporary relief during memory spikes, especially for infrequently accessed data, even if it incurs performance penalties.

 

No Other Disks Available: If all your disks are ZFS-based and you have no other storage options (like SSDs or non-ZFS devices), a ZFS-backed swap may be your only choice.

 

Reasons to Avoid Swap on ZFS:

 

Performance Penalty: ZFS is designed for data integrity and CoW, which can conflict with the typical access patterns of swap. Even when using sync=disabled, ZFS overhead may lead to slower swap performance compared to raw disk or dedicated swap partitions.

 

High Disk Activity: Swap generates frequent small writes, which can lead to excessive disk activity on ZFS pools, reducing their performance and potentially increasing wear on SSDs or HDDs.

 

Risk of Deadlock: ZFS itself consumes memory for managing its datasets (ARC, metadata, etc.). If the system starts swapping ZFS metadata or ARC data, it can lead to a feedback loop where ZFS struggles to free up memory, potentially causing system instability.

 

Better Alternatives Exist: Swap is typically a last resort for extending memory. Using RAM optimally (e.g., limiting VM or Docker resource usage) or adding more physical memory is preferable.

some other side fixes on zfs with swap:

Optimize ZFS Memory Usage

Reduce ZFS ARC (Adaptive Replacement Cache) size to free up more RAM for other processes:

echo "arc_max=4G" >> /etc/modprobe.d/zfs.conf

Use a Compressed RAM Disk (zram) for Swap

Instead of relying on disk-based swap, you can configure a compressed RAM disk for swap (via zram). This is faster and avoids disk I/O entirely

modprobe zram
echo lz4 > /sys/block/zram0/comp_algorithm
echo $((2*1024*1024*1024)) > /sys/block/zram0/disksize # Set to 2GB
mkswap /dev/zram0
swapon /dev/zram0

*would pull ram and make a ram disk in memory / disk cache...

Edited by bmartino1

  • 1 month later...
2 hours ago, bmartino1 said:

wiregurad nor Tailscale

Sorry but Tailscale is not installed by default and is a plugin so I would recommend that you uninstall the plugin if you don't want to have it on your system.

 

However, I wouldn't recommend uninstalling Wireguard at all but you just can disable the Server and therefor it won't work at all and furthermore if you don't have any tunnel set up Wireguard can't connect to anything or the other way around.

11 hours ago, bmartino1 said:

Unraid 7 has tailscale options and some binaries without the plugin...

That's simply not true. I assume you are talking about the Tailscale Docker Integration, if yes, there are no binaries or anything included into the base OS, you can also look at the output from:

grafik.png.d307c49d5d7c366220c18eaac0ff44f7.png

 

Please do keep in mind if you enabled the Tailscale Docker Integration in one or more containers you will still find processes on the host but these processes run in their own namespace so to speak isolated in the container(s) where you've enabled the Tailscale Docker Integration and this means that Tailscale is not installed or running on the host.

 

11 hours ago, bmartino1 said:

as even with a configured tailscale in testing uninstalling the plugin doesn't stop tailscale from running...

That is something you have to ask in the support thread from the Tailscale plugin.

 

I can tell you for sure that no Tailscale binary is installed on Unraid by default nor is a Tailscale binary installed to Unraid, even not when enabling the Tailscale Docker Integration.

  • 9 months later...
  • Author


Bring back the broadcast IP fix layer 2/layer 3 dispaly and routing with ifconfig...

Work around script fix:


#!/bin/bash
# show_broadcasts_noninteractive.sh
# Non-interactive: compute/set IPv4 broadcast on the PRIMARY (/0..30) addr per iface.
# When DO_FLUSH=true: link down -> flush -> add IP+brd -> link up -> restore default route (if it was on this iface).
# Wildcard include/exclude supported (br*, veth*, br-*). Pure bash + ip + awk.

set -euo pipefail

##########################
# CONFIG (edit these)
##########################
APPLY=true            # actually make changes
PRINT_ONLY=false      # when true (and APPLY=true), print the ip commands instead of running them
INTERFACES_INCLUDE="br0"   # CSV; supports globs: "br0", "eth0", "br*", "veth*", "br-*"; empty = all (minus EXCLUDE)
INTERFACES_EXCLUDE="lo,docker0,virbr0,tailscale1,tunl0,veth*,br-*"  # CSV; globs supported; exclude wins
DO_FLUSH=true         # safe flush sequence (down->flush->add brd->up->restore default route)
SLEEP_BEFORE=0        # optional delay to avoid racing rc scripts if you autostart (not recommended)
LOGFILE=""            # optional extra logfile; empty -> stdout only (User Scripts captures stdout)
##########################
# end CONFIG
##########################

_log() {
  local m="$*"
  if [[ -n "$LOGFILE" ]]; then
    printf '%s %s\n' "$(date -Iseconds)" "$m" | tee -a "$LOGFILE"
  else
    printf '%s %s\n' "$(date -Iseconds)" "$m"
  fi
}

matches_globs_csv() {
  # $1=name, $2=csv_globs
  local name="$1"
  local csv="$2"
  if [[ -z "$csv" ]]; then
    return 1
  fi
  local IFS=,
  local pat
  read -r -a arr <<< "$csv"
  for pat in "${arr[@]}"; do
    pat="${pat#"${pat%%[![:space:]]*}"}"
    pat="${pat%"${pat##*[![:space:]]}"}"
    [[ -z "$pat" ]] && continue
    case "$name" in
      $pat) return 0 ;;
    esac
  done
  return 1
}

should_process_iface() {
  local ifc="$1"
  if matches_globs_csv "$ifc" "$INTERFACES_EXCLUDE"; then
    return 1
  fi
  if [[ -z "$INTERFACES_INCLUDE" ]]; then
    return 0
  fi
  matches_globs_csv "$ifc" "$INTERFACES_INCLUDE"
}

ip2int() {
  local IFS=.
  local a b c d
  read -r a b c d <<< "$1"
  echo $(( (a<<24) | (b<<16) | (c<<8) | d ))
}

int2ip() {
  local n=$1
  n=$(( n & 0xFFFFFFFF ))
  printf "%d.%d.%d.%d\n" $(( (n>>24)&255 )) $(( (n>>16)&255 )) $(( (n>>8)&255 )) $(( n&255 ))
}

cidr_to_mask() {
  local c=$1
  if (( c <= 0 )); then
    echo 0
    return
  fi
  if (( c >= 32 )); then
    echo 4294967295
    return
  fi
  local top=$(( (1<<c) - 1 ))
  echo $(( (top << (32-c)) & 0xFFFFFFFF ))
}

query_kernel_broadcast() {
  local dst=$1
  local out br
  out=$(ip route get "$dst" 2>&1 || true)
  br=$(awk '{for(i=1;i<=NF;i++) if($i=="broadcast"){print $(i+1); exit}}' <<< "$out")
  printf "%s" "$br"
}

pick_primary_line_for_iface() {
  # arg1=iface
  local ifc="$1"
  # returns one best "ip -4 -o addr show dev IF" line (widest network; skip /31,/32)
  ip -4 -o addr show dev "$ifc" 2>/dev/null | awk '
    {
      for(i=1;i<=NF;i++) if($i=="inet"){ inet=$(i+1) }
      if(inet=="") next
      split(inet,a,"/")
      ip=a[1]; cidr=a[2]+0
      if(cidr>=31) next
      if(mincidr==0 || cidr<mincidr){ mincidr=cidr; best=$0 }
      inet=""
    }
    END{
      if(best!="") print best
    }
  '
}

# --- main ---
if (( SLEEP_BEFORE > 0 )); then
  _log "Sleeping ${SLEEP_BEFORE}s..."
  sleep "$SLEEP_BEFORE"
fi

_log "Start. APPLY=${APPLY} PRINT_ONLY=${PRINT_ONLY} DO_FLUSH=${DO_FLUSH} INCLUDE='${INTERFACES_INCLUDE}' EXCLUDE='${INTERFACES_EXCLUDE}'"

# enumerate all ifaces that currently have any IPv4; then filter by include/exclude
# (we intentionally avoid associative arrays, and process each iface independently)
while IFS= read -r IF; do
  IF="${IF%:}"
  should_process_iface "$IF" || continue

  _log ""
  _log "Interface: $IF"
  _log "  Pre-state:"
  ip -4 -o addr show dev "$IF" | sed 's/^/    /' || true

  # pick primary line
  PL="$(pick_primary_line_for_iface "$IF" || true)"
  if [[ -z "$PL" ]]; then
    _log "  No broadcast-capable primary (/0..30); skipping."
    continue
  fi

  inet="$(awk '{for(i=1;i<=NF;i++) if($i=="inet"){print $(i+1); exit}}' <<< "$PL")"
  rep_brd="$(awk '{for(i=1;i<=NF;i++) if($i=="brd"){print $(i+1); exit}}' <<< "$PL" 2>/dev/null || true)"
  IP="${inet%%/*}"
  CIDR="${inet##*/}"

  # capture default gateway if bound to this iface
  GW="$(ip route show default 2>/dev/null | awk -v IF="$IF" '$1=="default" && $0 ~ (" dev "IF"($| )"){for(i=1;i<=NF;i++) if($i=="via"){print $(i+1)}}' | head -n1)"
  if [[ -n "$GW" ]]; then
    _log "  Detected default GW on ${IF}: ${GW}"
  fi

  _log "  Primary: ${IP}/${CIDR}"
  if [[ -n "$rep_brd" ]]; then
    _log "  Reported brd: ${rep_brd}"
  else
    _log "  Reported brd: (none)"
  fi

  ip_int="$(ip2int "$IP")"
  m_int="$(cidr_to_mask "$CIDR")"
  inv=$(( (~m_int) & 0xFFFFFFFF ))
  comp_brd="$(int2ip $(( (ip_int & m_int) | inv )))"
  _log "  Computed brd: $comp_brd"

  kern_brd="$(query_kernel_broadcast "$comp_brd")"
  if [[ -n "$kern_brd" ]]; then
    _log "  Kernel says brd: $kern_brd"
  else
    _log "  Kernel brd: (none)"
  fi

  CHOSEN="$comp_brd"
  if [[ -n "$kern_brd" && "$kern_brd" != "0.0.0.0" ]]; then
    CHOSEN="$kern_brd"
  elif [[ -n "$rep_brd" && "$rep_brd" != "0.0.0.0" ]]; then
    CHOSEN="$rep_brd"
  fi
  _log "  -> Selected broadcast: $CHOSEN"

  if [[ "$APPLY" != "true" || "$PRINT_ONLY" == "true" ]]; then
    if [[ "$DO_FLUSH" == "true" ]]; then
      _log "  Would run (in order):"
      _log "    ip link set ${IF} down"
      _log "    ip -4 addr flush dev ${IF}"
      _log "    ip addr add ${IP}/${CIDR} brd ${CHOSEN} dev ${IF}"
      _log "    ip link set ${IF} up"
      if [[ -n "$GW" ]]; then
        _log "    ip route replace default via ${GW} dev ${IF}"
      fi
    else
      _log "  Would run: ip addr replace ${IP}/${CIDR} brd ${CHOSEN} dev ${IF}"
    fi
  else
    if [[ "$DO_FLUSH" == "true" ]]; then
      _log "  Applying (down -> flush -> add IP+brd -> up -> restore default route)..."
      ip link set "${IF}" down
      ip -4 addr flush dev "${IF}"
      ip addr add "${IP}/${CIDR}" brd "${CHOSEN}" dev "${IF}"
      ip link set "${IF}" up
      if [[ -n "$GW" ]]; then
        ip route replace default via "${GW}" dev "${IF}"
      fi

      # sanity
      if ! ip -4 -o addr show dev "$IF" | grep -q "${IP}/${CIDR}"; then
        _log "  ERROR: ${IP}/${CIDR} not present on ${IF} after flush/add."
        exit 1
      fi
      _log "  Applied successfully to ${IF}."
    else
      _log "  Applying: ip addr replace ${IP}/${CIDR} brd ${CHOSEN} dev ${IF}"
      ip addr replace "${IP}/${CIDR}" brd "${CHOSEN}" dev "${IF}"
      _log "  Applied successfully to ${IF}."
    fi
  fi

  _log "  Post-state:"
  ip -4 -o addr show dev "$IF" | sed 's/^/    /' || true

done < <(ip -4 -o addr show | awk '{print $2}' | sed 's/:$//' | sort -u)

_log ""
_log "Finished."
# NOTE:
# - Do NOT autostart this by default. A reboot without this script will restore Unraid's implicit-broadcast state.
# - If you choose to autostart anyway, consider SLEEP_BEFORE=5..10 to avoid racing rc.inet* and docker.


Last run to implement the fix:
image.png

LOG per script:

Full logs for this script are available at /tmp/user.scripts/tmpScripts/show_broadcasts/log.txt

2025-10-13T17:18:00-05:00 Sleeping 5s...

2025-10-13T17:18:05-05:00 Start. APPLY=true PRINT_ONLY=false DO_FLUSH=true INCLUDE='br0,shim-br0' EXCLUDE='lo,docker0,virbr0,tailscale1,tunl0,veth*,br-*'

2025-10-13T17:18:05-05:00

2025-10-13T17:18:05-05:00 Interface: br0

2025-10-13T17:18:05-05:00 Pre-state:

4: br0 inet 192.168.201.100/24 metric 1 scope global br0\ valid_lft forever preferred_lft forever

2025-10-13T17:18:05-05:00 Detected default GW on br0: 192.168.201.1

2025-10-13T17:18:05-05:00 Primary: 192.168.201.100/24

2025-10-13T17:18:05-05:00 Reported brd: (none)

2025-10-13T17:18:05-05:00 Computed brd: 192.168.201.255

2025-10-13T17:18:05-05:00 Kernel says brd: 192.168.201.255

2025-10-13T17:18:05-05:00 -> Selected broadcast: 192.168.201.255

2025-10-13T17:18:05-05:00 Applying (down -> flush -> add IP+brd -> up -> restore default route)...

2025-10-13T17:18:05-05:00 Applied successfully to br0.

2025-10-13T17:18:05-05:00 Post-state:

4: br0 inet 192.168.201.100/24 brd 192.168.201.255 scope global br0\ valid_lft forever preferred_lft forever

2025-10-13T17:18:05-05:00

2025-10-13T17:18:05-05:00 Interface: shim-br0

2025-10-13T17:18:05-05:00 Pre-state:

9: shim-br0 inet 192.168.201.100/24 scope global shim-br0\ valid_lft forever preferred_lft forever

2025-10-13T17:18:05-05:00 Primary: 192.168.201.100/24

2025-10-13T17:18:05-05:00 Reported brd: (none)

2025-10-13T17:18:05-05:00 Computed brd: 192.168.201.255

2025-10-13T17:18:05-05:00 Kernel says brd: 192.168.201.255

2025-10-13T17:18:05-05:00 -> Selected broadcast: 192.168.201.255

2025-10-13T17:18:05-05:00 Applying (down -> flush -> add IP+brd -> up -> restore default route)...

2025-10-13T17:18:05-05:00 Applied successfully to shim-br0.

2025-10-13T17:18:05-05:00 Post-state:

9: shim-br0 inet 192.168.201.100/24 brd 192.168.201.255 scope global shim-br0\ valid_lft forever preferred_lft forever

2025-10-13T17:18:05-05:00

2025-10-13T17:18:05-05:00 Finished.

Script Finished Oct 13, 2025 17:18.05

Full logs for this script are available at /tmp/user.scripts/tmpScripts/show_broadcasts/log.txt

  • 3 weeks later...
  • Author

Reviewing old codes over the years and post to remove some Personal data and have some security...

Stubbed across this old thread...
remove the Ctrl+Alt+Del reboot
*Better as a syslinux grub edit...
https://forums.unraid.net/topic/178395-etcinittab-not-working-after-change/

#!/bin/bash

# Disable CTRL-ALT-DEL in /etc/inittab
if grep -q '^ca::ctrlaltdel' /etc/inittab; then
  echo "Disabling CTRL-ALT-DEL in /etc/inittab..."
  sed -i 's/^ca::ctrlaltdel/# ca::ctrlaltdel/' /etc/inittab
  telinit q
else
  echo "CTRL-ALT-DEL is already disabled in /etc/inittab."
fi

# Disable kernel-level handling of CTRL-ALT-DEL
echo "Disabling kernel-level CTRL-ALT-DEL handling..."
echo 0 > /proc/sys/kernel/ctrl-alt-del

# Confirm the settings have been applied
echo "Current /etc/inittab entry for CTRL-ALT-DEL:"
grep 'ctrlaltdel' /etc/inittab

echo "Kernel-level CTRL-ALT-DEL setting:"
cat /proc/sys/kernel/ctrl-alt-del

echo "CTRL-ALT-DEL has been disabled."
  • Author

Force Docker updates - if temaplate exist but webui shows 3rd party...

#!/bin/bash

# Get the list of running Docker container names
CONTAINER_NAMES=$(docker ps --format '{{.Names}}')

# Check if there are any running containers
if [[ -z "$CONTAINER_NAMES" ]]; then
    echo "No running containers found."
    exit 0
fi

# Iterate over each container name and run the update command
for CONTAINER_NAME in $CONTAINER_NAMES; do
    echo "Updating container: $CONTAINER_NAME"
    /usr/bin/php -q /usr/local/emhttp/plugins/dynamix.docker.manager/scripts/update_container "$CONTAINER_NAME"
done

echo "Update process completed."
  • Author

terminal consloe shows syslog as main output...

*WARNING UINATEND ROOT ACCESS LEFT LOGED IN AT TERMAINL!

#!/bin/bash
set -euo pipefail

# ===== FIXED SETTINGS (edit if you want a different TTY or log) =====
TTY_DEV="/dev/tty1"
TTY_BASENAME="tty1"
INIT_ID="c1"
LOG_FILE="/var/log/syslog"
WRAPPER="/usr/local/sbin/tty-console.sh"
# ====================================================================

echo "[*] Configure ${TTY_DEV} as a live syslog console (Ctrl+C -> root shell)"

[[ -e "$TTY_DEV" ]] || { echo "[-] ${TTY_DEV} not found"; exit 1; }

# 1) Install the wrapper process that *is* the console on TTY_DEV
mkdir -p "$(dirname "$WRAPPER")"
cat > "$WRAPPER" <<'EOS'
#!/bin/bash
# Bind to the console and make this our controlling TTY
exec </dev/tty1 >/dev/tty1 2>&1
stty sane >/dev/null 2>&1 || true
printf "\033[2J\033[H"  # clear screen

TTY_WANT="/dev/tty1"
LOG_WANT="/var/log/syslog"

echo
echo "=== Live syslog on ${TTY_WANT} ==="
echo "Press Ctrl+C to drop into a root shell on this console."
echo

# Ctrl+C -> switch to an interactive root login shell
trap 'exec /bin/bash -l' INT

# Show entire file then follow in foreground
tail -f -n +1 "$LOG_WANT"
EOS
chmod 755 "$WRAPPER"

# Bake your chosen TTY/log into the wrapper
sed -i \
  -e "s#^exec </dev/tty1 >/dev/tty1 2>&1#exec <${TTY_DEV} >${TTY_DEV} 2>\&1#" \
  -e "s#^TTY_WANT=.*#TTY_WANT=\"${TTY_DEV}\"#" \
  -e "s#^LOG_WANT=.*#LOG_WANT=\"${LOG_FILE}\"#" \
  "$WRAPPER"

# 2) Point c1 to our wrapper (no agetty, no autologin)
if grep -qE "^${INIT_ID}:" /etc/inittab ; then
  sed -i "s#^${INIT_ID}:.*#${INIT_ID}:12345:respawn:${WRAPPER}#" /etc/inittab
else
  echo "${INIT_ID}:12345:respawn:${WRAPPER}" >> /etc/inittab
fi

# 3) Apply now: make init reread, and kill any current agetty on that TTY so it respawns our wrapper
telinit q || true
pkill -f "agetty .*${TTY_BASENAME}" || true
sleep 0.5

# Debug
echo "[D] inittab ${INIT_ID}: $(grep "^${INIT_ID}:" /etc/inittab || echo 'missing')"
echo "[D] process bound to ${TTY_BASENAME}:"
ps ax | grep -E "(${WRAPPER}|agetty).*${TTY_BASENAME}" || echo "  (init will spawn it)"

echo "[✓] ${TTY_DEV} is now a live syslog console."
echo "    Ctrl+C -> root shell; 'exit' -> back to log view (init respawns)."

# -------- OPTIONAL: quick revert helper (comment out if you don't want it) --------
# To revert to standard login on tty1, run these two lines manually:
# sed -i 's#^c1:.*#c1:12345:respawn:/sbin/agetty 38400 tty1 linux#' /etc/inittab ; telinit q ; pkill -f "(/usr/local/sbin/tty-console\.sh|agetty .*tty1)" || true
# ---------------------------------------------------------------------------------

  • Author

unraid docker notfication
*uses notify and unraid notfications to check on dockers at corn intervals.. (can ber used to check on dockers via unraids notfication system....

Set for unfi docker...
edit env at top and text in notfiy respone in script... could rework to call docker name form env...

#!/bin/bash
# Unraid User Script: Export UniFi container health to an SMB-visible file
# - Preserves the image's built-in HEALTHCHECK (we don't run curl ourselves)
# - Writes a single small status file (KV pairs) + an append-only log
# - Safe for cron: idempotent, atomic writes

set -Eeuo pipefail

### ======== CONFIGURE ME ======== ###
CONTAINER_NAME="unifi-controller-reborn"        # container name (as shown by docker ps)
OUTPUT_DIR="/mnt/user/health/unifi"             # SMB-exposed folder (make/share this as needed)
STATUS_FILE_NAME="unifi.status"                 # simple KV file Pi will read
LOG_FILE_NAME="unifi_health.log"                # append-only log for historical checks
# If your SMB share is different, change OUTPUT_DIR accordingly, e.g.:
# OUTPUT_DIR="/mnt/user/YourShare/health/unifi"
### ======== /CONFIGURE ME ======== ###

STATUS_FILE="${OUTPUT_DIR}/${STATUS_FILE_NAME}"
LOG_FILE="${OUTPUT_DIR}/${LOG_FILE_NAME}"

mkdir -p "${OUTPUT_DIR}"

ts() { date -Iseconds; }  # ISO-8601 timestamp

# --- Detect Docker engine status early ---
if ! docker info >/dev/null 2>&1; then
  ENGINE_STATE="down"
  CONTAINER_STATE="unknown"
  HEALTH_STATE="unknown"
  OK=0
else
  ENGINE_STATE="up"
  # Resolve container id (exact name match)
  CID="$(docker ps -aqf "name=^${CONTAINER_NAME}$" || true)"
  if [[ -z "${CID}" ]]; then
    CONTAINER_STATE="notfound"
    HEALTH_STATE="none"
    OK=0
  else
    # Read container state and health (health may be absent)
    CONTAINER_STATE="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}" 2>/dev/null || echo unknown)"
    HEALTH_STATE="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "${CONTAINER_NAME}" 2>/dev/null || echo none)"

    # Policy: OK=1 only when container is running AND (health is healthy OR health not defined)
    if [[ "${CONTAINER_STATE}" == "running" ]] && [[ "${HEALTH_STATE}" == "healthy" || "${HEALTH_STATE}" == "none" ]]; then
      OK=1
    else
      OK=0
    fi
  fi
fi

# --- Atomically write the status file (so the Pi never reads a partial write) ---
TMP="$(mktemp)"
{
  echo "WHEN=$(ts)"
  echo "ENGINE=${ENGINE_STATE}"
  echo "CONTAINER=${CONTAINER_NAME}"
  echo "STATE=${CONTAINER_STATE}"    # running|exited|paused|created|notfound|unknown
  echo "HEALTH=${HEALTH_STATE}"      # healthy|unhealthy|starting|none|unknown
  echo "OK=${OK}"                    # 1=good, 0=bad
} > "${TMP}"
mv -f "${TMP}" "${STATUS_FILE}"

# --- Append a one-line log entry (easy to tail on the Pi) ---
echo "$(ts) CONTAINER=${CONTAINER_NAME} STATE=${CONTAINER_STATE} HEALTH=${HEALTH_STATE} ENGINE=${ENGINE_STATE} OK=${OK}" >> "${LOG_FILE}"

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.