Ubuntu 25.04에서 LM Studio 서비스 배포

<div data-theme-toc="true">
</div>

Статья обновлена 2025.11.10, см. комментарий.


### Введение

В этой статье расскажу о том, как развернуть LM Studio как сервис в среде Ubuntu 25.04 (может подойдет и для других версий).

>LM Studio в качестве сервера позволяет не только загружать языковые модели и работать с ними единолично, но и организовывать API для подключения внешних сервисов. При этом вернуться к локальной работе можно, остановив сервис и включив приложение как обычно.

Вы сможете:
- работать с разными языковыми моделями (по запросу с выгрузкой при неиспользовании)
- подключать к API свои приложения или плагины

![В черном и белом стиле изображен программист, сосредоточенно работающий за компьютером с сигаретой в руке, окруженный книжными полками. (Подпись к изображению от AI)|689x394](upload://lGZiKaFv7a47ChrLB6WhLMt9PMU.jpeg)

### Скачать

Скачайте AppImage (в статье мы говорим про приложение для Linux), сайт:

https://lmstudio.ai/

Разместите файл в папке `~/llm` и сделайте его исполняемым:

chmod +x ~/llm/LM-Studio-0.3.27-4-x64.AppImage

На момент написания статьи эта версия была актуальной.

### headless

Развертывание в виде сервиса требуется тогда, когда вы работаете с ним удаленно. Сразу определитесь:

а) на сервере (ПК/ноутбуке и т.д.) графика есть и пользователь уже логинился хотя бы раз в оболочку UI. Либо если вы работаете в UI - то пропустите этот шаг.

б) на сервере графики нет либо пользователь никогда не логинился в UI. В этом случае понадобится пара дополнительных команд, выполняемых разово:

```bash
sudo loginctl enable-linger $USER

эта команда делает возможным работать с окружением, не входя в графический интерфейс

loginctl show-user ivan | grep Linger

эта команда показывает статус настройки (активно или недоступно):

Linger=yes

Команды, проверяющие, что ничего не мешает (в выводе должно быть какой-нибудь понятный статус типа degraded, но недопустимы ошибки):

systemctl --user status
systemctl --user is-system-running

systemd

Если вы все еще не решились на headless-режим (без графики), то пропустите этот шаг.

А если автозапуск это ваше всё, то будьте добры создать скрипт:

~/.config/systemd/user/lm-studio.service

И допустим, что ваш исполняемый файл LM Studio находится по адресу

%HOME/llm/LM-Studio-0.3.27-4-x64.AppImage

содержимое:

[Unit]
Description=LM Studio Service
After=network.target

[Service]
Type=simple

ExecStart=/usr/bin/xvfb-run -a --server-args="-screen 0 1920x1080x24" %h/llm/LM-Studio-0.3.27-4-x64.AppImage --run-as-service
ExecStartPost=/bin/bash -c 'sleep 10 && exec lms server start'

Restart=always
RestartSec=10
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin:/bin:%h/.lmstudio/bin
Environment=DISPLAY=:99
WorkingDirectory=%h/llm

[Install]
WantedBy=default.target

Скрипт состоит из двух частей:

  • запуск приложения
  • старт серверной части

По своей сути такой скрипт является хрупким, так как состоит из двух частей, которые не знают о состоянии друг друга. Не используйте подобные решения в продакшене. И вообще LM Studio не используйте, так как VLLM значительно быстрее.

Заметьте, что здесь эмулируется экран, поэтому вам необходимо доустановить:

sudo apt update && sudo apt install xvfb

Обратите внимание, что systemd в данном примере будет установлена от пользователя, а не root.

Проделайте обычные операции для стартового скрипта (применить изменения и сделать автозапуск):

systemctl --user daemon-reload
systemctl --user enable --now lm-studio.service

Запуск

systemctl --user status lm-studio.service

Сервис сейчас должен молчать, поскольку его еще ни разу не запускали.

systemctl --user start lm-studio.service

и теперь проверьте статус сервера:

lms server status

он должен прослушивать порт 1234.

Строго говоря, вам следует сначала поиграть с UI LM Studio, чтобы установить нужные параметры и загрузить модели. А также перевести прослушивание с адреса 127.0.0.1 на 0.0.0.0, если нужно организовать внешнее подключение к вашему API (потенциально опасно, так как сначала установите шифрование и авторизацию)

CURL

Проверьте endpoint вашего сервера:

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

вам должны вернуться доступные модели:

*   Trying 127.0.0.1:1234...
* Connected to 127.0.0.1 (127.0.0.1) port 1234
* using HTTP/1.x
> GET /v1/models HTTP/1.1
> Host: 127.0.0.1:1234
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
<
{
  "data": [
    {
      "id": "nvidia_nvidia-nemotron-nano-9b-v2",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "text-embedding-qwen3-embedding-0.6b",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "qwen/qwen3-8b",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "google/gemma-3-4b",
      "object": "model",
      "owned_by": "organization_owner"
    }
  ],
  "object": "list"
* Connection #0 to host 127.0.0.1 left intact

REST API

Теперь вы можете подключаться к вашему REST API, используя эндпоинты:

GET   http://127.0.0.1:1234/v1/models
POST  http://127.0.0.1:1234/v1/chat/completions
POST  http://127.0.0.1:1234/v1/completions
POST  http://127.0.0.1:1234/v1/embeddings
<div data-theme-toc="true"></div>

Статья обновлена 2025.11.10, см. комментарий.


### 소개

이 기사에서는 Ubuntu 25.04 환경에서 LM Studio를 서비스로 배포하는 방법을 설명합니다(다른 버전에서도 작동할 수 있습니다).

>LM Studio를 서버로 사용하면 언어 모델을 로드하고 독립적으로 작업할 뿐만 아니라 외부 서비스를 연결하기 위한 API를 구성할 수 있습니다. 서비스를 중지하고 애플리케이션을 평소처럼 실행하여 로컬 작업으로 되돌릴 수도 있습니다.

다음 작업을 수행할 수 있습니다:
- 다양한 언어 모델로 작업 (사용하지 않을 때는 다운로드)
- API에 자체 애플리케이션 또는 플러그인을 연결

![흑백 스타일의 프로그래머가 컴퓨터 앞에서 담배를 피우며 책장으로 둘러싸여 집중하고 있는 모습. (이미지 설명 AI)|689x394](upload://lGZiKaFv7a47ChrLB6WhLMt9PMU.jpeg)

### 다운로드

Linux용 애플리케이션(AppImage)을 다운로드하세요:

https://lmstudio.ai/

파일을 `~/llm` 폴더에 배치하고 실행 가능하게 만드세요:

chmod +x ~/llm/LM-Studio-0.3.27-4-x64.AppImage

기사 작성 시점에 이 버전이 최신 버전이었습니다.

### headless

서비스로 배포해야 하는 경우는 원격으로 작업할 때입니다. 먼저 다음 사항을 결정하세요:

a) 서버(PC/노트북 등)에 그래픽이 있고 사용자가 UI에 최소 한 번은 로그인한 경우. 또는 UI에서 작업하는 경우 이 단계를 건너뜁니다.

b) 서버에 그래픽이 없거나 사용자가 UI에 로그인하지 않은 경우, 다음 추가 명령을 한 번 실행해야 합니다:

```bash
sudo loginctl enable-linger $USER

이 명령은 그래픽 인터페이스에 로그인하지 않고도 환경에서 작업할 수 있도록 해줍니다.

loginctl show-user ivan | grep Linger

이 명령은 설정 상태(활성 또는 사용 불가능)를 표시합니다:

Linger=yes

아무것도 방해하지 않는지 확인하는 명령(출력에 degraded와 같은 이해 가능한 상태가 있어야 하지만 오류는 허용되지 않음):

systemctl --user status
systemctl --user is-system-running

systemd

아직 headless 모드(그래픽 없음)를 선택하지 않은 경우 이 단계를 건너뜁니다.

하지만 자동 시작을 원한다면 스크립트를 만들어야 합니다:

~/.config/systemd/user/lm-studio.service

그리고 LM Studio 실행 파일이 다음 위치에 있다고 가정합니다:

%HOME/llm/LM-Studio-0.3.27-4-x64.AppImage

내용:

[Unit]
Description=LM Studio Service
After=network.target

[Service]
Type=simple

ExecStart=/usr/bin/xvfb-run -a --server-args="-screen 0 1920x1080x24" %h/llm/LM-Studio-0.3.27-4-x64.AppImage --run-as-service
ExecStartPost=/bin/bash -c 'sleep 10 && exec lms server start'

Restart=always
RestartSec=10
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin:/bin:%h/.lmstudio/bin
Environment=DISPLAY=:99
WorkingDirectory=%h/llm

[Install]
WantedBy=default.target

스크립트는 두 부분으로 구성됩니다:

  • 애플리케이션 시작
  • 서버 부분 시작

본질적으로 이러한 스크립트는 서로 상태를 모르는 두 부분으로 구성되어 있기 때문에 불안정합니다. 프로덕션 환경에서 이와 같은 솔루션을 사용하지 마세요. 그리고 LM Studio도 사용하지 마십시오. 왜냐하면 VLLM이 훨씬 빠르기 때문입니다.

여기서 systemd는 root가 아닌 사용자로부터 설치된다는 점에 유의하세요.

일반적인 시작 스크립트 작업을 수행하십시오(변경 사항을 적용하고 자동 시작):

systemctl --user daemon-reload
systemctl --user enable --now lm-studio.service

실행

systemctl --user status lm-studio.service

서비스는 아직 한 번도 실행되지 않았으므로 조용해야 합니다.

systemctl --user start lm-studio.service

이제 서버 상태를 확인하세요:

lms server status

포트 1234에서 수신 대기 중이어야 합니다.

> UI LM Studio에서 필요한 매개변수를 설정하고 모델을 다운로드하기 전에 UI로 먼저 작업하는 것이 좋습니다. 또한 외부 API 연결이 필요하면 수신 대기를 127.0.0.1에서 0.0.0.0으로 변경하세요(잠재적으로 위험하므로 먼저 암호화 및 인증을 설정해야 합니다).

CURL

서버 엔드포인트를 확인합니다:

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

사용 가능한 모델이 반환되어야 합니다:

* Trying 127.0.0.1:1234...
* Connected to 127.0.0.1 (127.0.0.1) port 1234
* using HTTP/1.x
> GET /v1/models HTTP/1.1
> Host: 127.0.0.1:1234
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
<
{
  "data": [
    {
      "id": "nvidia_nvidia-nemotron-nano-9b-v2",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "text-embedding-qwen3-embedding-0.6b",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "qwen/qwen3-8b",
      "object": "model",
      "owned_by": "organization_owner"
    },
    {
      "id": "google/gemma-3-4b",
      "object": "model",
      "owned_by": "organization_owner"
    }
  ],
  "object": "list"
* Connection #0 to host 127.0.0.1 left intact

REST API

이제 다음 엔드포인트를 사용하여 REST API에 연결할 수 있습니다:

GET   http://127.0.0.1:1234/v1/models
POST  http://127.0.0.1:1234/v1/chat/completions
POST  http://127.0.0.1:1234/v1/completions
POST  http://127.0.0.1:1234/v1/embeddings

어딘가 0.3.31-2와 0.3.31-7 버전 사이에 외부에서 127.0.0.1로 청취 인터페이스를 강제로 변경하고 CORS를 비활성화하는 변경 사항이 발생했습니다.

LM Studio는 HTTP 서버 구성 (hot-reload)을 지원하므로 (적어도 corsnetworkInterface 변경 시) 재시작 없이 변경할 수 있습니다 (한 번만 작동함):

%h/.lmstudio/.internal/http-server-config.json
jq '.cors = true | .networkInterface = "0.0.0.0"' ~/.lmstudio/.internal/http-server-config.json | sponge ~/.lmstudio/.internal/http-server-config.json

sponge는 moreutils 패키트에 포함되어 있으므로 설치하는 것을 잊지 마세요.

변경 사항을 자동으로 적용하려면 시작 스크립트를 수정하세요:

$HOME/.config/systemd/user/lm-studio.service
[Unit]
Description=LM Studio Service
After=network.target

[Service]
Type=simple

ExecStart=/usr/bin/xvfb-run -a --server-args="-screen 0 1920x1080x24" %h/llm/lmstudio --run-as-service

# 1. HTTP 서버 시작
ExecStartPost=/bin/bash -c 'sleep 15 && exec lms server start'

# 2. 필요한 설정 적용 (서버가 이미 시작된 후)
ExecStartPost=/bin/bash -c ' \
  sleep 2 && \
  jq ".cors = true | .networkInterface = \\\"0.0.0.0\\\"" \
     "%h/.lmstudio/.internal/http-server-config.json" \
     > "%h/.lmstudio/.internal/http-server-config.json.tmp" && \
  mv "%h/.lmstudio/.internal/http-server-config.json.tmp" \
     "%h/.lmstudio/.internal/http-server-config.json" \
'

Restart=always
RestartSec=10
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin:/bin:%h/.lmstudio/bin
Environment=DISPLAY=:99
WorkingDirectory=%h/llm

[Install]
WantedBy=default.target

변경 사항을 적용하고 서비스를 다시 시작하세요 (sudo 없이!):

systemctl --user daemon-reload
systemctl --user stop lm-studio.service
systemctl --user start lm-studio.service

운영체제의 튜닝 파라미터를 최적화하기 위해 주의를 기울이세요.

예시

내 시스템의 예시입니다 (Oculink를 통해 그래픽카드가 연결된 노트북):

free -h
               total        used        free      shared  buff/cache   available
Mem:            37Gi       4.9Gi        29Gi       240Mi       3.5Gi        32Gi
Swap:          8.0Gi          0B       8.0Gi
cat /proc/meminfo | grep -E 'MemTotal|MemAvailable'

MemTotal:       39223064 kB
MemAvailable:   34073484 kB

VRAM은 별도로 표시됩니다 — MemTotal에 포함되지 않습니다.

nvidia-smi

Fri Nov 21 12:24:47 2025       \
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.09              Driver Version: 580.82.09      CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 5060 Ti     Off |   00000000:01:00.0 Off |                  N/A |
|  0%   44C    P8              8W /  180W |      13MiB /  16311MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A            5314      G   /usr/bin/gnome-shell                      2MiB |
+-----------------------------------------------------------------------------------------+

무엇을 해야 하는가

overcommit 정책과 swappiness 설정을 확인하세요.

cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/overcommit_ratio
cat /proc/sys/vm/swappiness

권장 값:

2 # 한도 = (RAM * ratio/100) + Swap
80 # 이 값이 ratio
10 # 20 이하로 설정 — 남은 RAM의 몇 퍼센트가 남아 있어야 swap이 활성화되며, swap 크기는 8 GiB일 수 있습니다. OS 휴면 기능을 사용하지 않는 경우, swap 크기는 RAM 크기와 동일하게 설정됩니다.

실행할 명령어:

sudo sysctl vm.overcommit_ratio=80
echo 'vm.overcommit_ratio=80' | sudo tee -a /etc/sysctl.d/99-ml-workstation.conf
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-ml-workstation.conf

중요: LLM (특히 llama.cpp)을 사용할 때 THP = always는 시스템 로그인 후 분당 단위의 지연을 유발할 수 있습니다.

cat /sys/kernel/mm/transparent_hugepage/enabled
# 값은 [always] madvise never여야 합니다.

디스크 작업 (예: LLM 가중치를 SSD에 저장할 때)에서는 writeback 설정이 중요합니다.

cat /proc/sys/vm/dirty_ratio
cat /proc/sys/vm/dirty_background_ratio
cat /proc/sys/vm/dirty_expire_centisecs

NVMe에 최적화된 값:

10
5
1000 (10초)
echo 'vm.dirty_ratio=10' | sudo tee -a /etc/sysctl.d/99-ml-workstation.conf
echo 'dirty_background_ratio=5' | sudo tee -a /etc/sysctl.d/99-ml-workstation.conf
echo 'vm.dirty_expire_centisecs=1000' | sudo tee -a /etc/sysctl.d/99-ml-workstation.conf

lmstudio를 실행하기 전에 메모리 캐시를 정리하는 것이 권장됩니다:

sync && echo 2 | sudo tee /proc/sys/vm/drop_caches