From 03d9e5cda0db6d4b213f595d3320eb3b69818444 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Apr 2014 16:07:53 +0200 Subject: [PATCH] sshd: Add support for socket activation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By enabling ‘services.openssh.startWhenNeeded’, sshd is started on-demand by systemd using socket activation. This is particularly useful if you have a zillion containers and don't want to have sshd running permanently. Note that socket activation is not noticeable slower, contrary to what the manpage for ‘sshd -i’ says, so we might want to make this the default one day. --- .../modules/services/networking/ssh/sshd.nix | 79 +++++++++++++------ .../virtualisation/container-config.nix | 3 + 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index d666b462d15..554cc6a1c3f 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -86,6 +86,16 @@ in ''; }; + startWhenNeeded = mkOption { + type = types.bool; + default = false; + description = '' + If set, sshd is socket-activated; that + is, instead of having it permanently running as a daemon, + systemd will start an instance for each incoming connection. + ''; + }; + forwardX11 = mkOption { type = types.bool; default = cfgc.setXAuthLocation; @@ -248,37 +258,60 @@ in } ]; - systemd.services.sshd = - { description = "SSH Daemon"; + systemd = + let + service = + { description = "SSH Daemon"; - wantedBy = [ "multi-user.target" ]; + wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; - stopIfChanged = false; + stopIfChanged = false; - path = [ pkgs.openssh pkgs.gawk ]; + path = [ pkgs.openssh pkgs.gawk ]; - environment.LD_LIBRARY_PATH = nssModulesPath; + environment.LD_LIBRARY_PATH = nssModulesPath; - preStart = - '' - mkdir -m 0755 -p /etc/ssh + preStart = + '' + mkdir -m 0755 -p /etc/ssh - ${flip concatMapStrings cfg.hostKeys (k: '' - if ! [ -f "${k.path}" ]; then - ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" - fi - '')} - ''; + ${flip concatMapStrings cfg.hostKeys (k: '' + if ! [ -f "${k.path}" ]; then + ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" + fi + '')} + ''; - serviceConfig = - { ExecStart = - "${pkgs.openssh}/sbin/sshd " + - "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; - Restart = "always"; - Type = "forking"; - KillMode = "process"; - PIDFile = "/run/sshd.pid"; + serviceConfig = + { ExecStart = + "${pkgs.openssh}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; + KillMode = "process"; + } // (if cfg.startWhenNeeded then { + StandardInput = "socket"; + } else { + Restart = "always"; + Type = "forking"; + PIDFile = "/run/sshd.pid"; + }); }; + in + + if cfg.startWhenNeeded then { + + sockets.sshd = + { description = "SSH Socket"; + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = cfg.ports; + socketConfig.Accept = true; + }; + + services."sshd@" = service; + + } else { + + services.sshd = service; + }; networking.firewall.allowedTCPPorts = cfg.ports; diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index 195a8056bf8..b81f97f2b4e 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -12,6 +12,9 @@ with lib; networking.useHostResolvConf = true; + # Containers should be light-weight, so start sshd on demand. + services.openssh.startWhenNeeded = mkDefault true; + # Shut up warnings about not having a boot loader. system.build.installBootLoader = "${pkgs.coreutils}/bin/true";