# heather — JupyterLab (systemd, не контейнер). # # Среда собирается uv'ом в /var/lib/jupyter-env (venv с jupyterlab + LSP + # SQL + темы). Устанавливается однократно вручную (nix run nixpkgs#uv), сама # установка не в nix store — пакеты летят из PyPI, пинить нечего. # # Безопасность: слушает только 127.0.0.1:8890, наружу через Caddy # (jupyter.iscg.dev). Caddy basicauth (см. caddy.nix jupyterBasicAuth) + # Jupyter token (пасс iscg.dev/jupyter/token, env-файл jupyter-secrets). # # Лимиты: MemoryMax 2G, CPUQuota 50% — ноутбук не сможет съесть сервер. { config, pkgs, lib, ... }: let jupyterEnv = "/home/mikl/.local/share/uv/tools/jupyterlab"; jupyterBin = "${jupyterEnv}/bin/jupyter-lab"; in { # JupyterLab управляет собственным env-файлом? нет — используем # EnvironmentFile с токеном: /var/lib/jupyter-secrets/jupyter.env # (JUPYTER_TOKEN=..., mikl:users 0600) systemd.services.jupyterlab = { description = "JupyterLab notebook server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = with pkgs; [ bash ]; environment = { HOME = "/home/mikl"; PATH = lib.mkForce "${jupyterEnv}/bin:/run/current-system/sw/bin"; }; serviceConfig = { Type = "simple"; User = "mikl"; Group = "users"; EnvironmentFile = "/var/lib/jupyter-secrets/jupyter.env"; ExecStart = '' ${jupyterBin} \ --no-browser \ --ip=127.0.0.1 \ --port=8890 \ --ServerApp.token="$JUPYTER_TOKEN" \ --ServerApp.root_dir=/srv/jupyter \ --ServerApp.password_required=True ''; Restart = "on-failure"; RestartSec = 5; # --- лимиты ресурсов --- MemoryMax = "2G"; MemoryHigh = "1536M"; CPUQuota = "50%"; TasksMax = 256; # --- sandbox (лёгкий, т.к. ноутбукам нужен доступ к ~/srv) --- NoNewPrivileges = true; PrivateTmp = true; ProtectSystem = "full"; ReadWritePaths = [ "/srv/jupyter" "/home/mikl" ]; }; }; # Каталог ноутбуков и env-директория systemd.tmpfiles.rules = [ "d /srv/jupyter 0755 mikl users -" "d /var/lib/jupyter-secrets 0750 mikl users -" "d /var/lib/jupyter-env 0755 mikl users -" ]; }