1. Introduction

The /etc/ directory is a common location for configuration files. Some are standard, while others are remnants of past functionality, available for backward compatibility. Although many configurations are self-contained, some spread across many files, sometimes with similar names. Ideas behind this split range from needing separate permissions to feature upgrades and compatibility.

In this tutorial, we talk about the initial messages users receive before and upon login, as well as how to control them. First, we explain what welcome banners and messages are. After that, we talk about the welcome banner in Linux. Finally, we explore welcome messages and how to configure their different parts.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments unless otherwise specified.

2. Welcome Banner and Message

Sometimes, interactive login shells just show just a basic login: prompt. Further, the default prefix to the login: prompt is the current hostname:

xost login:

However, most Linux systems also include a banner at this point. Yet, banners can be much more complex.

In addition, after the login shell, upon establishing an initial login session but before starting an interactive shell, many Linux distributions are configured to also show introductory information:

  • welcome message
  • disclaimers
  • update pompts
  • mail notifications
  • last login session
  • other initial data

Specifically, the aim of such preliminary messages is to guide new users, show current events, and generally make the environment more automated and user-friendly.

This behavior can be controlled and configured via different files.

3. Welcome Banner With /etc/issue and /etc/issue.net

Since a welcome banner is shown to every user, it usually doesn’t contain sensitive information. Because of this, there is often a limited number of parameters for its possible values. These mainly depend on TTY maintenance mechanisms like getty and agetty.

3.1. Local Banner in /etc/issue

In practice, the TTY maintenance service reads /etc/issue and interprets it for each login prompt:

Debian GNU/Linux 12 xost tty1

xost login: 

In this case, the first line is the actual banner.

Additionally, the use of /etc/issue can be dictated by the /etc/pam.d/login login service configuration file, as seen here with cat:

$ cat /etc/pam.d/login
# Outputs an issue file prior to each login prompt (Replaces the
# ISSUE_FILE option from login.defs). Uncomment for use
auth       required   pam_issue.so issue=/etc/issue

Further, this configuration can outsource this task to /etc/login.defs.

Let’s see what /etc/issue contains:

$ cat /etc/issue
Debian GNU/Linux 12 \n \l

Notably, in this case, there is an empty line at the end. Generally, the file contains some literal text but also escape sequences that the TTY maintenance service interprets:

  • \b: baud rate of the current line
  • \d: current date
  • \s: operating system name
  • \l: name of the current TTY line
  • \m: machine architecture
  • \n: node name, i.e. hostname
  • \o: domain name
  • \r: operating system release number
  • \t: current time
  • \u: count of logged-in users
  • \U: same as \u, but ending in user or users accordingly
  • \v: operating system version, build date, and similar

Many of these escape codes are direct flags of the uname command.

So, in our case, we could also replace the literal string Debian GNU/Linux 12 with \v for a similar final result:

$ cat /etc/issue
\v \n \l

Now, let’s see the login banner:

$ cat /etc/issue
#1 SMP Debian 5.10.666-1 (2023-06-06) xost tty1

xost login: 

Notably, we again see Debian as the OS, but this time it’s the build number instead of just the literal string 12.

3.2. Remote Banner in /etc/issue.net

On the other hand, /etc/issue.net is responsible for the banner, if any, that remote users see before logging in at the login prompt:

$ cat /etc/issue.net
Debian GNU/Linux 12

Notably, in this case, the default doesn’t include escape codes or an empty line for formatting. In fact, the escape codes here are actually format specifiers:

  • %d: current time and date, similar to \d and \t above
  • %D: name of the NIS domain, similar to \o above
  • %h: system node name (FQDN), similar to \n above
  • %m: machine architecture, same as \m above
  • %r; operating system release number, same as \r above
  • %s: operating system name, same as \s above
  • %t: current tty, similar to \l above
  • %v: operating system version, build date, and similar, same as \v above
  • %%: % character

While some Secure Shell (SSH) servers do use the file, /etc/issue.net is mostly a remnant of the telnet era. Because of this, even one of the most common SSH servers, OpenSSH, doesn’t use /etc/issue.net by default. Instead, OpenSSH acts according to its own Banner option, which only allows static files to be displayed. So, while we can add a configuration option like Banner /etc/issue.net, no format specifiers would be interpreted.

Let’s see what a default Telnet server shows:

$ apt-get install telnetd
$ cat /etc/inetd.conf
[...]
telnet  stream  tcp     nowait  root    /usr/sbin/tcpd  /usr/sbin/telnetd
[...]
$ systemctl restart inetd

After installing telnetd and configuring it by uncommenting a line in /etc/inetd.conf, we restart inetd with systemctl.

Now, we can connect via telnet:

$ telnet localhost
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Linux 5.10.0-23-amd64 (Xost) (pts/1)

xost login: 

After the initial lines, we see our banner is Linux 5.10.0-666-amd64 (Xost) (pts/1). This banner is the default for the latest Debian (currently Bookworm).

Still, we can get a glimpse of the /etc/issue.net file interpretation in a supported Linux distribution:

$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
[...]
$ cat /etc/issue.net
%v %h
$ telnet localhost
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
#1 SMP Fri Jul 07 07:00:10 UTC 2023 xold
xost login: 

Here, the /etc/os-release file verifies the older version of Debian that we use.

4. Welcome Messages

