Skip to content

Instantly share code, notes, and snippets.

@brandon1024
Created October 31, 2025 18:25
Show Gist options
  • Save brandon1024/fb443b628f02b03290de3d0cc30d2127 to your computer and use it in GitHub Desktop.
Save brandon1024/fb443b628f02b03290de3d0cc30d2127 to your computer and use it in GitHub Desktop.
update-motd.d - simple pam_motd scripts for a useful ssh motd
#!/usr/bin/env bash
echo
echo ' _______/\\\\\_______/\\\\\\\\\\\\\____/\\\\\\\\\\\\\\\__/\\\\\\\\\\\____________________/\\\_ '
echo ' _____/\\\///\\\____\/\\\/////////\\\_\///////\\\/////__\/////\\\///_________________/\\\\\\\_ '
echo ' ___/\\\/__\///\\\__\/\\\_______\/\\\_______\/\\\___________\/\\\___________________\/////\\\_ '
echo ' __/\\\______\//\\\_\/\\\\\\\\\\\\\/________\/\\\___________\/\\\______/\\\\\\\\\\\_____\/\\\_ '
echo ' _\/\\\_______\/\\\_\/\\\/////////__________\/\\\___________\/\\\_____\///////////______\/\\\_ '
echo ' _\//\\\______/\\\__\/\\\___________________\/\\\___________\/\\\_______________________\/\\\_ '
echo ' __\///\\\__/\\\____\/\\\___________________\/\\\___________\/\\\_______________________\/\\\_ '
echo ' ____\///\\\\\/_____\/\\\___________________\/\\\________/\\\\\\\\\\\___________________\/\\\_ '
echo ' ______\/////_______\///____________________\///________\///////////____________________\///_ '
echo
#!/usr/bin/env bash
uname -snrvm
#!/usr/bin/env bash
LOAD_AVERAGES=($(</proc/loadavg))
declare -A MEMINFO
while IFS=' ' read STAT VAL OTHER; do
MEMINFO["$STAT"]=$(numfmt --suffix=B --from-unit=1024 --to=iec $VAL)
done </proc/meminfo
printf "\n"
printf " System information as of %s\n" "$(date)"
printf "\n"
printf " System uptime: %s\n" "$(uptime -p)"
printf " System load: %s, %s, %s\n" ${LOAD_AVERAGES[0]} ${LOAD_AVERAGES[1]} ${LOAD_AVERAGES[2]}
printf " Memory: %-15s %-15s %-15s %-15s\n" "${MEMINFO['MemFree:']} (free)" "${MEMINFO['MemTotal:']} (total)" "${MEMINFO['Cached:']} (cached)" "${MEMINFO['Buffers:']} (buffers)"
printf " Swap: %-15s %-15s\n" "${MEMINFO['SwapFree:']} (free)" "${MEMINFO['SwapTotal:']} (total)"
echo
echo " File Systems"
echo
df -h --exclude-type=tmpfs --exclude-type=squashfs --exclude-type=devtmpfs --print-type | sed 's/^/ /'
echo
echo " Network Interfaces"
echo
tail -n +3 /proc/net/dev | numfmt --to=iec --field=2,10 --suffix=B | numfmt --to=si --field=3,11 | \
awk '{print $1, $2, $3, $10, $11}' | column -t -N 'Interface,RX Bytes,RX Packets,TX Bytes,TX Packets' | sed 's/^/ /'
#!/usr/bin/env bash
echo
n=$(apt-get -qq --just-print dist-upgrade | cut -f 2 -d " " | sort -u | wc -l)
if [[ $n -gt 0 ]]; then
echo " You have ${n} packages waiting for upgrades."
echo
fi
n=$(apt-get -qq --just-print autoremove | cut -f 2 -d " " | sort -u | wc -l)
if [[ $n -gt 0 ]]; then
echo " You have ${n} packages that were automatically installed and are not needed anymore."
echo
fi

update-motd.d - simple pam_motd scripts for a useful ssh motd

If you have any experience with basic linux server administration, you've surely heard or come across the concept of an ssh motd. Maybe you've set PrintMotd yes in your /etc/ssh/sshd_config and updated /etc/motd with an ascii art drawing of a cow welcoming users to the 10-year-old Dell Optiplex chugging along relentlessly in your bedroom closet.

