Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/src/machines.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,54 @@ getcap $(which sunshine)
# Should show: cap_sys_admin=p
```

## ComfyUI Image Generation (personal-dell)

`personal-dell` runs [ComfyUI](https://github.com/comfyanonymous/ComfyUI), a node-based Stable Diffusion (SDXL) web UI for creating and modifying digital paintings on the GPU. Enabled via `services.comfyui.enable = true` and accessible at:

- **Web UI**: `https://atorgesen-dell.local/comfyui/` (also linked from the services landing page as "ComfyUI")

The service runs in `--lowvram` mode because the RTX 500 Ada has only ~3.7 GB of usable VRAM. SDXL-Turbo / SDXL-Lightning checkpoints are recommended for usable speed; full SDXL base works but is slow.

### Adding Models (manual step — required before first use)

Model checkpoints are **not** packaged in Nix (they are large and user-managed). They live under the service's data directory and must be downloaded manually into the `checkpoints` subfolder:

```bash
mkdir -p /data/andrew/comfyui/models/checkpoints
cd /data/andrew/comfyui/models/checkpoints

# Example: SDXL-Turbo (~6.9 GB), a good fit for low-VRAM
curl -fL -C - -o sd_xl_turbo_1.0_fp16.safetensors \
"https://huggingface.co/stabilityai/sdxl-turbo/resolve/main/sd_xl_turbo_1.0_fp16.safetensors"
```

ComfyUI rescans the `checkpoints` folder automatically (no service restart needed) — the new model appears in the `Load Checkpoint` node after a page refresh. Other model types go in sibling folders (`models/loras/`, `models/vae/`, `models/controlnet/`, etc.).

### Creating and Modifying Paintings

- **Create**: in the web UI, build (or load) a text→image graph — `Load Checkpoint` → `CLIP Text Encode` (positive/negative) → `KSampler` → `VAE Decode` → `Save Image`. For SDXL-Turbo use `cfg ≈ 1.0`, `steps 1–4`, sampler `euler_ancestral`. Generated images are written to `/data/andrew/comfyui/output/`.
- **Modify**: drop an existing painting into `/data/andrew/comfyui/input/`, then run an img2img or inpaint graph (`Load Image` → `VAE Encode` → `KSampler` with reduced `denoise`).

### Architecture

- **Service**: `comfyui.service` (systemd, user `andrew:dev`), internal port 8188 (centrally managed in `service-ports.nix`)
- **Nginx proxy**: `/comfyui/` → `http://127.0.0.1:8188` (ComfyUI uses relative asset paths, so the subpath works without a dedicated vhost). The location forwards the raw request path (from `$request_uri`, prefix stripped) plus the query string via custom variables, rather than a normal prefix-stripping `proxy_pass`. This preserves the `%2F`-encoded slashes in ComfyUI's `/userdata/{file}` API (e.g. saving `workflows/foo.json`) — a prefix-stripping proxy decodes them and breaks saves with HTTP 405. The path and query are split (`$path?$query`) rather than passing `$request_uri` whole, so the `?` is not percent-encoded into the filename, and `$args` is avoided so the config passes the `gixy` SSRF lint.
- **Data directory**: `/data/andrew/comfyui/` — `models/`, `input/`, `output/`, `custom_nodes/`, `user/` (created automatically via `systemd.tmpfiles`)
- **Asset database**: `/data/andrew/comfyui/user/comfyui.db` (SQLite) — set explicitly with `--database-url` because ComfyUI's default DB path is relative to the read-only Nix store
- **Version**: pinned to ComfyUI **v0.11.0**, the newest release predating the `comfy-aimdo` dependency (a compiled native wheel that does not package cleanly under Nix on Python 3.13). The three frontend asset packages (`comfyui-frontend-package`, `comfyui-workflow-templates`, `comfyui-embedded-docs`) and `spandrel` are packaged in `anixpkgs`.

### Troubleshooting

**Service not running / crash-looping:**
```bash
systemctl status comfyui
journalctl -u comfyui -n 50
```

**Model not showing up:** Confirm the file is in `/data/andrew/comfyui/models/checkpoints/` and refresh the browser. A `comfy_kitchen` import warning in the logs is expected and harmless (fp8/fp4 quantization is disabled; not needed for SDXL).

**Out-of-memory during generation:** Lower the resolution (SDXL-Turbo was trained at 512×512) or batch size; the service already runs `--lowvram`.

