Hello everyone, I’ve installed nixos a couple of days ago.
One of the difficulties I had was how to startx xorg via systemd socket activation.
I need this to transfer my old home stuff on arch to the new distro.
startx works fine overall, but because of it’s not started by systemd some stuff like ~/.config/environment.d is not loaded.
But in general, it’s not clear what’s missing, since xinit and the parameters may be the same.
Trying to start x11.service I get
xf86OpenConsole: Cannot open virtual console 1 (Permission denied)
I’ve tried change default tty rules via
services.udev.extraRules = ''
SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666"
SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="sclp_line[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="ttysclp[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="3270/tty[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty"
KERNEL=="tty[A-Z]*[0-9]|ttymxc[0-9]*|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="uucp"
SUBSYSTEM=="input", GROUP="input"
SUBSYSTEM=="input", KERNEL=="js[0-9]*", MODE="0664"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
KERNEL=="rfkill", MODE="0664"
'';
without success
My systemwide config:
/mnt/loop1/etc/nixos ❯> cat configuration.nix filesystems.nix networking.nix nvidia.nix
# Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
{ config, lib, pkgs, modulesPath, packageOverrides, ... }:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
./filesystems.nix
./networking.nix
./nvidia.nix
];
nix.extraOptions = ''experimental-features = nix-command flakes'';
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "usb_storage" "usbhid" "sd_mod" ];
boot.initrd.kernelModules = [ "dm-snapshot" ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
networking.hostName = "telfir"; # Define your hostname.
networking.wireless.enable = false; # Enables wireless support via wpa_supplicant.
networking.networkmanager.enable = true;
time.timeZone = "Europe/Moscow";
i18n.defaultLocale = "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "ru_RU.UTF-8";
LC_IDENTIFICATION = "ru_RU.UTF-8";
LC_MEASUREMENT = "ru_RU.UTF-8";
LC_MONETARY = "ru_RU.UTF-8";
LC_NAME = "ru_RU.UTF-8";
LC_NUMERIC = "ru_RU.UTF-8";
LC_PAPER = "ru_RU.UTF-8";
LC_TELEPHONE = "ru_RU.UTF-8";
LC_TIME = "ru_RU.UTF-8";
};
services.xserver.enable = true;
services.xserver.displayManager.startx.enable = true;
services.xserver.displayManager.autoLogin.enable = true;
services.xserver.displayManager.autoLogin.user = "neg";
systemd.packages = [ pkgs.packagekit ];
services.xserver = {
layout = "us,ru";
xkbVariant = "";
xkbOptions = "grp:alt_shift_toggle";
};
security.polkit.enable = true;
security.loginDefs.settings.TTYPERM = "0666";
security.sudo.extraRules= [ {
users = [ "privileged_user" ];
commands = [
{ command = "ALL" ;
options= [ "NOPASSWD" ]; # "SETENV" # Adding the following could be a good idea
}
];
}
];
security.pam.loginLimits = [
{ domain = "@users"; item = "rtprio"; type = "-"; value = 1; }
];
security.pam.services.xserver.startSession = true;
security.pam.services.xserver.forwardXAuth = true;
# security.pam.enableGnomeKeyring = true;
# This is using a rec (recursive) expression to set and access XDG_BIN_HOME within the expression
# For more on rec expressions see https://nix.dev/tutorials/first-steps/nix-language#recursive-attribute-set-rec
environment.sessionVariables = rec {
XDG_CACHE_HOME = "$HOME/.cache";
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_STATE_HOME = "$HOME/.local/state";
XDG_BIN_HOME = "$HOME/.local/bin";
PATH = [ "${XDG_BIN_HOME}" ];
};
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
liberation_ttf
iosevka
];
services.printing.enable = false;
hardware.pulseaudio.enable = false;
security.rtkit.enable = true; # rtkit is optional but recommended
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
jack.enable = true;
};
services.xserver.libinput.enable = true; # Enable touchpad support (enabled default in most desktopManager).
# Define a user account. Don't forget to set a password with ‘passwd’.
users.users.neg = {
isNormalUser = true;
description = "Neg";
extraGroups = [
"audio"
"neg"
"networkmanager"
"systemd-journal"
"video"
"wheel"
"tty"
"input"
];
};
users.defaultUserShell = pkgs.zsh;
users.groups.neg.gid = 1000;
nixpkgs.config.allowUnfree = true;
environment.systemPackages = with pkgs; [
curl
gcc
gdb
git
neovim
nix-index
python3
tig
tmux
wget
zsh
];
environment.shells = with pkgs; [ zsh ];
programs.dconf.enable = true;
programs.mtr.enable = true;
programs.zsh = { enable = true; };
services.openssh.enable = true;
services.flatpak.enable = true;
services.getty.autologinUser = "neg";
xdg.portal.enable = true;
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
xdg.portal.config.common.default = "gtk";
# (man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "23.11"; # Did you read the comment?
}
{ config, lib, pkgs, modulesPath, ... }:
{
# UUID=C06B-349A /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 2
# /dev/main/sys / f2fs rw,relatime,lazytime,background_gc=off,no_heap,inline_xattr,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,alloc_mode=default,fsync_mode=posix 0 1
# /dev/main/home /home f2fs x-systemd.automount,rw,relatime,lazytime,background_gc=off,no_heap,inline_xattr,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,alloc_mode=default,fsync_mode=posix 0 1
# /dev/argon/zero /zero f2fs rw,defaults,x-systemd.automount,relatime,lazytime 0 0
# /dev/xenon/one /one f2fs rw,defaults,x-systemd.automount,relatime,lazytime 0 0
# /one/music /home/neg/music none nofail,x-systemd.automount,bind 0 0
# /one/torrent /home/neg/torrent none nofail,x-systemd.automount,bind 0 0
# /one/vid /home/neg/vid none nofail,x-systemd.automount,bind 0 0
# /one/games /home/neg/games none nofail,x-systemd.automount,bind 0 0
# /one/mail /home/neg/.local/mail none nofail,x-systemd.automount,bind 0 0
# /zero/opt /opt none nofail,x-systemd.automount,bind 0 0
# /zero/flatpak /home/neg/.var none nofail,x-systemd.automount,bind 0 0
# tmpfs /dev/shm tmpfs defaults,rw,nosuid,noexec,nodev,size=32g 0 0
fileSystems."/" =
{ device = "/dev/mapper/xenon-nix";
fsType = "f2fs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/C06B-349A";
fsType = "vfat";
};
fileSystems."/home" =
{ device = "/dev/mapper/main-home";
fsType = "f2fs";
};
fileSystems."/one" =
{ device = "/dev/mapper/xenon-one";
fsType = "f2fs";
};
fileSystems."/zero" =
{ device = "/dev/mapper/argon-zero";
fsType = "f2fs";
};
fileSystems."/home/neg/music"={device="/one/music"; options=["bind"];};
fileSystems."/home/neg/torrent"={device="/one/torrent"; options=["bind"];};
fileSystems."/home/neg/vid"={device="/one/vid"; options=["bind"];};
fileSystems."/home/neg/games"={device="/one/games"; options=["bind"];};
fileSystems."/home/neg/.var"={device="/zero/flatpak"; options=["bind"];};
swapDevices = [ ];
}
{ config, lib, pkgs, modulesPath, ... }:
{
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp6s0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp8s0.useDHCP = lib.mkDefault true;
}
{ config, lib, pkgs, ... }:
{
hardware.opengl = {
enable = true;
driSupport = true;
driSupport32Bit = true;
};
boot.blacklistedKernelModules = [ "nouveau" ];
boot.extraModprobeConfig = ''
blacklist nouveau
options nouveau modeset=0
'';
environment = {
systemPackages = with pkgs;
[ glxinfo ];
variables = { __GL_GSYNC_ALLOWED = "1"; };
};
services.xserver = {screenSection = ''Option "metamodes" "3440x1440_175 +0+0 {AllowGSYNCCompatible=On}"'';};
services.xserver.videoDrivers = ["nvidia"];
hardware.nvidia = {
modesetting.enable = true; # Modesetting is required.
# Nvidia power management. Experimental, and can cause sleep/suspend to fail. powerManagement.enable = false;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
powerManagement.finegrained = false;
open = false; # Currently alpha-quality/buggy, so false is currently the recommended setting.
nvidiaSettings = true;
#package = config.boot.kernelPackages.nvidiaPackages.stable;
};
# services.udev.extraRules = ''
# SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
# SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666"
# SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
# SUBSYSTEM=="tty", KERNEL=="sclp_line[0-9]*", GROUP="tty", MODE="0620"
# SUBSYSTEM=="tty", KERNEL=="ttysclp[0-9]*", GROUP="tty", MODE="0620"
# SUBSYSTEM=="tty", KERNEL=="3270/tty[0-9]*", GROUP="tty", MODE="0620"
# SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty"
# KERNEL=="tty[A-Z]*[0-9]|ttymxc[0-9]*|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="uucp"
#
# SUBSYSTEM=="input", GROUP="input"
# SUBSYSTEM=="input", KERNEL=="js[0-9]*", MODE="0664"
#
# SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
#
# KERNEL=="rfkill", MODE="0664"
# '';
}
and here is the home stuff
~/.config/home-manager ❯> cat home.nix
{ config, pkgs, ... }:
{
home.username = "neg";
home.homeDirectory = "/home/neg";
home.stateVersion = "23.11"; # Please read the comment before changing.
home.packages = with pkgs; [
acpi
bat
dash
dunst
fasd
ffmpeg
firefox
flameshot
gnome.gpaste
hsetroot
i3
inputplug
jq
kitty
libnotify
lshw
maim
mpc-cli
mpd
mpdas
mpdris2
mpv
ncmpcpp
ncpamixer
neovim-remote
netcat
nsxiv
pass
picom
polybar
python3
python311Packages.pip
rofi
# stig
stow
telegram-desktop
transmission
udisks2
unclutter-xfixes
unzip
wmctrl
xclip
xdotool
xsel
xterm
ydotool
yt-dlp
zathura
];
services.udiskie = { enable = true; };
services.gpg-agent = {
enable = true;
enableScDaemon = true;
enableSshSupport = true;
defaultCacheTtl = 60480000;
pinentryFlavor = "gnome3";
verbose = true;
};
systemd.user.targets.tray = {
Unit = {
Description = "Home Manager System Tray";
Requires = ["graphical-session-pre.target"];
};
};
systemd.user.services.i3 = {
Unit = {
Description = "i3 improved dynamic tiling window manager for X";
Documentation = "man:i3(5)";
Wants = ["graphical-session-pre.target" "i3-session.target"];
After = ["graphical-session-pre.target" "i3-session.target"];
BindsTo = ["graphical-session.target"];
PartOf = ["graphical-session.target"];
#OnFailure = notify@%i.service
};
Service = {
ExecStart = "${pkgs.i3}/bin/i3";
ExecReload = ["${pkgs.i3}/i3-msg reload" "${pkgs.systemd}/bin/systemctl --user restart negwm.service"];
ExecStopPost = "${pkgs.systemd}/bin/systemctl --user stop --no-block graphical-session.target";
Restart = "on-failure";
RestartSec = "5";
TimeoutStopSec = "10";
};
};
systemd.user.services.mpdris2 = {
Unit = {
Description = "mpDris2 - Music Player Daemon D-Bus bridge";
Requires = "mpd.service";
BindsTo = "mpd.service";
ConditionPathExists = "${pkgs.mpdris2}/bin/mpDris2";
# OnFailure=notify@%i.service
};
Service = {
Restart = "on-failure";
ExecStart = "${pkgs.mpdris2}/bin/mpDris2 --use-journal";
BusName = "org.mpris.MediaPlayer2.mpd";
};
Install = { WantedBy = ["default.target"]; };
};
systemd.user.services.negwm-autostart = {
Unit = {
Description = "Startup stuff depended on negwm";
Requires = "negwm.service";
After = ["negwm.service" "executor.service"];
#OnFailure = "notify@%i.service";
};
Service = {
Type = "oneshot";
ExecStart = "${pkgs.dash}/bin/dash -c \"echo 'circle next term' | ${pkgs.netcat}/bin/nc localhost 15555 -w 0\"";
Restart = "on-failure";
RestartSec = "1";
StartLimitBurst = "20";
};
};
systemd.user.services.negwm = {
Unit = {
Description = "negwm window manager mod for i3wm";
PartOf = ["graphical-session.target"];
StartLimitBurst = "5";
StartLimitIntervalSec = "0";
Requires = ["xsettingsd.service"];
# OnFailure=notify@%i.service
};
Service = {
ExecStart = "%h/bin/negwm";
Restart = "on-failure";
};
};
systemd.user.services.x11 = {
Unit = {
Description = "Xorg";
Documentation = "man:Xorg(1)";
Requires = ["x11.socket"];
After = "x11.socket";
Before = "x11.target";
#OnFailure = "notify@%i.service";
};
Service = {
Environment = ["XDG_SESSION_TYPE=x11" "XSERVERRC=%E/xinit/xserverrc"];
ExecStartPre = "${pkgs.dbus}/bin/dbus-update-activation-environment --all";
ExecStart = "${pkgs.xorg.xinit}/bin/xinit ${pkgs.i3}/bin/i3 -- :0 -nolisten tcp vt1";
SuccessExitStatus = "0 1";
};
Install = {
Also = ["x11.socket" "x11.target"];
WantedBy = ["default.target"];
};
};
systemd.user.services.picom = {
Unit = {
Description = "Compositing manager";
Documentation = "man:Xorg(1)";
After = "dbus.socket";
Before = "x11.target";
PartOf = ["graphical-session.target"];
StartLimitIntervalSec = "60";
Requires = ["x11.service"];
OnFailure = "notify@%i.service";
};
Service = {
ExecStart = "${pkgs.picom}/bin/picom --dbus --backend glx";
ExecReload = "${pkgs.util-linux}/bin/kill -SIGUSR1 $MAINPID";
Restart = "on-failure";
RestartSec = "1";
StartLimitBurst = "3000";
};
};
systemd.user.services.inputplug = {
Unit = {
Description = "XInput event monitor";
PartOf = ["graphical-session.target"];
OnFailure = ["notify@%i.service"];
};
Service = {
ExecStart = "${pkgs.inputplug}/bin/inputplug -d -0 -c %h/bin/input-event";
Restart = "on-failure";
};
};
systemd.user.services.cover-notify = {
Unit = {
Description = "Music track notification with cover";
After = ["network.target" "sound.target" "playerctld.service" "mpd.service" "mpDris2.service"];
BindsTo = "mpDris2.service";
OnFailure = ["notify@%i.service"];
};
Service = {
ExecStart = "%h/bin/track-notification-daemon";
Restart = "always";
StartLimitIntervalSec = "0";
RestartSec = "3";
};
Install = {
WantedBy = ["default.target"];
};
};
systemd.user.services.openrgb = {
Unit = {
Description = "OpenRGB Configuration utility for RGB lights supporting motherboards, RAM, & peripherals";
After = ["dbus.socket"];
PartOf = ["graphical-session.target"];
OnFailure = ["notify@%i.service"];
};
Service = {
ExecStart = "${pkgs.openrgb}/bin/openrgb --server -p neg.orp";
RestartSec = "30";
StartLimitBurst = "8";
};
Install = {
WantedBy = ["default.target"];
};
};
systemd.user.services.polybar = {
Unit = {
Description = "Polybar statusbar";
PartOf = ["graphical-session.target"];
StartLimitIntervalSec = "60";
Requires = "xsettingsd.service";
BindsTo = "xsettingsd.service";
OnFailure = "notify@%i.service";
};
Service = {
ExecStart = "${pkgs.polybar}/bin/polybar -q main";
ExecStop = "${pkgs.polybar}/bin/polybar-msg cmd quit";
Restart = "on-failure";
RestartSec = "3";
StartLimitBurst = "30";
};
};
systemd.user.services.mpdas = {
Unit = {
Description = "mpdas last.fm scrobbler";
After = ["network.target" "sound.target" "mpd.service"];
Requires = "mpd.service";
OnFailure = "notify@%i.service";
};
Service = {
ExecStart = "${pkgs.mpdas}/bin/mpdas -c %E/mpdas/neg.rc";
Restart = "on-failure";
RestartSec = "10";
};
Install = {
WantedBy = ["default.target"];
};
};
systemd.user.services.mpd = {
Unit = {
Description = "Music Player Daemon";
Documentation = "man:mpd(1) man:mpd.conf(5)";
After = ["network.target" "sound.target"];
ConditionPathExists = "${pkgs.mpd}/bin/mpd";
OnFailure = "notify@%i.service";
};
Service = {
Type = "notify";
ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon";
# Enable this setting to ask systemd to watch over MPD, see
# systemd.service(5). This is disabled by default because it causes
# periodic wakeups which are unnecessary if MPD is not playing.
#WatchdogSec=120
# allow MPD to use real-time priority 40
LimitRTPRIO = "40";
LimitRTTIME = "infinity";
# for io_uring
LimitMEMLOCK = "64M";
# disallow writing to /usr, /bin, /sbin, ...
ProtectSystem = "yes";
# more paranoid security settings
NoNewPrivileges = "yes";
ProtectKernelTunables = "yes";
ProtectControlGroups = "yes";
# AF_NETLINK is required by libsmbclient, or it will exit() .. *sigh*
RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK"];
RestrictNamespaces = "yes";
# Note that "ProtectKernelModules=yes" is missing in the user unit
# because systemd 232 is unable to reduce its own capabilities
# ("Failed at step CAPABILITIES spawning /usr/bin/mpd: Operation not
# permitted")
Restart = "on-failure";
RestartSec = "5";
};
Install = {
WantedBy = ["default.target"];
};
};
systemd.user.sockets.x11 = {
Unit = {
Description = "X11 Server Socket";
Before = ["x11.target"];
};
Socket = {
ListenStream = "/tmp/.X11-unix/X0";
};
Install = {
WantedBy = ["sockets.target"];
};
};
home.file = {
".config/xinit/xserverrc".text = ''
exec ${pkgs.xorg.xorgserver}/bin/Xorg -ardelay 250 -arinterval 20 -nolisten tcp "$@" vt$XDG_VTNR
'';
};
home.sessionVariables = {
# EDITOR = "emacs";
};
programs.home-manager.enable = true; # Let Home Manager install and manage itself.
}
The problem is that it seems that systemd does not have enough rights to manage the tty or something like that. Perhaps x-server itself requires a suid bit, not sure yet.
Maybe I need some specific pam stuff to make it work, but not sure what exactly.
Using chown 0777 /dev/tty*
also does not make things better.
This scheme works on arch linux nicely.
/etc/X11/Xwrapper.config is also setuped:
needs_root_rights = yes
allowed_users = anybody
Xwrapper does not work in nixos?