debian, linux, raspberrypi, shell

Customize your MOTD login message in Debian and Ubuntu

This is a little guide to display dynamic login messages on a Debian system.

This is one of those things where the internet has plenty of resources, but they are mostly outdated and contradictory. Even typing man motd in Debian is a sad experience.

It is not a difficult thing to do but it can be a big waste of time to sort out the contradictions.

Hopefully, this post will help get the big picture from one single place.

Short history

Ancient times

Time ago, most distributions just printed the contents of /etc/motd upon login.

MOTD stands for message of the day (although it was static), and was put in place at installation time, only to be changed at upgrade time maybe.

$ cat /etc/motd

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

Some distributions such as Arch keep operating this way.

Ubuntu came along

Then, Ubuntu Intrepid Ibex (2008) introduced a package update-motd, which consisted of

  • a script called update-motd.
  • an entry in /etc/cron.d calling update-motd every 10 minutes.
  • a folder /etc/update-motd.d

The script runs all the scripts in /etc/update-motd.d using run-parts, then stores all output in /var/run/motd.

#!/bin/sh
#
#    update-motd - update the dynamic MOTD immediately
#
#    Copyright (C) 2008-2014 Dustin Kirkland <dustin.kirkland@gmail.com>
#
#    Authors: Dustin Kirkland <dustin.kirkland@gmail.com>
#    [ comments edited out by ownyourbits ]
set -e

if ! touch /var/run/motd.new 2>/dev/null; then
        echo "ERROR: Permission denied, try:" 1>&2
        echo "  sudo $0" 1>&2
        exit 1
fi

if run-parts --lsbsysinit /etc/update-motd.d > /var/run/motd.new; then
        if mv -f /var/run/motd.new /var/run/motd; then
                cat /var/run/motd
                exit 0
        else
                echo "ERROR: could not install new MOTD" 1>&2
                exit 1
        fi
fi
echo "ERROR: could not generate new MOTD" 1>&2
exit 2

/etc/motd was then made into a symbolic link to /var/run/motd

And pam_motd copied it

Then, PAM thought that that was actually a cool idea and copied it from Ubuntu. In modern Linux, PAM is in charge of login authentication.

SSH uses the pam_motd module

session    optional     pam_motd.so  motd=/run/motd.dynamic

Ok, now we have yet another file, /run/motd.dynamic.

We can see that they almost literally copied the code.