## Miscellaneous

### Cloud Syncing
Expand Down
35 changes: 35 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
easy-google-auth.url = "github:goromal/easy-google-auth";
easy-google-auth.flake = false;

spandrel-src.url = "github:chaiNNer-org/spandrel";
spandrel-src.flake = false;

comfyui-src.url = "github:comfyanonymous/ComfyUI?ref=refs/tags/v0.11.0";
comfyui-src.flake = false;

evil-hangman.url = "github:goromal/evil-hangman";
evil-hangman.flake = false;

Expand Down
50 changes: 50 additions & 0 deletions index.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,56 @@
"attr": "vdlserver",
"ci": true,
"docs": false
},
{
"attr": "spandrel",
"ci": true,
"docs": false
},
{
"attr": "comfyui-frontend-package",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates-core",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates-media-api",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates-media-video",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates-media-image",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates-media-other",
"ci": true,
"docs": false
},
{
"attr": "comfyui-workflow-templates",
"ci": true,
"docs": false
},
{
"attr": "comfyui-embedded-docs",
"ci": true,
"docs": false
},
{
"attr": "comfyui",
"ci": true,
"docs": false
}
],
"bash": [
Expand Down
59 changes: 59 additions & 0 deletions pkgs/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,27 @@ let
pkg-src = flakeInputs.jetson-stats;
}
);
spandrel = pySelf.callPackage ./python-packages/spandrel {
pkg-src = flakeInputs.spandrel-src;
};
comfyui-frontend-package = pySelf.callPackage ./python-packages/comfyui-frontend-package { };
comfyui-workflow-templates-core =
pySelf.callPackage ./python-packages/comfyui-workflow-templates-core
{ };
comfyui-workflow-templates-media-api =
pySelf.callPackage ./python-packages/comfyui-workflow-templates-media-api
{ };
comfyui-workflow-templates-media-video =
pySelf.callPackage ./python-packages/comfyui-workflow-templates-media-video
{ };
comfyui-workflow-templates-media-image =
pySelf.callPackage ./python-packages/comfyui-workflow-templates-media-image
{ };
comfyui-workflow-templates-media-other =
pySelf.callPackage ./python-packages/comfyui-workflow-templates-media-other
{ };
comfyui-workflow-templates = pySelf.callPackage ./python-packages/comfyui-workflow-templates { };
comfyui-embedded-docs = pySelf.callPackage ./python-packages/comfyui-embedded-docs { };
jupyter-mimetypes = pySelf.callPackage ./python-packages/jupyter-mimetypes { };
jupyter-kernel-client = pySelf.callPackage ./python-packages/jupyter-kernel-client { };
jupyter-server-client = pySelf.callPackage ./python-packages/jupyter-server-client { };
Expand Down Expand Up @@ -414,6 +435,44 @@ rec {
book-notes-sync = final.python313.pkgs.book-notes-sync;
gmail-parser = final.python313.pkgs.gmail-parser;
jetson-stats = final.python313.pkgs.jetson-stats;
spandrel = final.python313.pkgs.spandrel;
comfyui =
let
py = final.python313;
pyPkgs = py.pkgs;
in
prev.callPackage ./python-packages/comfyui {
python313 = py;
torch = pyPkgs.torch;
torchsde = pyPkgs.torchsde;
torchvision = pyPkgs.torchvision;
torchaudio = pyPkgs.torchaudio;
numpy = pyPkgs.numpy;
einops = pyPkgs.einops;
transformers = pyPkgs.transformers;
tokenizers = pyPkgs.tokenizers;
sentencepiece = pyPkgs.sentencepiece;
safetensors = pyPkgs.safetensors;
aiohttp = pyPkgs.aiohttp;
yarl = pyPkgs.yarl;
pyyaml = pyPkgs.pyyaml;
pillow = pyPkgs.pillow;
scipy = pyPkgs.scipy;
tqdm = pyPkgs.tqdm;
psutil = pyPkgs.psutil;
alembic = pyPkgs.alembic;
sqlalchemy = pyPkgs.sqlalchemy;
requests = pyPkgs.requests;
pydantic = pyPkgs.pydantic;
pydantic-settings = pyPkgs.pydantic-settings;
kornia = pyPkgs.kornia;
spandrel = pyPkgs.spandrel;
av = pyPkgs.av;
comfyui-frontend-package = pyPkgs.comfyui-frontend-package;
comfyui-workflow-templates = pyPkgs.comfyui-workflow-templates;
comfyui-embedded-docs = pyPkgs.comfyui-embedded-docs;
pkg-src = flakeInputs.comfyui-src;
};
jupyter-mcp-server = final.python313.pkgs.jupyter-mcp-server;
goromail = final.python313.pkgs.goromail;
orchestrator = final.python313.pkgs.orchestrator;
Expand Down
1 change: 1 addition & 0 deletions pkgs/nixos/configurations/personal-dell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
machines.base.wifiInterfaceName = "wlp0s13f0u1u4";
machines.base.acceptRemoteBuilds = true;
machines.cudaNode.enable = true;
services.comfyui.enable = true;
machines.base.timedOrchJobs = [
{
name = "launchpad-sync";
Expand Down
99 changes: 99 additions & 0 deletions pkgs/nixos/modules/comfyui/module.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
pkgs,
config,
lib,
...
}:
let
service-ports = import ../../service-ports.nix;
cfg = config.services.comfyui;
extendedPkgs = pkgs.extend (import ../../../../overlay.nix);
in
{
options.services.comfyui = {
enable = lib.mkEnableOption "ComfyUI Stable Diffusion server";
port = lib.mkOption {
type = lib.types.port;
default = service-ports.comfyui;
};
dataDir = lib.mkOption {
type = lib.types.str;
default = "/data/andrew/comfyui";
};
package = lib.mkOption {
type = lib.types.package;
default = extendedPkgs.comfyui;
};
};

config = lib.mkIf cfg.enable {
machines.base.runWebServer = true;

machines.base.webServices = [
{
name = "ComfyUI";
path = "/comfyui/";
description = "Stable Diffusion (SDXL) image generation";
icon = "film";
}
];

services.nginx.virtualHosts."${config.networking.hostName}.local" = {
locations."/comfyui/" = {
extraConfig = ''
client_max_body_size 100m;
set $comfyui_path $request_uri;
set $comfyui_query "";
if ($comfyui_path ~ "^/comfyui(/[^?]*)\?(.*)$") {
set $comfyui_path $1;
set $comfyui_query $2;
}
if ($comfyui_path ~ "^/comfyui(/[^?]*)$") {
set $comfyui_path $1;
}
proxy_pass http://127.0.0.1:${builtins.toString cfg.port}$comfyui_path?$comfyui_query;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
};
};

systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0755 andrew dev -"
"d ${cfg.dataDir}/models 0755 andrew dev -"
"d ${cfg.dataDir}/input 0755 andrew dev -"
"d ${cfg.dataDir}/output 0755 andrew dev -"
"d ${cfg.dataDir}/custom_nodes 0755 andrew dev -"
];

systemd.services.comfyui = {
enable = true;
description = "ComfyUI Stable Diffusion Server";
unitConfig.StartLimitIntervalSec = 0;
serviceConfig = {
Type = "simple";
ExecStart = "${cfg.package}/bin/comfyui --listen 127.0.0.1 --port ${builtins.toString cfg.port} --base-directory ${cfg.dataDir} --database-url sqlite:///${cfg.dataDir}/user/comfyui.db --lowvram";
ReadWritePaths = [
cfg.dataDir
"/tmp"
];
WorkingDirectory = cfg.dataDir;
Restart = "always";
RestartSec = 5;
User = "andrew";
Group = "dev";
Environment = [
"HOME=/data/andrew"
];
};
wantedBy = [ "multi-user.target" ];
};

networking.firewall.allowedTCPPorts = [ cfg.port ];
};
}
1 change: 1 addition & 0 deletions pkgs/nixos/pc-base.nix
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ in
./modules/claude-agent/module.nix
./modules/webserverNode/module.nix
./modules/cudaNode/module.nix
./modules/comfyui/module.nix
../modules/notes-wiki/module.nix
../modules/metricsNode/module.nix
../modules/plexNode/module.nix
Expand Down
1 change: 1 addition & 0 deletions pkgs/nixos/service-ports.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
la-quiz-web = 5656;
tester = 5757;
launchpad = 8888;
comfyui = 8188;
anix_upgrade_ui = 5858;
tasks_ui = 5959;
videodl = 6060;
Expand Down
Loading
Loading