From 3394242bcc399890527238b0b48398e3a18e2d01 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 18 Sep 2023 13:59:48 +0200 Subject: [PATCH] Add jupyter --- hosts/voyager/configuration.nix | 3 +- hosts/voyager/services/jupyter.nix | 103 +++++++++++++++++++++++++++++ secrets/voyager/voyager.yaml | 6 +- 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 hosts/voyager/services/jupyter.nix diff --git a/hosts/voyager/configuration.nix b/hosts/voyager/configuration.nix index 3616daf..c6a9095 100644 --- a/hosts/voyager/configuration.nix +++ b/hosts/voyager/configuration.nix @@ -26,7 +26,8 @@ ./services/vaultwarden.nix ./services/calibre.nix ./services/fancontrol.nix - ./services/searx.nix + ./services/jupyter.nix + # ./services/searx.nix # ./services/code-server.nix ]; diff --git a/hosts/voyager/services/jupyter.nix b/hosts/voyager/services/jupyter.nix new file mode 100644 index 0000000..f94437e --- /dev/null +++ b/hosts/voyager/services/jupyter.nix @@ -0,0 +1,103 @@ +{ config, pkgs, lib, ... }: let + cfg = config.services.jupyter; +in { + sops.secrets."jupyter/password" = { + restartUnits = [ "jupyter.service" ]; + owner = cfg.user; + group = cfg.group; + }; + + users.users."jupyter".group = "jupyter"; + users.groups."jupyter".members = [ "nginx" ]; + + services.jupyter = { + enable = true; + group = "jupyter"; + password = let + readFile = f: "open('${f}', 'r', encoding='utf8').read().strip()"; + in + readFile config.sops.secrets."jupyter/password".path; + + kernels = { + pythonDS = let + env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [ + numpy + matplotlib + scipy + ipykernel + ])); + in { + displayName = "Python for data science"; + argv = [ + "${env.interpreter}" + "-m" + "ipykernel_launcher" + "-f" + "{connection_file}" + ]; + language = "python"; + logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png"; + logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png"; + }; + }; + }; + + systemd.services.jupyter = let + notebookConfig = pkgs.writeText "jupyter_config.py" '' + c.NotebookApp.notebook_dir = 'notebooks' + c.NotebookApp.open_browser = False + c.NotebookApp.password = ${cfg.password} + c.NotebookApp.password_required = True + + c.NotebookApp.sock = '/run/jupyter/jupyter.sock' + c.NotebookApp.sock_mode = '0660' + c.NotebookApp.local_hostnames = ['jupyter.feal.no'] + + c.ConnectionFileMixin.transport = 'ipc' + + ${cfg.notebookConfig} + ''; + in { + environment = { + JUPYTER_DATA_DIR = "$STATE_DIRECTORY/data"; + JUPYTER_RUNTIME_DIR = "$RUNTIME_DIRECTORY"; + }; + serviceConfig = { + RuntimeDirectory = "jupyter"; + StateDirectory = "jupyter"; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictSUIDSGID = true; + UMask = "0007"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + SystemCallArchitectures = "native"; + + ExecStartPre = '' + ${pkgs.coreutils}/bin/mkdir -p /var/lib/jupyter/{notebooks,data} + ''; + ExecStart = lib.mkForce '' + ${cfg.package}/bin/${cfg.command} --NotebookApp.config_file=${notebookConfig} + ''; + }; + }; + + services.nginx.virtualHosts."jupyter.feal.no" = { + locations."/".proxyPass = "http://unix:/run/jupyter/jupyter.sock:/"; + }; +} diff --git a/secrets/voyager/voyager.yaml b/secrets/voyager/voyager.yaml index ea7944c..2c6595c 100644 --- a/secrets/voyager/voyager.yaml +++ b/secrets/voyager/voyager.yaml @@ -23,6 +23,8 @@ wireguard: private: ENC[AES256_GCM,data:XF89i1/TF5CpOvixwFDNOpke0YdWQDAMbvf/jOGR7iHKzz4OJu7K33lQbObT,iv:tVGdkkUU83Ba7VxHa7AJaIHFETp2Dy72dya3FDjnPZY=,tag:h9IJVeGnK7gABbu9hWZpww==,type:str] vaultwarden: admintoken: ENC[AES256_GCM,data:mJDiu0tgJQmvmJcJMULmctJvPN6/uM9VaoigHOMFkve9Vd3IMrpDmyJq+ibLpul+hw4PlLARjRzOxdZVcX7AB+uOOOrypppOIfvYC6U=,iv:YcyYLEHeIsCchcEy+fOMiQi8Cgf24AwQDpL7fhogNEU=,tag:1SqpNvuPhfjYIjvvRV34/Q==,type:str] +jupyter: + password: ENC[AES256_GCM,data:eTcjhRphz+2+QAPIPh/H4Dy3SK5bhUVTMkg=,iv:I+fdFG/zNqCj5Wl2H+qJb/eIfjrWmu2fUsxITBMM2N8=,tag:Vim/Fepf/Q67hjUJlXIkbg==,type:str] sops: kms: [] gcp_kms: [] @@ -56,8 +58,8 @@ sops: NENEM2VLRDBzTWM0ckdPVThaeE0xL2MKTAvsDKgaoj0Fz9CoNbP6s1kROlDbbXtB 4rFRGN+WZJrBioz5nN4kR7mVFKa4w6z6Pu3D5WLyK7UQQkZJ64avdw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-08-22T15:28:28Z" - mac: ENC[AES256_GCM,data:Fj4acVrxZJjJTXQAFedzdra3L3rupGbP4SnymkN/vd9dFm0iFNUXF1ZybQGtLFsEBtKZqlNxUMcyGz3/jbWfTDEoItITc+rjHFoWpTDyT81aGGSQFr/NYyGI421stn9x4uZgh2SZZAepYDWb7gLLhw24kvFW3XMV08m6XatUn9I=,iv:g7uQE40u6q373X4hiL8HPlm3rLRU/o1NTrSYcSQVgao=,tag:M0ul7bVOdwZKT4BrhcbEFw==,type:str] + lastmodified: "2023-09-18T11:59:23Z" + mac: ENC[AES256_GCM,data:dTejNchI4iKODArCaotXwVkLmjm+mt0u9KOajj1MBAUQ31p+0r5v3smrOO6ZdlCn4t+F8C8F//pnTw/zr8TSRYFbwMaJtDpPn5Dl/ZNuHmWgEM1JN/1obA6kfGaj5LVM01DhfzD5MGU9s3gSA9SjdRB4I1iT33nuO6xGIXgESn8=,iv:8isU2ZBSKqsmSZMRgebuP17o/tWSiq+nSmN5QyAAwPM=,tag:GVwlBmvvo5s7y3CIvyGi4Q==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3