if (do_update && (stat("/etc/update-motd.d", &st) == 0)
        && S_ISDIR(st.st_mode))
    {
       mode_t old_mask = umask(0022);
       if (!system("/usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ru
n-parts --lsbsysinit /etc/update-motd.d > /var/run/motd.new"))
           rename("/var/run/motd.new", "/var/run/motd");
       umask(old_mask);
    }

For this reason, even in Debian if we create the folder /etc/update-motd.d, which does not exist by default, it will be run at every login in the same way as if we had Ubuntu’s update-motd package installed.

Confusing huh? Well it gets worse because over time, Debian and Ubuntu have changed things, like the scripts populated in /etc/update-motd.d and the use of special files.

Files involved

  • /etc/motd – The classic, static file. Does not exist anymore in Ubuntu 16.04 LTS, not even as a symbolic link to /var/run/motd. If it is created, however its contents will be printed too.
  • /var/run/motd – This was used by Ubuntu’s first implementation. It is not used anymore. It is just ignored by PAM.
  • /var/run/motd.dynamicThis is what is shown on login currently. It is updated by /etc/init.d/motd at every boot. It is also updated by PAM by running the scripts in /etc/update-motd.d/, if they exist.
  • /etc/motd.tail – The Ubuntu package used to populate /etc/update-motd.d. One of them would cat the contents of this file so it was easy to add static content. That script does not exist in the package anymore, so the file does not have the intended effect.

How to then?

Okay, so once we understand why Google confuses us, it is pretty easy to customize our MOTD.

First, make sure to disable /etc/init.d/motd,  as it writes to /var/run/motd.dynamic.

...
# Update motd
uname -snrvm > /var/run/motd.dynamic
...

In my Raspbian Jessie, for instance it already came disabled. Just in case

sudo systemctl disable motd

Then, just delete current static MOTD, create /etc/update-motd.d folder and place scripts in it.

mkdir /etc/update-motd.d
rm -f /etc/motd                  # in Debian still exists

Scripts are run by run-parts, so they need not have an extension. They must start with digits so they will be run in order.

Finally, you can opt to get rid of the “last login” message if you want

PrintLastLog no

This is a simple example

cat > /etc/update-motd.d/10logo <<EOF
#!/bin/sh
echo
cat /etc/issue
EOF

cat > /etc/update-motd.d/20updates <<'EOF'
#!/bin/sh
echo
echo "uptime is $( uptime )"
echo "date   is $( date   )"
EOF

chmod a+x /etc/update-motd.d/*

Next login we will get

Debian GNU/Linux 9 


uptime is  15:40:52 up 2 days, 4 min,  1 user,  load average: 1.54, 1.48, 1.04
date   is Wed Apr  5 15:40:52 UTC 2017

Some ideas

FIGlet

You can use good old FIGlet. It will take your input and create some text based ASCII art.

$ figlet ownyourbits
                                            _     _ _
  _____      ___ __  _   _  ___  _   _ _ __| |__ (_) |_ ___
 / _ \ \ /\ / / '_ \| | | |/ _ \| | | | '__| '_ \| | __/ __|
| (_) \ V  V /| | | | |_| | (_) | |_| | |  | |_) | | |_\__ \
 \___/ \_/\_/ |_| |_|\__, |\___/ \__,_|_|  |_.__/|_|\__|___/
                     |___/

You can even get “fonts” for it here

$ figlet -ct -f roman ownyourbits
                                                                                     .o8        o8o      .
                                                                                    "888        `"'    .o8
   .ooooo.  oooo oooo    ooo ooo. .oo.   oooo    ooo  .ooooo.  oooo  oooo  oooo d8b  888oooo.  oooo  .o888oo  .oooo.o
  d88' `88b  `88. `88.  .8'  `888P"Y88b   `88.  .8'  d88' `88b `888  `888  `888""8P  d88' `88b `888    888   d88(  "8
  888   888   `88..]88..8'    888   888    `88..8'   888   888  888   888   888      888   888  888    888   `"Y88b.
  888   888    `888'`888'     888   888     `888'    888   888  888   888   888      888   888  888    888 . o.  )88b
  `Y8bod8P'     `8'  `8'     o888o o888o     .8'     `Y8bod8P'  `V88V"V8P' d888b     `Y8bod8P' o888o   "888" 8""888P'
                                         .o..P'
                                         `Y8P'
System info

You can play with lm-sensors to get information such as fan speed or temperature.

Also, you can print any of the typical system info provided by standard tools.

#!/bin/sh

upSeconds="$(/usr/bin/cut -d. -f1 /proc/uptime)"
secs=$((${upSeconds}%60))
mins=$((${upSeconds}/60%60))
hours=$((${upSeconds}/3600%24))
days=$((${upSeconds}/86400))
UPTIME=`printf "%d days, %02dh%02dm%02ds" "$days" "$hours" "$mins" "$secs"`

# get the load averages
read one five fifteen rest < /proc/loadavg

echo "$(tput setaf 2)
   .~~.   .~~.    `date +"%A, %e %B %Y, %r"`
  '. \ ' ' / .'   `uname -srmo`$(tput setaf 1)
   .~ .~~~..~.
  : .~.'~'.~. :   Uptime.............: ${UPTIME}
 ~ (   ) (   ) ~  Memory.............: `cat /proc/meminfo | grep MemFree | awk {'print $2'}`kB (Free) / `cat /proc/meminfo | grep MemTotal | awk {'print $2'}`kB (Total)
( : '~'.~.'~' : ) Load Averages......: ${one}, ${five}, ${fifteen} (1, 5, 15 min)
 ~ .~ (   ) ~. ~  Running Processes..: `ps ax | wc -l | tr -d " "`
  (  : '~' :  )   IP Addresses.......: `ip a | grep glo | awk '{print $2}' | head -1 | cut -f1 -d/` and `wget -q -O - http://icanhazip.com/ | tail`
   '~ .~~~. ~'    Weather............: `curl -s "http://rss.accuweather.com/rss/liveweather_rss.asp?metric=1&locCode=EUR|UK|UK001|NAILSEA|" | sed -n '/Currently:/ s/.*: \(.*\): \([0-9]*\)\([CF]\).*/\2°\3, \1/p'`
       '~'
$(tput sgr0)"

adapted from here.

Here is one example output

Termpix

You can get even fancier using tools like termpix. This tool creates ASCII art from pictures, and shows better if we have half block capable fonts available.

This is what I used for the MOTD in NextCloudPi.

landscape-sysinfo

This one is Ubuntu only.

sudo apt-get install landscape-common
$ landscape-sysinfo
  System load:  1.39             Processes:           3
  Usage of /:   3.1% of 9.99GB   Users logged in:     0
  Memory usage: 34%              IP address for eth0: 172.17.0.3
  Swap usage:   0%

  Graph this data and manage this system at:
    https://landscape.canonical.com/
Banner
sudo apt-get install sysvbanner
$ banner myownbits      

 #    #   #   #   ####   #    #  #    #  #####      #     #####   ####
 ##  ##    # #   #    #  #    #  ##   #  #    #     #       #    #
 # ## #     #    #    #  #    #  # #  #  #####      #       #     ####
 #    #     #    #    #  # ## #  #  # #  #    #     #       #         #
 #    #     #    #    #  ##  ##  #   ##  #    #     #       #    #    #
 #    #     #     ####   #    #  #    #  #####      #       #     ####
Boxes
sudo apt-get install boxes

Another classic

$ boxes -a c -d scroll <<< "gimme my bits"
 / ~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
|  /~~\                   /~~\  |
|\ \   |                 |   / /|
| \   /|  gimme my bits  |\   / |
|  ~~  |                 |  ~~  |
|      |                 |      |
 \     |~~~~~~~~~~~~~~~~~|     /
  \   /                   \   /
   ~~~                     ~~~
$ boxes -a c -d spring <<< "own your flowers"
      ,
  /\^/`\
 | \/   |
 | |    |                               jgs
 \ \    /                             _ _
  '\\//'                            _{ ' }_
    ||         own your flowers    { `.!.` }
    ||                             ',_/Y\_,'
    ||  ,                            {_,_}
|\  ||  |\                             |
| | ||  | |                          (\|  /)
| | || / /                            \| //
 \ \||/ /                              |//
  `\\//`   \   \./    \\   \./    \ \\ |/ /
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$ boxes -a c -d unicornthink <<< "there is no cloud"
   _________________________________
  /                                 \
  |        there is no cloud        |
  \______________________________ '\
                             ()    \\
                               O    \\  .
                                 o  |\\/|
                                    / " '\
                                    . .   .
                                   /    ) |
                                  '  _.'  |
                                  '-'/    \
$ boxes -a c -d mouse <<< "today is $(date)"
             .--,       .--,
            ( (  \.---./  ) )
             '.__/o   o\__.'
                {=  ^  =}
                 >  -  <
 ____________.""`-------`"".____________
/                                       \
\ today is Thu Apr  6 15:51:48 UTC 2017 /
/                                       \
\_______________________________________/
               ___)( )(___
              (((__) (__)))

List all different designs with

boxes -l
lolcat

You can spice up your creations with trippy rainbow colors with lolcat

Play with it

No need to risk your system. Test your ideas in a Docker container.

You can use ownyourbits minidebian container.

docker run --rm -ti ownyourbits/minidebian

, and the official Ubuntu container.

docker run --rm -ti ubuntu /bin/bash

References

https://wiki.ubuntu.com/UpdateMotd

https://wiki.debian.org/motd

Author: nachoparker

Humbly sharing things that I find useful [ github dockerhub ]

3 Comments on “Customize your MOTD login message in Debian and Ubuntu

  1. As you point out: “It is not a difficult thing to do but it can be a big waste of time to sort out the contradictions”. So, thank you very much for sorting this out!

    For me the missing part was sshd pam_mot.d, which was not activated on my server so nothing would show whatsoever. Its quite easy to overlook this setting, so if anyone else has trouble actually showing the motd this might be worth a look.

  2. This is a great post. It has cleared up a lot of confusion in regards to the MOTD message usage for debian/raspbian.

    I have also stumbled upon the issue of PAM not being enabled on my ssh server settings.
    I enabled it and followed the recommendation for using session checks:

    sudo vim /etc/ssh/sshd_config
    UsePAM yes
    PasswordAuthentication no
    ChallengeResponseAuthentication no

Leave a Reply

Your email address will not be published. Required fields are marked *