1
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-06-19 07:59:24 +03:00
nixpkgs/nixos/modules/services/web-servers/ttyd.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

286 lines
7.1 KiB
Nix
Raw Permalink Normal View History

2019-09-12 18:47:15 +01:00
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.ttyd;
2024-01-31 17:58:59 +01:00
inherit (lib)
optionals
types
mkOption
;
2019-09-12 18:47:15 +01:00
# Command line arguments for the ttyd daemon
args =
[
"--port"
(toString cfg.port)
]
++ optionals (cfg.socket != null) [
"--interface"
cfg.socket
]
++ optionals (cfg.interface != null) [
"--interface"
cfg.interface
]
++ [
"--signal"
(toString cfg.signal)
2024-09-08 19:00:53 +02:00
]
++ (lib.concatLists (
lib.mapAttrsToList (_k: _v: [
"--client-option"
"${_k}=${_v}"
]) cfg.clientOptions
))
2019-09-12 18:47:15 +01:00
++ [
"--terminal-type"
cfg.terminalType
]
++ optionals cfg.checkOrigin [ "--check-origin" ]
++ optionals cfg.writeable [ "--writable" ] # the typo is correct
2019-09-12 18:47:15 +01:00
++ [
"--max-clients"
(toString cfg.maxClients)
]
++ optionals (cfg.indexFile != null) [
"--index"
cfg.indexFile
]
2019-09-12 18:47:15 +01:00
++ optionals cfg.enableIPv6 [ "--ipv6" ]
++ optionals cfg.enableSSL [
"--ssl"
"--ssl-cert"
cfg.certFile
"--ssl-key"
cfg.keyFile
]
++ optionals (cfg.enableSSL && cfg.caFile != null) [
"--ssl-ca"
cfg.caFile
]
2019-09-12 18:47:15 +01:00
++ [
"--debug"
(toString cfg.logLevel)
];
in
{
###### interface
options = {
services.ttyd = {
2024-01-31 17:58:59 +01:00
enable = lib.mkEnableOption ("ttyd daemon");
2019-09-12 18:47:15 +01:00
port = mkOption {
2021-06-18 17:28:17 +02:00
type = types.port;
2019-09-12 18:47:15 +01:00
default = 7681;
2024-01-31 17:58:59 +01:00
description = "Port to listen on (use 0 for random port)";
2019-09-12 18:47:15 +01:00
};
socket = mkOption {
type = types.nullOr types.path;
default = null;
example = "/var/run/ttyd.sock";
2024-01-31 17:58:59 +01:00
description = "UNIX domain socket path to bind.";
2019-09-12 18:47:15 +01:00
};
interface = mkOption {
type = types.nullOr types.str;
default = null;
example = "eth0";
2024-01-31 17:58:59 +01:00
description = "Network interface to bind.";
2019-09-12 18:47:15 +01:00
};
username = mkOption {
type = types.nullOr types.str;
default = null;
2024-01-31 17:59:39 +01:00
description = "Username for basic http authentication.";
2019-09-12 18:47:15 +01:00
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
apply = value: if value == null then null else toString value;
2024-01-31 17:58:59 +01:00
description = ''
2024-01-31 17:59:39 +01:00
File containing the password to use for basic http authentication.
2019-09-12 18:47:15 +01:00
For insecurely putting the password in the globally readable store use
`pkgs.writeText "ttydpw" "MyPassword"`.
'';
};
signal = mkOption {
type = types.ints.u8;
default = 1;
2024-01-31 17:58:59 +01:00
description = "Signal to send to the command on session close.";
2019-09-12 18:47:15 +01:00
};
2024-01-31 17:59:39 +01:00
entrypoint = mkOption {
type = types.listOf types.str;
default = [ "${pkgs.shadow}/bin/login" ];
defaultText = lib.literalExpression ''
[ "''${pkgs.shadow}/bin/login" ]
'';
example = lib.literalExpression ''
[ (lib.getExe pkgs.htop) ]
'';
description = "Which command ttyd runs.";
apply = lib.escapeShellArgs;
};
user = mkOption {
type = types.str;
# `login` needs to be run as root
default = "root";
description = "Which unix user ttyd should run as.";
};
writeable = mkOption {
type = types.nullOr types.bool;
default = null; # null causes an eval error, forcing the user to consider attack surface
example = true;
2024-01-31 17:58:59 +01:00
description = "Allow clients to write to the TTY.";
};
2019-09-12 18:47:15 +01:00
clientOptions = mkOption {
type = types.attrsOf types.str;
default = { };
2024-01-31 17:58:59 +01:00
example = lib.literalExpression ''
2023-06-30 18:14:37 +02:00
{
fontSize = "16";
fontFamily = "Fira Code";
}
'';
2024-01-31 17:58:59 +01:00
description = ''
2019-09-12 18:47:15 +01:00
Attribute set of client options for xtermjs.
<https://xtermjs.org/docs/api/terminal/interfaces/iterminaloptions/>
'';
};
terminalType = mkOption {
type = types.str;
default = "xterm-256color";
2024-01-31 17:58:59 +01:00
description = "Terminal type to report.";
2019-09-12 18:47:15 +01:00
};
checkOrigin = mkOption {
type = types.bool;
default = false;
2024-01-31 17:58:59 +01:00
description = "Whether to allow a websocket connection from a different origin.";
2019-09-12 18:47:15 +01:00
};
maxClients = mkOption {
type = types.int;
default = 0;
2024-01-31 17:58:59 +01:00
description = "Maximum clients to support (0, no limit)";
2019-09-12 18:47:15 +01:00
};
indexFile = mkOption {
type = types.nullOr types.path;
default = null;
2024-01-31 17:58:59 +01:00
description = "Custom index.html path";
2019-09-12 18:47:15 +01:00
};
enableIPv6 = mkOption {
type = types.bool;
default = false;
2024-01-31 17:58:59 +01:00
description = "Whether or not to enable IPv6 support.";
2019-09-12 18:47:15 +01:00
};
enableSSL = mkOption {
type = types.bool;
default = false;
2024-01-31 17:58:59 +01:00
description = "Whether or not to enable SSL (https) support.";
2019-09-12 18:47:15 +01:00
};
certFile = mkOption {
type = types.nullOr types.path;
default = null;
2024-01-31 17:58:59 +01:00
description = "SSL certificate file path.";
2019-09-12 18:47:15 +01:00
};
keyFile = mkOption {
type = types.nullOr types.path;
default = null;
apply = value: if value == null then null else toString value;
2024-01-31 17:58:59 +01:00
description = ''
2019-09-12 18:47:15 +01:00
SSL key file path.
For insecurely putting the keyFile in the globally readable store use
`pkgs.writeText "ttydKeyFile" "SSLKEY"`.
'';
};
caFile = mkOption {
type = types.nullOr types.path;
default = null;
2024-01-31 17:58:59 +01:00
description = "SSL CA file path for client certificate verification.";
2019-09-12 18:47:15 +01:00
};
logLevel = mkOption {
type = types.int;
default = 7;
2024-01-31 17:58:59 +01:00
description = "Set log level.";
2019-09-12 18:47:15 +01:00
};
};
};
###### implementation
2024-01-31 17:58:59 +01:00
config = lib.mkIf cfg.enable {
2019-09-12 18:47:15 +01:00
assertions = [
{
assertion = cfg.enableSSL -> cfg.certFile != null && cfg.keyFile != null;
message = "SSL is enabled for ttyd, but no certFile or keyFile has been specified.";
}
{
assertion = cfg.writeable != null;
message = "services.ttyd.writeable must be set";
}
2019-09-12 18:47:15 +01:00
{
assertion = !(cfg.interface != null && cfg.socket != null);
message = "Cannot set both interface and socket for ttyd.";
}
{
assertion = (cfg.username != null) == (cfg.passwordFile != null);
message = "Need to set both username and passwordFile for ttyd";
}
];
systemd.services.ttyd = {
description = "ttyd Web Server Daemon";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
2024-01-31 17:59:39 +01:00
User = cfg.user;
LoadCredential = lib.optionalString (
cfg.passwordFile != null
) "TTYD_PASSWORD_FILE:${cfg.passwordFile}";
2019-09-12 18:47:15 +01:00
};
2019-09-12 18:47:15 +01:00
script =
if cfg.passwordFile != null then
''
PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/TTYD_PASSWORD_FILE")
2019-09-12 18:47:15 +01:00
${pkgs.ttyd}/bin/ttyd ${lib.escapeShellArgs args} \
2024-01-31 17:58:59 +01:00
--credential ${lib.escapeShellArg cfg.username}:"$PASSWORD" \
2024-01-31 17:59:39 +01:00
${cfg.entrypoint}
2019-09-12 18:47:15 +01:00
''
else
''
2019-09-12 18:47:15 +01:00
${pkgs.ttyd}/bin/ttyd ${lib.escapeShellArgs args} \
2024-01-31 17:59:39 +01:00
${cfg.entrypoint}
2019-09-12 18:47:15 +01:00
'';
};
};
}