A display manager or login manager is a graphical interface shown at the end of boot. It presents the user with a login screen, and when credentials are entered it starts a session on an X server. Examples of such software can be found in Debian, Arch, and Gentoo wiki. The default on a NixOS installation is LightDM, a relatively lightweight and highly customizable display manager with various front-ends (greeters) written in a variety of toolkits (NixOS defaults to the GTK one). Though a good choice, for an one-user system where user wants to just run their session without much else its features are mostly unneeded.
Disabling the display manager
NixOS allows decleratively setting various options, among them is the default session and autologin which are dependent on the display manager. For example if the user named user (cleverly thought, right?) wants to login automatically at their i3 session the following configuration may be used.
...
services.xserver = {
displayManager = {
defaultSession = "none+i3";
autoLogin = {
enable = true;
user = user;
};
};
windowManager.i3.enable = true;
};
...
In order for the display manager to be suppressed the following option exists. According to the documentation, this enables a dummy pseudo-display manager. Basically it disables LightDM, the display-manager systemd service and sets Xorg’s log file to null (see <nixpkgs/…/start.nix>). Most importantly it enables the xinit and startx (wrapper to xinit) commands at the global environment.
...
services.xserver = {
displayManager = {
startx.enable = true;
};
};
...
Unfortunately it also means losing autologin functionality and some set up done by the display manager. In case anyone wonders, autologin is useful when full-disk encryption is used. As a password is entered during the boot the need for a second password just few seconds later is mostly pointless.
Autologin
Automatical login of a user can be done creating a systemd (system) service. For this the following configuration can used, adapted from an @caadar’s gist. Specifically a new target is created, the kernel logging is suppressed, and the service logs in the user named user after the multi-user target has been reached.
...
systemd.targets = {
"autologin-tty1" = {
requires = [ "multi-user.target" ];
after = [ "multi-user.target" ];
unitConfig.AllowIsolate = "yes";
};
};
systemd.services = {
"autovt@tty1" = {
enable = true;
restartIfChanged = false;
description = "autologin service at tty1";
after = [ "suppress-kernel-logging.service" ];
wantedBy = [ "autologin-tty1.target" ];
serviceConfig = {
ExecStart = builtins.concatStringsSep " " ([
"@${pkgs.utillinux}/sbin/agetty"
"agetty --login-program ${pkgs.shadow}/bin/login"
"--autologin user --noclear %I $TERM"
]);
Restart = "always";
Type = "idle";
};
};
"suppress-kernel-logging" = {
enable = true;
restartIfChanged = false;
description = "suppress kernel logging to the console";
after = [ "multi-user.target" ];
wantedBy = [ "autologin-tty1.target" ];
serviceConfig = {
ExecStart = "${pkgs.utillinux}/sbin/dmesg -n 1";
Type = "oneshot";
};
};
...
The restartIfChange
is set to false
so, if a nixos-rebuild
takes
place and the service has changed, the session won’t absurdly restart.
Nevertheless it will restart if user decides to exit the sesssion.
Autostarting X
There’re two ways to autostart X on console login. Either using the profile, or as a systemd user service. Theoretically the optimal will be the later since the profile is for shell configuration and environment set up rather running services. This is for the service manager to do (systemd in NixOS case). But it is also substantially more complicated (see Pitt’s slides) and moreover requires running a Xorg server as root (though the session will be run as user). In contrast the former way is mostly trivial and also runs Xorg as user.
First, we need to source the ~/.profile
. This isn’t done by default.
Rather the following configuration has to be added. This makes an
/etc/profile.local
sourced by /etc/profile
which sources
~/.profile
.
...
environment.etc = {
"profile.local".text = ''
# /etc/profile.local: DO NOT EDIT -- this file has been generated automatically.
if [ -f "$HOME/.profile" ]; then
. "$HOME/.profile"
fi
'';
};
...
The startx
will run the ~/.xinitrc
file. Therefore to run i3 adding
the following will be enough.
exec i3
Then at the end of ~/.profile
the following will run startx
if no
display has been set and only on logging at tty1. Therefore it won’t run
on other consoles or when the shell opens in a terminal.
if [ -z "$DISPLAY" ] && [ $TTY == "/dev/tty1" ]; then
exec startx
fi
Someone may argue that it could be added in /etc/profile.local
directly. But in that case X will run before any user configuration
takes place.
Set-up X
The display manager loads ~/.xprofile
which is used to execute
commands at the beginning of the user session, and ~/.Xresources
which sets parameters for X applications. Therefore simply add the
following before executing the window manager.
[ -f ~/.xprofile ] && . ~/.xprofile
[ -f ~/.Xresources ] && xrdb -merge ~/.Xresources
A display manager also loads the ~/.pam_environment
. The variables
used in it have to be moved to ~/.profile
before starting up X. It
should be noted that on NixOS there’s no /etc/environment
or or
/etc/security/pam_env.conf
file, rather environment variables set in
configuration.nix will be added in /etc/profile
. This is the place
where most of set up takes place making a display manager even less
necessary.
Also the user’s dbus daemon has to be set. This is done adding the
following to ~/.xinitrc
, taken from nixos.wiki.
if test -z "$DBUS_SESSION_BUS_ADDRESS"; then
eval $(dbus-launch --exit-with-session --sh-syntax)
fi
systemctl --user import-environment DISPLAY XAUTHORITY
if command -v dbus-update-activation-environment >/dev/null 2>&1; then
dbus-update-activation-environment DISPLAY XAUTHORITY
fi
The wiki also shows how to run X without installing it system-wide. This could be useful in a multi-user environment or/and if running Nix on another system (non-NixOS). For both cases some modifications are required.
Finally start the graphical-session target in systemd.
systemctl --user start graphical-session.target
The graphical-session target was made for services that require a graphical session to be running. As many services are starting at that run level, without the previous some of them will never run.
TODO: Add systemd-based X autostart
TODO: Add Wayland (sway) instructions