252 lines
7.6 KiB
Nix
252 lines
7.6 KiB
Nix
# nyx-module/system/service/vnc.nix
|
|
#
|
|
# Provides:
|
|
# - TigerVNC multi-session server as a systemd service
|
|
# - Desktop session (.desktop file) for the chosen environment
|
|
# - Automatic password hashing at build time (via `vncpasswd -f`)
|
|
# - Optional firewall rule opening for chosen display port
|
|
#
|
|
# Options:
|
|
# enable → Enable the VNC server service
|
|
# user → System user that owns and runs the VNC server
|
|
# password → Plaintext password (hashed during build)
|
|
# displayNumber → X display number (e.g. :1 => TCP 5901)
|
|
# openFirewall → Open firewall for the corresponding TCP port
|
|
# session → Name of the desktop session (xfce, plasma, etc.)
|
|
# geometry → Screen resolution (e.g. 1920x1080)
|
|
# sessionCommand→ Command to start the X session
|
|
#
|
|
# Example:
|
|
# nyx-module.system.service.vnc = {
|
|
# enable = true;
|
|
# user = "myuser";
|
|
# password = "secret12";
|
|
# session = "xfce";
|
|
# geometry = "1280x800";
|
|
# };
|
|
#
|
|
# After enabling, run:
|
|
# sudo nixos-rebuild switch
|
|
# sudo systemctl enable --now vncserver
|
|
#
|
|
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}:
|
|
with lib; let
|
|
cfg = config.nyx-module.system.service.vnc;
|
|
|
|
# Resolve the user home safely even if the user isn't declared yet.
|
|
userHome = lib.attrByPath ["users" "users" cfg.user "home"] "/home/${cfg.user}" config;
|
|
|
|
# Only generate passwd file if enabled, otherwise null
|
|
generatedPasswdFile =
|
|
if cfg.enable
|
|
then
|
|
pkgs.runCommand "tigervnc-passwd" {
|
|
buildInputs = [pkgs.tigervnc];
|
|
} ''
|
|
mkdir -p $out
|
|
echo -n "${cfg.password}" | vncpasswd -f > $out/passwd
|
|
''
|
|
else null;
|
|
in {
|
|
options.nyx-module.system.service.vnc = {
|
|
enable = mkEnableOption "Enable a TigerVNC multi-session server.";
|
|
|
|
user = mkOption {
|
|
type = types.str;
|
|
example = "myuser";
|
|
description = "System user that owns and runs the VNC server.";
|
|
};
|
|
|
|
password = mkOption {
|
|
type = types.str;
|
|
example = "secret12";
|
|
description = ''
|
|
Plaintext VNC password. Will be hashed at build time using
|
|
`vncpasswd -f`. **Warning:** Stored in the Nix store, only
|
|
the first 8 characters are significant.
|
|
'';
|
|
};
|
|
|
|
displayNumber = mkOption {
|
|
type = types.int;
|
|
default = 1;
|
|
description = "X display number (:1 => TCP 5901).";
|
|
};
|
|
|
|
openFirewall = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = "Open the firewall for the selected display port.";
|
|
};
|
|
|
|
session = mkOption {
|
|
type = types.str;
|
|
default = "xfce";
|
|
example = "plasma";
|
|
description = "Name of the desktop session (matches .desktop file).";
|
|
};
|
|
|
|
geometry = mkOption {
|
|
type = types.str;
|
|
default = "1920x1080";
|
|
description = "Default VNC display resolution.";
|
|
};
|
|
|
|
sessionCommand = mkOption {
|
|
type = types.str;
|
|
default = "${pkgs.xterm}/bin/xterm";
|
|
example = "${pkgs.xfce4-session}/bin/startxfce4";
|
|
description = "Command to start the X session.";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
# Install required packages
|
|
environment.systemPackages = with pkgs; [
|
|
tigervnc
|
|
xorg.xauth
|
|
xorg.xinit
|
|
];
|
|
|
|
# Enable X server and desktop environment
|
|
services.xserver = {
|
|
enable = true;
|
|
desktopManager.xfce.enable = true;
|
|
xkb.layout = "de";
|
|
displayManager.defaultSession = cfg.session; # fixed option path
|
|
};
|
|
|
|
# Configure session
|
|
services.xserver.displayManager.session = [
|
|
{
|
|
manage = "desktop";
|
|
name = cfg.session;
|
|
start = ''
|
|
${cfg.sessionCommand} &
|
|
waitPID=$!
|
|
'';
|
|
}
|
|
];
|
|
|
|
# Install a custom .desktop file for session
|
|
environment.etc."xdg/xsessions/${cfg.session}.desktop".text = ''
|
|
[Desktop Entry]
|
|
Name=${cfg.session}
|
|
Comment=Custom ${cfg.session} session for VNC
|
|
Exec=${cfg.sessionCommand}
|
|
Type=Application
|
|
'';
|
|
|
|
system.activationScripts.linkCustomSession = ''
|
|
mkdir -p /usr/share/xsessions
|
|
ln -sf /etc/xdg/xsessions/${cfg.session}.desktop \
|
|
/usr/share/xsessions/${cfg.session}.desktop
|
|
'';
|
|
|
|
# Systemd service for VNC server
|
|
systemd.services.vncserver = {
|
|
description = "TigerVNC server on :${toString cfg.displayNumber}";
|
|
after = ["network.target" "syslog.target"];
|
|
wantedBy = ["multi-user.target"];
|
|
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
User = cfg.user;
|
|
TimeoutStartSec = "60s";
|
|
WorkingDirectory = userHome;
|
|
PIDFile = "${userHome}/.vnc/%H:${toString cfg.displayNumber}.pid";
|
|
|
|
Environment = "PATH=${pkgs.xorg.xinit}/bin:${pkgs.tigervnc}/bin:${pkgs.xorg.xauth}/bin:/run/current-system/sw/bin";
|
|
|
|
ExecStartPre = pkgs.writeShellScript "prepare-vnc" ''
|
|
mkdir -p ${userHome}/.vnc
|
|
cp ${generatedPasswdFile}/passwd ${userHome}/.vnc/passwd
|
|
chmod 600 ${userHome}/.vnc/passwd
|
|
chown ${cfg.user}:users ${userHome}/.vnc/passwd
|
|
|
|
mkdir -p ${userHome}/.config/tigervnc
|
|
cat > ${userHome}/.config/tigervnc/config <<EOF
|
|
session=${cfg.session}
|
|
geometry=${cfg.geometry}
|
|
alwaysshared
|
|
rfbauth=${userHome}/.vnc/passwd
|
|
EOF
|
|
|
|
# Minimal xstartup with logging
|
|
cat > ${userHome}/.vnc/xstartup <<'EOF'
|
|
#!/bin/sh
|
|
|
|
export DISPLAY=:${toString cfg.displayNumber}
|
|
export XAUTHORITY="$HOME/.Xauthority"
|
|
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
|
|
export XKL_XMODMAP_DISABLE=1
|
|
export GTK_USE_PORTAL=0
|
|
export PULSE_SERVER=unix:/run/user/$(id -u)/pulse/native
|
|
export PULSE_SERVER=tcp:localhost:4714
|
|
# Log:
|
|
echo "=== Starting VNC session on $(date) ===" >> "$HOME/.vnc/xstartup.log" 2>&1
|
|
|
|
# Load user profile to get PATH, XDG vars, etc.
|
|
if [ -f /etc/profile ]; then
|
|
. /etc/profile
|
|
fi
|
|
|
|
# Source NixOS user environment
|
|
if [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
|
|
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
|
fi
|
|
|
|
export XDG_SESSION_TYPE=x11
|
|
export XDG_CURRENT_DESKTOP=XFCE
|
|
export XDG_CONFIG_HOME="$HOME/.config"
|
|
|
|
${cfg.sessionCommand} >> "$HOME/.vnc/xstartup.log" 2>&1 &
|
|
|
|
wait $!
|
|
EOF
|
|
|
|
chmod +x ${userHome}/.vnc/xstartup
|
|
chown ${cfg.user}:users ${userHome}/.vnc/xstartup
|
|
touch ${userHome}/.vnc/xstartup.log
|
|
chown ${cfg.user}:users ${userHome}/.vnc/xstartup.log
|
|
chmod 600 ${userHome}/.vnc/xstartup.log
|
|
'';
|
|
|
|
ExecStart = "${pkgs.tigervnc}/bin/vncserver :${toString cfg.displayNumber}";
|
|
ExecStop = "${pkgs.procps}/bin/pkill -f 'Xvnc :${toString cfg.displayNumber}' || true";
|
|
};
|
|
};
|
|
|
|
environment.etc."X11/Xsession" = {
|
|
text = ''
|
|
#!/bin/sh
|
|
LOGFILE="$HOME/.vnc/xsession.log"
|
|
mkdir -p "$HOME/.vnc"
|
|
touch "$LOGFILE"
|
|
chmod 600 "$LOGFILE"
|
|
|
|
echo "=== Xsession started on $(date) ===" >> "$LOGFILE" 2>&1
|
|
|
|
if [ -x "$HOME/.vnc/xstartup" ]; then
|
|
echo "Found xstartup, executing..." >> "$LOGFILE" 2>&1
|
|
exec "$HOME/.vnc/xstartup" >> "$LOGFILE" 2>&1
|
|
else
|
|
echo "No ~/.vnc/xstartup found, cannot start session." >> "$LOGFILE" 2>&1
|
|
echo "No ~/.vnc/xstartup found, cannot start session." >&2
|
|
exit 1
|
|
fi
|
|
'';
|
|
mode = "0755";
|
|
};
|
|
|
|
# Optionally open firewall
|
|
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [
|
|
(5900 + cfg.displayNumber)
|
|
];
|
|
};
|
|
}
|