在游戏 PC 上使用 NixOS WSL 运行 Nvidia 加速的 Ollama,实现 24/7 全天候可用

Nvidia on Nixos WSL - Ollama up 24/7 on your gaming PC

Posted Apr 1, 2025 Updated Apr 1, 2025 By _yomaq _ 9 min read

在家方便地使用 LLM

我一直想在我的家庭实验室里尝试使用 LLM,但又不想为了专门的 GPU 机器而增加开销,或者忍受 CPU 处理的缓慢。我还希望一切都能长期方便使用:更新需要自动化,如果操作系统崩溃,重建需要快速而简单等等。

在我的游戏 PC 上使用 WSL 运行 NixOS 似乎是完美的解决方案,但我不断遇到几个挑战:

经过几个星期的摸索,我现在解决了这些障碍:

虽然这里有一些通用的有用信息,但它主要关注 NixOS。此外,我非常依赖 Tailscale 来方便我的网络,因此也包含了一些可选的 Tailscale 步骤。

我在家积极使用的实时配置:

仅供参考

强制 WSL 保持运行

首先,要解决最大的、与操作系统无关的问题,我找到了这个 github 帖子。假设你在 WSL 上运行 Ubuntu,你可以运行

1

```
| ```
wsl --exec dbus-launch true

```
  
---|---  
`

这将启动 WSL 并使其保持运行。你可以在 Windows 任务计划程序中设置一个基本任务,以在“启动时”自动运行此命令,并将其设置为在用户注销后运行。

对于 WSL 上的 NixOS,我发现这不太有效,`--exec` 选项似乎存在问题。所以我改为这样设置:

1

| ```
wsl.exe dbus-launch true

---|---
`

我相信对于 NixOS,这意味着一个 shell 会在后台运行,这不如为 Ubuntu 使用 --exec 理想,但我会接受我能得到的东西。

在 WSL 上安装 NixOS

我对长期便利性的大部分要求都由 NixOS 满足。通过 NixOS 配置来配置整个系统(Nvidia、网络、容器等),可以轻松地重新部署所有内容。此外,我的 NixOS Flake 已经设置为通过 github action 进行自动每周更新,并且我所有的 NixOS 主机都配置为自动拉取并完全重建到这些更新。我的 WSL 上的 NixOS 将能够继承这些优势。

或者,如果你愿意,还有其他方法可以为你的单个 WSL 设置自动更新一次性的 NixOS 机器。

要开始安装,请按照 Nixos-WSL github 中的步骤操作:

  1. 如果尚未启用 WSL,请启用:
1

```
| ```
wsl--install--no-distribution
```
  
---|---  
`

2.  从[最新版本](https://yomaq.github.io/posts/nvidia-on-nixos-wsl-ollama-up-24-7-on-your-gaming-pc/<https:/github.com/nix-community/NixOS-WSL/releases/latest>)下载 `nixos.wsl`。
3.  双击刚刚下载的文件(需要 WSL >= 2.4.4)
4.  你现在可以运行 NixOS:

1

| ```
wsl-dNixOS

---|---
`

然后将其设置为默认值

1

```
| ```
wsl --setdefault NixOS

```
  
---|---  
`

### 基本 NixOS 配置

要配置 NixOS,请输入 WSL 并导航到 `/etc/nixos/`。你将找到一个 configuration.nix 文件,其中包含整个系统的配置,它非常简陋,我们将添加一些基本内容以使事情更容易。在第一次重建完成之前,你需要使用 Nano 编辑该文件。(我正在使用 Tailscale 进行网络连接,我推荐它,但这不是必需的。)

1 2 3 4 5 6 7 8 9

| ```
environment.systemPackages = [
  pkgs.vim
  pkgs.git
  pkgs.tailscale
  pkgs.docker
];
services.tailscale.enable = true;
wsl.useWindowsDriver = true;
nixpkgs.config.allowUnfree = true;

---|---
`

现在运行

1

```
| ```
sudo nix-channel --update

```
  
---|---  
`

和

1

| ```
sudo nixos-rebuild switch

---|---
`

如果你正在使用 Tailscale,请登录 Tailscale,只需按照创建的链接操作即可。

1

```
| ```
sudo tailscale up

```
  
---|---  
`

### 配置 NixOS 以使用 Nvidia Container Toolkit

目前,[Nixos on WSL](https://yomaq.github.io/posts/nvidia-on-nixos-wsl-ollama-up-24-7-on-your-gaming-pc/<https:/github.com/nix-community/NixOS-WSL?tab=readme-ov-file>) 不像标准 NixOS 那样支持 Nvidia 和 Nvidia Container Toolkit,所以我必须进行一些调整才能使其工作。

通过这些修复,Nvidia Container Toolkit 可以正常工作,你可以像预期一样与基本的 Nvidia 命令进行交互(就我所测试的而言,例如 `nvidia-smi`)。但是,依赖 Nvidia 的内置 NixOS 模块(例如 Nixos 的 `services.ollama`)不起作用。可能每个这些服务都需要自己的补丁才能正确连接到 Cuda,而且我不打算处理这些,因为仅使用容器 GPU 工作负载对我来说就足够了。

也就是说,这是使其工作的配置:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

| ```
services.xserver.videoDrivers = ["nvidia"];
hardware.nvidia.open = true;
environment.sessionVariables = {
  CUDA_PATH = "${pkgs.cudatoolkit}";
  EXTRA_LDFLAGS = "-L/lib -L${pkgs.linuxPackages.nvidia_x11}/lib";
  EXTRA_CCFLAGS = "-I/usr/include";
  LD_LIBRARY_PATH = [
    "/usr/lib/wsl/lib"
    "${pkgs.linuxPackages.nvidia_x11}/lib"
    "${pkgs.ncurses5}/lib"
];
  MESA_D3D12_DEFAULT_ADAPTER_NAME = "Nvidia";
};
hardware.nvidia-container-toolkit = {
  enable = true;
  mount-nvidia-executables = false;
};
systemd.services = {
  nvidia-cdi-generator = {
    description = "Generate nvidia cdi";
    wantedBy = [ "docker.service" ];
    serviceConfig = {
    Type = "oneshot";
    ExecStart = "${pkgs.nvidia-docker}/bin/nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml --nvidia-ctk-path=${pkgs.nvidia-container-toolkit}/bin/nvidia-ctk";
    };
  };
};
virtualisation.docker = {
  daemon.settings.features.cdi = true;
  daemon.settings.cdi-spec-dirs = ["/etc/cdi"];
};

---|---
`

再进行一次 nixos-rebuild switch 并重新启动 WSL。现在你应该能够运行 nvidia-smi 并看到你的 GPU。你需要使用 --device=nvidia.com/gpu=all 运行所有 docker 容器以连接到 GPU。

我没有自己发现这些修复,我从这两个 github 问题中整理了这些信息

配置 Ollama Docker 容器:

我设置了一个 Ollama 容器示例,以及一个可选的 Tailscale 容器,以使其更容易联网。如果要使用 Tailscale 容器,请取消注释所有代码,将你的 Tailscale 域名放在适当的位置,并注释掉 Ollama 容器的 portnetworking.firewall 端口。

如果你使用 Tailscale 容器,则已使用 Tailscale Serve 进行设置,以通过签名 https 在 https://ollama.${YOUR_TAILSCALE_DOMAIN}.ts.net 上提供 Ollama API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

```
| ```
virtualisation.oci-containers.backend = "docker";
virtualisation = {
 docker = {
  enable = true;
  autoPrune.enable = true;
 };
};
systemd.tmpfiles.rules = [ 
 "d /var/lib/ollama 0755 root root" 
 #"d /var/lib/tailscale-container 0755 root root"
];
networking.firewall.allowedTCPPorts = [ 11434 ]; 
virtualisation.oci-containers.containers = {
 "ollama" = {
  image = "docker.io/ollama/ollama:latest";
  autoStart = true;
  environment = {
   "OLLAMA_NUM_PARALLEL" = "1";
  };
  ports = [ 11434 ];
  volumes = [ "/var/lib/ollama:/root/.ollama" ];
  extraOptions = [
   "--pull=always"
   "--device=nvidia.com/gpu=all"
   "--network=container:ollama-tailscale"
  ];
 };
 #"ollama-tailscale" = {
 # image = "ghcr.io/tailscale/tailscale:latest";
 # autoStart = true;
 # environment = {
 #  "TS_HOSTNAME" = "ollama";
 #  "TS_STATE_DIR" = "/var/lib/tailscale";
 #  "TS_SERVE_CONFIG" = "config/tailscaleCfg.json";
 # };
 # volumes = [
 #  "/var/lib/tailscale-container:/var/lib"
 #  "/dev/net/tun:/dev/net/tun"
 #  "${
 #  (pkgs.writeTextFile {
 #   name = "ollamaTScfg";
 #   text = ''
 #    {
 #     "TCP": {
 #      "443": {
 #       "HTTPS": true
 #      }
 #     },
 #     "Web": {
 #      #replace this with YOUR tailscale domain 
 #      "ollama.${YOUR_TAILSCALE_DOMAIN}.ts.net:443": {
 #       "Handlers": {
 #        "/": {
 #         "Proxy": "http://127.0.0.1:11434"
 #        }
 #       }
 #      }
 #     }
 #    }
 #   '';
 #  })
 #  }:/config/tailscaleCfg.json"
 # ];
 # extraOptions = [
 #  "--pull=always"
 #  "--cap-add=net_admin"
 #  "--cap-add=sys_module"
 #  "--device=/dev/net/tun:/dev/net/tun"
 # ];
 #};
};

```
  
---|---  
`

再进行一次 `nixos-rebuild switch`,你的 Ollama 容器应该已启动。

### 网络和测试

如果使用 Tailscale:

*   需要先设置 Tailscale 容器,否则两个容器将继续失败。
*   执行到 Tailscale 容器中:`sudo docker exec -it ollama-tailscale sh`
*   `tailscale up`
*   使用链接将其添加到你的 Tailnet
*   执行到 Ollama 容器中以拉取模型:`sudo docker exec -it ollama ollama run gemma3`
*   运行测试提示,在 WSL 上使用 `nvidia-smi` 进行验证以查看 GPU 是否正在使用。
*   从另一个 Tailscale 连接的设备测试 API:

1 2 3 4 5

| ```
curl https://ollama.${YOUR_TAILSCALE_DOMAIN}.ts.net/api/generate -d '{
 "model": "gemma3",
 "prompt": "test",
 "stream": false
}'

---|---
`

如果不使用 Tailscale:

1
2

```
| ```
"OLLAMA_HOST" = "0.0.0.0:11434";
"OLLAMA_ORIGINS" = "*";

```
  
---|---  
`

到 NixOS 配置的 Ollama 环境。

*   使用 `ifconfig` 获取你的 WSL IP 地址,通常在 eth0 下
*   在 Windows 上,使用具有管理员权限的 Powershell 创建防火墙规则:

1 2 3

| ```
New-NetFireWallRule -DisplayName 'WSL firewall unlock' -Direction Outbound -LocalPort 11434 -Action Allow -Protocol TCP
New-NetFireWallRule -DisplayName 'WSL firewall unlock' -Direction Inbound -LocalPort 11434 -Action Allow -Protocol TCP

---|---
`

1

```
| ```
netsh interface portproxy add v4tov4 listenport=11434 listenaddress=0.0.0.0 connectport=11434 connectaddress=$WSL-IP-ADDRESS

```
  
---|---  
`

请务必替换 $WSL-IP-ADDRESS

*   现在使用你的 Windows LAN IP 地址,你应该能够访问 Ollama:`http://192.168.1.123:11434`
*   使用你的 Windows LAN IP 地址测试 API。

1 2 3 4 5

| ```
curl http://WINDOWS-LAN-IP:11434api/generate -d '{
 "model": "gemma3",
 "prompt": "test",
 "stream": false
}'

---|---
`

完成!

现在你可以将你的 Ollama API 连接到你想要的任何地方,例如 Open-WebUI 等。

Homelab, Nixos nixos wsl tailscale This post is licensed under CC BY 4.0 by the author. Share