Welcome messages are text that appears right after logging in but just before the relevant shell is started. While there are global configurations, each user can see a different welcome message based on their settings and preferences. Most of the initial and subsequent login and security messages come from one or another  Pluggable Authentication Module (PAM).

Let’s explore options to influence welcome messages.

4.1. Message of the Day (MOTD)

One of the oldest and most common ways to show an initial message is the MOTD (Message Of The Day) /etc/motd file and mechanism:

$ 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.

Above, we see the content of /etc/motd on Debian. However, this is only part of the welcome information we see after logging in:

xost login: baeldung
Password:
Linux xost 5.10.0-10-amd64 #1 SMP Debian 5.10.666-1 (2023-06-26) x86_64

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.
You have new mail.
Last login: Fri Jul 07 07:00:07 2023 from 192.168.6.66

Let’s break down this content into separate blocks:

  • system data
  • legal information
  • mail notification
  • last login

In practice, the /etc/update-motd.d/ directory contains executable scripts, the output of which ends up at /var/run/motd.dynamic:

$ ls /etc/update-motd.d/
10-uname
$ cat /etc/update-motd.d/10-uname
#!/bin/sh
uname -snrvm
$ cat /var/run/motd.dynamic
Linux xost 5.10.0-10-amd64 #1 SMP Debian 5.10.666-1 (2023-06-26) x86_64

In this case, ls shows us we just have the 10-uname script, which runs uname with several switches. So, only its output goes to /var/run/motd.dynamic, representing the initial lines of the final welcome message.

Usually, the priority of each script is a prefix of its filename. Thus, we can decide which piece of data appears prior to another when adding our own scripts.

For instance, let’s add a simple script and check the result:

$ cat /etc/update-motd.d/15-date
#!/bin/sh
date
$ chmod +x /etc/update-motd.d/15-date
$ run-parts /etc/update-motd.d/ > /var/run/motd.dynamic
$ cat /var/run/motd.dynamic
Linux xost 5.10.0-10-amd64 #1 SMP Debian 5.10.666-1 (2023-06-26) x86_64
Fri Jul 07 08:00:10 EDT 2023

Here, we first see the script we add just shows the date. Next, we make the script executable via chmod. After that, we employ run-parts to immediately update /var/run/motd.dynamic with the new content, which we output.

To prevent any scripts from affecting motd.dynamic, we can perform one of three actions:

  • move the script outside /etc/update-motd.d/
  • remove the executable permission from the script
  • change specific settings in other files (like /etc/default/motd-news for the news module)

Finally, MOTD files might be cross-linked on some systems, depending on the setup.

Now, let’s see where the rest of the information in the welcome message comes from.

4.2. Mail Notifications

The /etc/pam.d/login configuration file is responsible for the notification of pending unread emails:

$ cat /etc/pam.d/login
[...]
# Prints the status of the user's mailbox upon successful login
# also removes the user's mail spool file.
session    optional   pam_mail.so standard
[...]

Here, we see that the optional pam_mail.so module is turned on in /etc/pam.d/login. Commenting out or removing the relevant line from this configuration would disable the notification.

4.3. Last Login

Indeed, we may sometimes want to see information about the last login session. To achieve this, the lastlog command reads a log of the last successful login attempts:

$ lastlog
Username         Port     From             Latest
root             tty1                      Fri Jul 07 07:00:07 -0400 2023
[...]
sshd                                       **Never logged in**
noot             pts/0    192.168.6.66     Fri Jul  7 07:00:07 -0400 2023
systemd-coredump                           **Never logged in**
user1                                      **Never logged in**
baeldung         pts/0    192.168.6.66     Fri Mar  3 00:00:01 -0500 2023
[...]

The actual log that holds the information is at /var/log/lastlog. The pam_lastlog.so module use /var/log/lastlog to output the last session information upon logging in. Of course, /etc/pam.d/login controls whether pam_lastlog.so is on:

$ cat /etc/pam.d/login
[...]
# Prints the last login info upon successful login
# (Replaces the `LASTLOG_ENAB' option from login.defs)
session    optional   pam_lastlog.so
[...]

Again, commenting out or removing the line turns off the behavior and message.

4.4. Remote Login

Depending on the environment and access method, some default welcome data might be irrelevant, insecure, or dangerous. For example, SSH banners and messages might (need to) differ from local ones.

For example, sshd has the PrintMotd option that specifies whether to print /etc/motd when logging it through SSH. In practice, enabling this option can result in MOTD appearing twice.

Another example involves the PrintLastLog option, which can disable the respective part of the welcome message.

4.5. Hide Welcome Messages

The existence of the .hushlogin file within the $HOME directory of a given user prevents any welcome messages for that user:

$ touch $HOME/.hushlogin

Thus, using touch as we did above silences the initial message for the current user. Which file has this special function is actually dictated by the /etc/login.defs file:

$ cat /etc/login.defs
[...]
#
# If defined, file which inhibits all the usual chatter during the login
# sequence.  If a full pathname, then hushed mode will be enabled if the
# user's name or shell are found in the file.  If not a full pathname, then
# hushed mode will be enabled if the file exists in the user's home directory.
#
HUSHLOGIN_FILE  .hushlogin
#HUSHLOGIN_FILE /etc/hushlogins
[...]

The /etc/hushlogins is also a hidden commented-out default.

5. Summary

In this article, we looked at welcome banners and messages, as well as how to configure and use them.

In conclusion, depending on the system, users can see and configure their welcome message, while administrators are often the only ones that can change banners.