LM Studio on Windows, WSL2 for Development: The Setup Guide I Wish I Had

작성자

카테고리:

← 피드로
DEV Community · Acel · 2026-08-14 개발(SW)

I went to a Build with Gemma event expecting to spend the day experimenting with local models. Instead, I spent most of the day trying to make a Windows-installed LM Studio talk to code running inside WSL2.

If your development environment also lives in WSL2, this is the setup path I wish I had before the workshop.

The Problem

The workshop instructions were straightforward: install a local model runner, download Gemma, and write a small Python application that talks to the model. The codelab was based on Ollama, which made the Windows-native path look especially simple.

The problem was that my development environment was not on Windows. I use WSL2 for my terminal, Python projects, virtual environments, and Git repositories. LM Studio, however, was installed on the Windows side because that is where the desktop application and model runtime live.

That gives you two environments on one computer:

Windows
└── LM Studio
    └── Gemma model and local HTTP API

WSL2
└── Python application, terminal, files, and virtual environment

Enter fullscreen mode Exit fullscreen mode

The model does not need to be installed twice. The Python application in WSL2 only needs to reach LM Studio’s HTTP API.

That sounds simple. It was not obvious from the workshop instructions, and several different problems looked like the same problem:

  • The LM Studio chat window worked, but the API server was stopped.
  • localhost inside WSL2 was not initially the same as localhost on Windows.
  • I entered Windows WSL configuration into a Linux shell.
  • The workshop used Ollama model names, while LM Studio returned different model identifiers.
  • I spent time investigating a shell plugin that was unrelated to the basic API connection.

The key was separating the layers instead of treating “LM Studio works” as one single test.

My Environment

This was the setup I used:

  • Windows 11, build 26200
  • WSL version 2.7.11.0
  • LM Studio 1.0.7 (build 2)
  • 16 GB RAM
  • Intel UHD Graphics 620
  • WSL2 as the development environment
  • Gemma 4 E2B served by LM Studio

Your versions may differ. LM Studio’s interface changes, so treat the concepts and verification commands as more important than the exact screenshots.

First Important Distinction: Chat Is Not the API

Being able to ask questions in LM Studio’s chat window does not mean that a program can reach the model.

The LM Studio chat window working with Gemma does not prove that the API is running.

The chat interface and the Local Model API server are separate. In my version of LM Studio, the relevant setting was here. LM Studio also documents this server as an OpenAI-compatible API:

Settings -> Local Model API -> Local API server

Enter fullscreen mode Exit fullscreen mode

The switch must be running before a Python program or curl can connect.

You can check the server from Windows PowerShell:

lms server status --json --quiet
curl.exe http://127.0.0.1:1234/v1/models

Enter fullscreen mode Exit fullscreen mode

The curl.exe spelling matters in PowerShell. curl may resolve to PowerShell’s Invoke-WebRequest alias rather than the normal curl executable.

A working response looks like this:

{
  "data": [
    {
      "id": "google/gemma-4-e2b",
      "object": "model",
      "owned_by": "organization_owner"
    }
  ],
  "object": "list"
}

Enter fullscreen mode Exit fullscreen mode

If this Windows-side request fails, do not troubleshoot WSL2 yet. The API server or its port is the problem.

The Setup That Worked

WSL2 commonly starts in NAT networking mode. In that mode, a service running on Windows is not always reachable from Linux through 127.0.0.1. Microsoft’s WSL networking documentation describes the difference between the default NAT and mirrored modes.

Windows 11 supports mirrored networking, which lets WSL2 and Windows reach each other’s localhost services. That was the simplest option for this setup because LM Studio could continue listening on localhost instead of being exposed to the rest of my network.

Step 1: Configure mirrored networking

Open the WSL configuration file from PowerShell, not from Bash:

notepad.exe "$env:USERPROFILE\.wslconfig"

Enter fullscreen mode Exit fullscreen mode

If the file already exists, add the setting under its existing [wsl2] section. Otherwise, create the file with:

[wsl2]
networkingMode=mirrored

Enter fullscreen mode Exit fullscreen mode

Save the file, then restart WSL from PowerShell:

wsl --shutdown

Enter fullscreen mode Exit fullscreen mode

This was one of my mistakes. I initially pasted the [wsl2] lines into the WSL terminal, where Bash tried to execute them as commands. .wslconfig is a Windows file stored at %UserProfile%\.wslconfig.

Step 2: Start the LM Studio API

Open LM Studio and enable the Local API server switch under Settings -> Local Model API.

The default port is usually 1234. If you use another port, replace 1234 in every command and code sample below.

Confirm the server from PowerShell before testing from WSL:

lms server status --json --quiet
curl.exe http://127.0.0.1:1234/v1/models

Enter fullscreen mode Exit fullscreen mode

Step 3: Test from WSL2

Open a new WSL terminal and run:

curl --connect-timeout 5 http://127.0.0.1:1234/v1/models

Enter fullscreen mode Exit fullscreen mode

The response should contain the same model list as the PowerShell request.

At this point, the important test has passed: a program running inside WSL2 can reach a model server running on Windows.

What About NAT Networking?

Mirrored networking is not the only solution.

With the default NAT configuration, WSL2 can reach the Windows host through the gateway address shown by this command:

LM_STUDIO_HOST="$(ip route show default | awk '$1 == "default" {print $3; exit}')"
echo "$LM_STUDIO_HOST"

Enter fullscreen mode Exit fullscreen mode

LM Studio must then listen beyond Windows localhost:

lms server start --port 1234 --bind 0.0.0.0

Enter fullscreen mode Exit fullscreen mode

From WSL2, the request becomes:

curl "http://${LM_STUDIO_HOST}:1234/v1/models"

Enter fullscreen mode Exit fullscreen mode

This approach has two drawbacks:

  1. The WSL2 gateway address can change after a restart.
  2. Binding to 0.0.0.0 exposes the server beyond localhost, so authentication and firewall rules become important.

NAT is still useful when you want stronger network separation or do not want to change the global WSL networking mode. For this single-computer setup, mirrored networking was simpler and allowed LM Studio to remain local-only.

Adapting the Workshop Code

The workshop example uses Ollama. Its Python client and model name assume an Ollama server:

import ollama

response = ollama.chat(
    model="gemma4:e2b",
    messages=[{"role": "user", "content": prompt}],
)

Enter fullscreen mode Exit fullscreen mode

LM Studio provides an OpenAI-compatible API, so the same application can use the OpenAI Python client instead.

Create a small project with uv:

mkdir gemma4-local-app
cd gemma4-local-app
uv init
uv add openai==2.53.0

Enter fullscreen mode Exit fullscreen mode

uv creates and manages the project environment and resolves the Python dependencies. There is no separate virtual-environment setup to maintain.

Create app.py:

import os

from openai import OpenAI


MODEL = os.getenv("LM_STUDIO_MODEL", "google/gemma-4-e2b")
BASE_URL = os.getenv("LM_STUDIO_BASE_URL", "http://127.0.0.1:1234/v1")
API_KEY = os.getenv("LM_STUDIO_API_KEY", "lm-studio")

client = OpenAI(
    base_url=BASE_URL,
    api_key=API_KEY,
)


def ask_model(prompt: str) -> str:
    response = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content or ""


if __name__ == "__main__":
    print(ask_model("Give me three creative local AI app ideas."))

Enter fullscreen mode Exit fullscreen mode

Run it from WSL2:

uv run app.py

Enter fullscreen mode Exit fullscreen mode

The model stays loaded in LM Studio on Windows. The Python process, source code, and uv environment remain in WSL2.

No API token is needed when LM Studio authentication is disabled. The lm-studio value in the example is only a non-empty placeholder required by the OpenAI client; I did not create or enter a token. If you enable authentication in LM Studio, replace it with a real token:

export LM_STUDIO_API_KEY="your-token"

Enter fullscreen mode Exit fullscreen mode

Do not commit that token to the repository.

Use the Model Identifier LM Studio Returns

The workshop’s gemma4:e2b is an Ollama-style model tag. It is not necessarily the identifier that LM Studio expects.

Always inspect the API response:

curl http://127.0.0.1:1234/v1/models

Enter fullscreen mode Exit fullscreen mode

In my case, the correct identifier was:

google/gemma-4-e2b

Enter fullscreen mode Exit fullscreen mode

Use that exact value in the OpenAI client. Do not guess the model name from the chat display or from another model runner’s documentation.

The Failures That Cost Me Time

The API server was stopped

My LM Studio chat session was working, but the Local Model API screen showed Stopped. No WSL networking configuration can fix a server that is not listening.

The Local Model API server was stopped even though the chat window worked.

The first diagnostic should always be the Windows-side request:

curl.exe http://127.0.0.1:1234/v1/models

Enter fullscreen mode Exit fullscreen mode

I used the wrong localhost

Under default WSL2 NAT networking, 127.0.0.1 inside WSL2 refers to the Linux environment. It does not automatically mean the Windows host.

Mirrored networking changes this relationship so WSL2 can reach Windows localhost services through 127.0.0.1.

I entered a Windows configuration file into Bash

These lines are not Bash commands:

[wsl2]
networkingMode=mirrored

Enter fullscreen mode Exit fullscreen mode

They belong in %UserProfile%\.wslconfig, and the WSL subsystem must be restarted after saving them.

I investigated the wrong plugin

I also tried to install a shell-access plugin for LM Studio. That plugin is designed to let a model execute commands on the host or in WSL. It does not solve the basic problem of making a Python program reach the model API.

For workshop code, the API connection is the first milestone. Tool execution and agent plugins are a separate concern.

A Note on Performance

Connectivity and inference speed are different problems.

After the connection worked, Gemma 4 E2B generated at roughly 2.8 to 3.3 completion tokens per second on my laptop. A simple coding request took several minutes because the model spent many tokens on reasoning and the machine had no discrete GPU.

That does not indicate a WSL2 networking failure. If /v1/models responds quickly but generation is slow, the connection is working. The likely causes are model size, reasoning behavior, quantization, context length, and available hardware.

For a workshop, benchmark a small non-reasoning or coding-focused model before assuming that the API setup is broken.

The Checklist I Wish I Had

Before the workshop, I would have run these checks in order:

  1. Start the model in LM Studio.
  2. Enable Settings -> Local Model API -> Local API server.
  3. Confirm the API from PowerShell with curl.exe.
  4. Configure mirrored networking in %UserProfile%\.wslconfig.
  5. Run wsl --shutdown from PowerShell.
  6. Confirm the same API from WSL2 with curl.
  7. Copy the exact model ID from /v1/models.
  8. Use an OpenAI-compatible client from the WSL2 application.
  9. Only after all of that, investigate tool calling or agent behavior.

The entire distinction is this:

LM Studio chat working
        !=
LM Studio API reachable from WSL2

Enter fullscreen mode Exit fullscreen mode

Once I treated those as separate systems, the setup became straightforward.

If you use Windows for your model runtime and WSL2 for development, I hope this saves you the day I lost.

¡Hasta luego!

원문에서 계속 ↗