The standard sshd option for configuring a motd on login has been around for ages, but package maintainers for most modern distrbutions have switched to using pam_motd instead. This PAM module generates a motd from a set of user scripts in /etc/update-motd.d/. The script are executed in lexical order, and the output is concatenated with the static /etc/motd file to render a dynamic message to the user. You can read more about it here and here.

A common use case for this is to dynamically generate some system information on login. For instance, newer distributions of Ubuntu Server ship with scripts that generate a motd with package updates, news, and other information:

Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-101-generic x86_64)

* Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro

System information as of Wed Jun 17 11:56:43 MDT 2020

System load: 4.33
Usage of /home: 81.0% of 393.60GB
Memory usage: 63%
Swap usage: 17%
Processes: 1270
Users logged in: 1
IP address for br0: 10.10.0.13

=> / is using 85.0% of 53.79GB

* MicroK8s gets a native Windows installer and command-line integration.

https://ubuntu.com/blog/microk8s-installers-windows-and-macos

36 packages can be updated.
9 updates are security updates.

You have packages from the Hardware Enablement Stack (HWE) installed that
are going out of support on 2023-04-30.

There is a graphics stack installed on this system. An upgrade to a
configuration supported for the full lifetime of the LTS will become
available on 2020-07-21 and can be installed by running 'update-manager'
in the Dash.

*** System restart required ***

There are quite a few update-motd.d scripts floating around GitHub. These scripts have irked me a little, primarily because they often have dependencies on system packages. The Ubuntu dynamic-motd package for example, although a bit dated now, executes a python script to generate system details that could be easily parsed from /proc. There are some good examples out there to be fair, like this one from d-Rickyy-b is pretty cool.

I've build a set of update-motd.d scripts for my own servers which use primitives like numfmt and awk which are often available by default in most distributions. Just copy them into /etc/update-motd.d, chmod +x, and you're good to go. Feel free to use and build upon them. Here's what they look like:

 ╰╼ ▶ ssh n1.opti.lan

 _______/\\\\\_______/\\\\\\\\\\\\\____/\\\\\\\\\\\\\\\__/\\\\\\\\\\\____________________/\\\_        
  _____/\\\///\\\____\/\\\/////////\\\_\///////\\\/////__\/////\\\///_________________/\\\\\\\_       
   ___/\\\/__\///\\\__\/\\\_______\/\\\_______\/\\\___________\/\\\___________________\/////\\\_      
    __/\\\______\//\\\_\/\\\\\\\\\\\\\/________\/\\\___________\/\\\______/\\\\\\\\\\\_____\/\\\_     
     _\/\\\_______\/\\\_\/\\\/////////__________\/\\\___________\/\\\_____\///////////______\/\\\_    
      _\//\\\______/\\\__\/\\\___________________\/\\\___________\/\\\_______________________\/\\\_   
       __\///\\\__/\\\____\/\\\___________________\/\\\___________\/\\\_______________________\/\\\_  
        ____\///\\\\\/_____\/\\\___________________\/\\\________/\\\\\\\\\\\___________________\/\\\_ 
         ______\/////_______\///____________________\///________\///////////____________________\///_ 

Linux optiplex-micro-7040-1 6.1.0-37-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64

  System information as of Fri Oct 31 15:20:29 ADT 2025

    System uptime: up 18 weeks, 2 days, 4 hours, 24 minutes
    System load:   0.16, 0.20, 0.22
    Memory:        1.7GB (free)    16GB (total)    6.2GB (cached)  2.0GB (buffers)
    Swap:          563MB (free)    976MB (total)  

  File Systems

    Filesystem     Type  Size  Used Avail Use% Mounted on
    /dev/sda2      ext4  467G   61G  384G  14% /
    /dev/md0       ext4  7.3T  5.3T  1.7T  77% /var/data
    /dev/sda1      vfat  511M   12M  500M   3% /boot/efi

  Network Interfaces

    Interface   RX Bytes  RX Packets  TX Bytes  TX Packets
    lo:         380GB     91M         380GB     91M
    enp0s31f6:  2.9TB     2.5G        833GB     1.4G
    wg0:        2.6GB     13M         76GB      65M


Last login: Fri Oct 31 14:08:13 2025 from 192.168.1.29
user@optiplex-micro-7040-1:~$ 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment