NordBastion의 북극곰 마스코트가 어두운 노르딕 금고 안, 조각된 돌 벤치에 앉아 무릎 위에 노트북을 올려놓고 있다. 옆의 서버 랙 위에는 육각형 유리 용기 안에 봉인된 빛나는 시안색 신경망 격자가 있고, 그 용기에서 짧은 시안색 토큰의 흐름이 닫힌 룬 문 뒤편의 화면으로 흘러내린다.
방법 가이드 · AI 에이전트·읽기 17분 · 실습 30분

VPS에 LLM 셀프호스팅.
GPU 없음. API 키 없음. 프롬프트는 절대 건물 밖으로 나가지 않습니다.

LLM 셀프호스팅 여섯 단계 — 자신의 하드웨어에서 응답하는 언어 모델을 만듭니다. 서버를 사기 전에 초당 토큰 수를 예측하는 산술, 4, 8, 16, 32GB 중 어디에 맞는 모델인지, Ollama가 기본 제공하지 않는 인증, 그리고 정말로 맞지 않는 작업의 솔직한 목록까지 다룹니다. Debian 12에서 테스트했습니다.

6단계
  1. 01

    크기

    코어가 아니라 대역폭

  2. 02

    설치

    Ollama

  3. 03

    측정

    당신만의 토큰/초

  4. 04

    보호

    TLS + 토큰

  5. 05

    연결

    기본 URL 하나

  6. 06

    제한

    컨텍스트, RAM, 디스크

시작하기 전에 · 산술

나눗셈 하나가 이 서버로 무엇을 할 수 있는지 알려줍니다. 서버를 사기 전에 해 보십시오.

언어 모델을 로컬에서 구동하는 것에 관해 쓰인 글은 거의 다 그래픽카드 이야기이고, 가진 것이 가상 머신뿐이라면 별 도움이 되지 않습니다. 실제로 쓸모 있는 사고 모델은 GPU 담론이 암시하는 것보다 단순하며, 한 문장으로 요약됩니다. 토큰 하나를 만들어내려면, 덴스 모델은 자신의 가중치 전부를 메모리에서 읽어야 합니다. 일부가 아니라 — 전부를, 토큰마다 한 번씩.

이 한 가지 사실이 성능에 관한 모든 질문을 정리해 줍니다. 생성 속도는 얼마나 많은 코어를 빌리는지가 아니라, 머신이 RAM에서 모델을 얼마나 빠르게 흘려보낼 수 있는지로 정해집니다. 이는 돈을 쓰기 전에 봉투 뒷면에서 계산할 수 있는 상한을 줍니다:

tokens per second  ≈  memory bandwidth (GB/s)  ÷  model size (GB)

양자화된 8B 모델은 약 5GB를 차지합니다. 실제로 초당 20GB 안팎을 스트리밍할 수 있는 가상화 호스트라면 상한은 초당 약 4토큰이며, 실제로 관측되는 수치는 그 절반에서 3분의 2 정도일 것입니다. 대략 초당 세 단어입니다. 이것을 실망이 아니라 이 작업량에 대한 사실로 받아들이십시오. 채팅창으로는 느리지만, 문서를 분류해 JSON 한 줄을 반환하는 작업에는 충분합니다.

코어는 여전히 중요합니다. 다만 사람들이 생각하는 이유 때문은 아닙니다. 스레드를 늘리는 것은 메모리 경로가 포화될 때까지만 도움이 되며, 이런 머신에서는 그 지점이 이르게 옵니다 — 흔히 스레드 4~8개 근처입니다. 그 지점을 넘어서면 나머지 코어는 유휴 상태로 RAM을 기다립니다. 그래서 16코어 서버가 텍스트 생성에서 4코어 서버보다 네 배 빠르지 않은 것이며, 속도를 기대하고 코어에 돈을 쓰는 것이 잘못된 등급을 고르는 가장 흔한 방식인 이유입니다.

읽기는 빠르고, 쓰기는 느립니다. 모든 요청에는 두 단계가 있고, 둘은 전혀 다르게 동작합니다. 프롬프트를 처리하는 단계 — 프리필 — 은 전체 입력에 대해 한 번에 이루어지는 연산 집약적 행렬 연산이며, 생성보다 몇 배는 더 빠르게 실행됩니다. 답을 만들어내는 단계는 앞서 설명한 메모리 집약적 부분으로, 토큰을 하나씩 처리합니다. 그래서 2천 단어짜리 문서를 건네고 세 문장으로 돌려달라고 하는 것은 편안한 작업량이지만, 2천 단어짜리 에세이를 써달라는 것은 그렇지 않습니다. 이 비대칭을 염두에 두고 프롬프트를 설계하면, CPU 서버는 토큰 속도가 암시하는 것보다 훨씬 낫게 느껴집니다.

티어 메모리 무리 없이 돌아가는 최대 모델 대략적 자릿수 용도
Sentinel · $3.904 GBQ4 기준 3B (~2 GB)초당 한 문장분류, 태깅, 라우팅, 임베딩
Garrison · $7.908 GBQ4 기준 8B (~5 GB)초당 몇 단어기본값. 요약, JSON 추출, RAG 답변
Ravelin · $16.9016 GBQ4 기준 14B (~9 GB)위 수치의 약 절반더 어려운 추론, 긴 컨텍스트, 배치 파이프라인
Bulwark · $32.9032 GBQ4 기준 32B (~20 GB)초당 한 단어 미만속도보다 품질. 비동기 작업 전용
Citadel · $62.9064 GBQ4 기준 70B (~40 GB)답변당 몇 분맞습니다. 대화형은 아닙니다. 야간 작업용

모델 크기는 흔히 쓰이는 Q4_K_M 양자화 기준이며, 대체로 눈에 띄지 않는 약간의 품질을 내주고 메모리를 절반 이하로 줄입니다. 속도 열은 위의 나눗셈에서 도출한 대략적인 자릿수일 뿐 벤치마크가 아닙니다 — 3단계의 요점은 이 표를 포함해 어떤 표도 믿지 말고 직접 자신의 머신을 측정하라는 것입니다.

시작하기 전에 · 적합성

CPU에 진짜로 맞는 것. 그리고 맞지 않는 것, 솔직하게.

이 절에서는 솔직한 설명이 열광적인 설명보다 훨씬 가치가 있습니다. 셀프호스팅 모델을 가장 빨리 포기하게 되는 길은, 그것이 가장 못하는 일에 써 보고는 이 아이디어 전체가 어리석었다고 결론짓는 것이기 때문입니다.

여유 있게 맞습니다. 출력이 짧고 가치가 문장력이 아니라 판단력에 있는 모든 작업입니다. 메시지를 몇 가지 범주 중 하나로 분류하기. 지원 티켓이 긴급한지 판단하기. 청구서에서 다섯 개 필드를 JSON으로 추출하기. 스레드를 세 문장으로 요약하기. 문서에 태그 달기. 제품 설명 다시 쓰기. 짧은 문자열 번역하기. 두 레코드가 같은 사람을 가리키는지 판별하기. 다른 곳으로 넘어가기 전에 문단에서 이름 지우기. 이들 모두 긴 입력을 소비하고 짧은 출력을 만드는데, 이것이 바로 CPU가 잘 다루는 비대칭입니다.

맞기는 하지만, 인내가 필요합니다. 사람이 기다리지 않는 작업. 야간 배치, 큐 워커, 그날의 문서를 훑는 야간 처리, 예약된 리포트. 답을 기다리며 막히는 것이 없다면, 채팅창에서는 견딜 수 없을 토큰 속도도 전혀 문제가 되지 않습니다 — 새벽 3시에 6분 동안 도는 작업은 그냥 실행된 작업일 뿐입니다.

맞지 않습니다. 사람들이 실제로 즐겁게 쓸 만한 대화형 어시스턴트: 이 속도로는 커서가 기어가듯 움직이고, 경험은 차라리 어시스턴트가 없는 것보다 못합니다. 장문 생성 — '2천 단어를 써줘' 같은 — 은 출력 전체가 느린 부분입니다. 대규모 저장소를 순회하는 코딩 에이전트는 컨텍스트와 품질 기준 모두 작은 모델이 감당할 수 있는 범위를 넘어섭니다. 10만 토큰급 컨텍스트가 필요한 모든 작업은 캐시만으로도 머신의 용량을 넘어섭니다. 그리고 이미지나 영상 모델은 완전히 다른 분야이며 실제로 GPU를 필요로 합니다.

작업이 그 마지막 그룹에 속한다면, 합리적인 답은 더 큰 CPU 서버를 사는 것이 아니라 하이브리드 구성입니다. 대다수 호출은 로컬 모델이 처리하고, 프런티어 수준의 추론이 필요한 소수만 호스팅형 API로 보내십시오. 이는 AI 에이전트를 24시간 구동하는 가이드가 런타임 측면에서 설명하는 것과 정확히 같은 형태입니다. 그 가이드는 모델 자체를 의도적으로 다루지 않았습니다. 이 가이드가 그 빠진 절반입니다.

1단계 · 크기

코어가 아니라 모델을 기준으로 구매하십시오. 그리고 여유를 남기십시오.

작업에서 거꾸로 출발하십시오. 모델이 무엇을 해야 하는지 정하고, 그것을 해낼 수 있는 가장 작은 크기를 고르고, 그 크기가 Q4_K_M 기준으로 얼마나 차지하는지 확인한 뒤, 부가 비용을 더하십시오:

RAM needed  =  model file  +  KV cache  +  ~2 GB for the system

  3B  Q4_K_M  ≈  2.0 GB        KV cache at 8k context   ≈  0.5–1 GB
  8B  Q4_K_M  ≈  4.9 GB        KV cache at 32k context  ≈  2–4 GB
 14B  Q4_K_M  ≈  9.0 GB
 32B  Q4_K_M  ≈ 20.0 GB
 70B  Q4_K_M  ≈ 40.0 GB

키-값 캐시는 사람들이 잊어버리는 부담입니다. 대화에 이미 등장한 모든 토큰은 모델이 다시 계산하지 않도록 메모리에 보관되며, 이 저장 공간은 허용한 컨텍스트에 비례해 커집니다. 컨텍스트를 두 배로 늘리면 대략 두 배로 커집니다. 4k 컨텍스트에서는 맞던 모델이 32k에서는 맞지 않게 될 수 있는데, 이는 첫 요청이 아니라 열 번째 요청에서 실패하기 때문에 산술 오류가 아니라 미스터리처럼 보이게 됩니다.

여기에는 우아한 성능 저하 같은 것은 없습니다. 합계가 RAM을 넘어서면 커널은 얌전히 느려지지 않습니다. 토큰 하나하나마다 모델 가중치를 디스크로 페이징하기 시작합니다. 4초짜리 생성이 4분이 되고, 부하 평균은 수십까지 치솟으며, 서버의 다른 모든 것 — 데이터베이스, 웹 서버, SSH 세션 — 도 함께 고통받습니다. 메모리에 맞추는 것은 최적화가 아닙니다. 필수 조건입니다.

패널에서: 주문 → VPS → 산술이 가리킨 등급, 이미지는 Debian 12. 계정을 여는 데 이메일 주소가 필요하지 않고, 어느 단계에서도 신분증을 요구하지 않으며, 청구서는 Monero, Bitcoin, Lightning 또는 그 밖에 지원되는 자산으로 결제됩니다 — 이는 일반 웹 서버보다 여기서 더 중요한데, 그 이유는 익명 VPS 호스팅 필러 가이드가 설명하며, 아래의 프라이버시 챕터가 그 내용을 프롬프트에 구체적으로 적용합니다.

2단계 · 설치

명령 하나, 서비스 하나. 루프백에 바인딩된 채로, 그대로 둡니다.

먼저 서버를 강화하십시오 — 키 전용 SSH, 요청하지 않은 것은 아무것도 허용하지 않는 방화벽, 무인 보안 업데이트. 첫 시간 체크리스트는 한 시간 정도 걸리며, 이 서버는 곧 당신이 던지는 모든 질문을 품게 될 서버입니다.

그다음 러너를 설치하십시오. Ollama는 모델 레지스트리, REST API, systemd 유닛을 감싼 llama.cpp이며, 한 줄짜리 설치 스크립트가 셋 다 설정해 줍니다:

apt update && apt install -y curl
curl -fsSL https://ollama.com/install.sh | sh

systemctl status ollama --no-pager
ss -ltnp | grep 11434
# → 127.0.0.1:11434 — loopback only. Leave it that way.

그 마지막 줄은 두 번 읽을 가치가 있습니다. 기본 설정에서 서비스는 루프백 인터페이스에서 대기하며, 이는 정확히 옳은 설정입니다. 그다음 10분 안에 가장 흔히 저지르는 실수는, 다른 머신에서 접근이 안 된다는 이유로 OLLAMA_HOST를 0.0.0.0으로 설정하는 것입니다. 제대로 접근하는 방법은 4단계에서 다룹니다. 포트 11434가 인터넷에 직접 노출되는 버전은 어디에도 없습니다.

나중에 알아채기보다 지금 정해 두는 것이 나은 설정이 두 가지 있습니다. 모델은 기본적으로 /usr/share/ollama 아래에 저장되고 용량이 크므로, 여유가 있는 곳으로 지정해 두십시오. 그리고 기본값은 마지막 요청 이후 5분 동안 모델을 RAM에 상주시키는데, 이는 다른 작업도 하는 서버에서는 다소 넉넉한 설정입니다:

systemctl edit ollama
[Service]
Environment="OLLAMA_MODELS=/var/lib/ollama/models"
Environment="OLLAMA_KEEP_ALIVE=30m"
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
systemctl daemon-reload && systemctl restart ollama

병렬 요청과 다중 모델 로드는 둘 다 메모리 사용량을 곱으로 늘리며, 모델 하나만 담을 수 있는 크기로 맞춘 머신에는 두 번째 사본을 위한 여유 기가바이트가 없습니다. 큐를 직렬화하는 것은 이 하드웨어의 한계가 아니라, 쓰러지지 않는 유일한 설정입니다.

3단계 · 측정

직접 자신의 수치를 확보하십시오. 다른 사람의 벤치마크는 당신의 머신에 대한 이야기가 아닙니다.

모델을 하나 내려받으십시오. 첫 측정에는 요즘 나온 8B급 인스트럭트 모델 아무거나로 충분합니다 — 크기가 서로 비슷해서, 측정된 시간이 모델이 아니라 하드웨어에 대해 말해 줍니다:

ollama pull llama3.1:8b        # ~4.9 GB at Q4_K_M
ollama list
ollama ps                      # nothing resident yet

이제 타이밍을 켠 채로 생성을 한 번 실행하십시오. 중요한 수치는 생성 속도(eval rate)입니다 — 프롬프트를 다 읽은 뒤, 초당 만들어지는 토큰 수입니다:

ollama run llama3.1:8b --verbose "Reply with exactly one sentence about the Baltic Sea."
total duration:        14.2s
load duration:          3.1s
prompt eval count:        24 token(s)
prompt eval rate:      92.11 tokens/s      ← reading: fast
eval count:               38 token(s)
eval rate:              3.42 tokens/s      ← writing: the real ceiling

두 줄, 두 개의 다른 세계. 읽기는 초당 90여 토큰으로 돌았고, 쓰기는 3.5토큰이었습니다. 그 비율이 바로 산술 장에서 다룬 비대칭이며, 당신 자신의 하드웨어에서 측정한 것이고, 오늘 얻을 수 있는 가장 쓸모 있는 사실입니다. 그것이 말해 주는 것: 이 서버에는 긴 입력을 주고 짧은 출력을 요구하십시오.

같은 측정을 API를 통해 하는 방법입니다. 모델 크기 두세 개를 스크립트로 비교하려 한다면 실제로 이 방법이 필요합니다:

apt install -y jq

curl -s http://127.0.0.1:11434/api/generate -d '{
  "model":  "llama3.1:8b",
  "prompt": "List three Nordic capitals.",
  "stream": false
}' | jq '{
  tokens: .eval_count,
  seconds: (.eval_duration / 1000000000),
  rate: (.eval_count / (.eval_duration / 1000000000))
}'

바로 아래 크기와 바로 위 크기를 측정한 뒤, 거기서 멈추십시오. 3B와 14B를 내려받아 같은 프롬프트를 각각 돌려보고, 세 가지 속도를 적어 두십시오. 이제 이 머신에서 그 교환이 정확히 얼마의 대가를 치르는지 알게 됩니다 — 보통 방향마다 대략 두 배 차이입니다 — 그러면 의견이 아니라 작업에 맞춰 고를 수 있습니다. 그런 다음 계속 쓰지 않을 모델은 지우십시오. 각각 몇 기가바이트씩 차지하기 때문입니다.

모든 모델의 첫 실행에는 한 가지 주의할 점이 있습니다. 출력에 나오는 로드 시간은 가중치를 디스크에서 RAM으로 읽어들이는 데 걸린 시간입니다. 이는 모델이 아직 상주하지 않을 때만 발생하며, 이를 제어하는 것이 OLLAMA_KEEP_ALIVE입니다. 속도를 비교할 때는 이 시간을 포함하지 마시고, 놀라지도 마십시오 — NVMe에서는 몇 초에 불과하고, 한 번만 발생합니다.

4단계 · 보호

Ollama에는 인증이 없습니다. 전혀 없습니다. 약한 것도 아니라 — 아예 없습니다.

이 부분은 이 가이드에서 나쁜 일이 일어나는 것을 막는 대목이므로, 에둘러 말하지 않겠습니다. Ollama API에는 비밀번호도, 토큰도, 사용자 모델도, 권한 체계도 없습니다. 포트 11434로 TCP 연결을 열 수 있는 무엇이든 당신의 CPU에서 텍스트를 생성하고, 내려받은 모델 목록을 나열하고, 새 모델을 내려받고, 쓰던 모델을 지울 수 있습니다. 켤 수 있는 설정 같은 것은 없습니다. 애초에 켤 수 있는 메커니즘 자체가 없기 때문입니다.

포트 11434는 끊임없이 스캔당하는데, 이유는 뻔합니다. 열려 있는 모델 러너는 누군가 다른 사람의 공짜 연산 자원이기 때문입니다. 증상은 경고 알림이 아닙니다. 2주 동안 느리게 느껴지는 머신과, 당신이 한 일과 맞아떨어지지 않는 대역폭 그래프입니다. 서비스는 루프백에만 두고, 그 앞에 누가 호출하는지 묻는 무언가를 세워 두십시오.

이 머신 바깥에서 모델을 필요로 하는 것이 없다면, 여기서 멈추십시오 — 이미 끝났습니다. 루프백과 방화벽만으로 완전한 답이 되며, 같은 VPS에서 실행되는 에이전트, 자동화 스택, 웹 앱은 이후 내용 없이도 127.0.0.1을 통해 모델에 접근합니다. 다른 머신에 있는 무언가가 호출해야 하는 경우에만 계속 읽으십시오.

프록시, 그리고 토큰. 길고 무작위한 토큰을 생성하고, A 레코드를 이 서버로 지정한 뒤, 인증서와 출입문 모두 Caddy가 처리하게 하십시오:

openssl rand -hex 32      # → the bearer token, store it in a password manager
apt install -y caddy

/etc/caddy/Caddyfile

llm.example.com {
    @unauthorised not header Authorization "Bearer PASTE_THE_HEX_TOKEN_HERE"
    respond @unauthorised "unauthorised" 401

    reverse_proxy 127.0.0.1:11434 {
        # Generation is slow by nature — do not let the proxy give up first.
        transport http {
            read_timeout 10m
        }
    }
}
systemctl reload caddy
ufw allow 80,443/tcp
ufw status                # 11434 must appear nowhere

기본 인증 대신 베어러 토큰을 고르는 데는 작은 우아함이 있습니다. Ollama는 OpenAI 호환 API를 제공하고, 모든 OpenAI 클라이언트는 키를 정확히 그 헤더로 보내므로, 방금 생성한 토큰이 애플리케이션이 이미 다룰 줄 아는 API 키가 됩니다. 사용자 지정 헤더는 필요 없으며, 접근 권한을 회전시키는 것은 Caddyfile 한 줄과 호출자 쪽 환경 변수 하나로 끝납니다.

서버가 아닌 다른 머신에서 확인하십시오. 첫 번째 호출은 거부되어야 하고, 두 번째 호출은 응답해야 합니다:

curl -s -o /dev/null -w '%{http_code}\n' https://llm.example.com/api/tags
# → 401

curl -s https://llm.example.com/api/tags -H "Authorization: Bearer THE_TOKEN" | jq '.models[].name'
# → the list of models you pulled

모델을 당신이 아니라 에이전트들이 호출하게 될 경우, 노출 문제는 원격 MCP 서버 호스팅 가이드에서 더 충실히 다룹니다 — TLS, 토큰, 어디서 무엇에 접근할 수 있어야 하는지에 관한 같은 논리를, 토큰이 아니라 도구를 내주는 서비스에 적용한 내용입니다.

5단계 · 연결

기본 URL 하나면, 이미 모든 것이 그 언어로 말합니다. 문자열 하나만 바꾸면 됩니다.

Ollama는 자체 API와 함께 /v1에서 OpenAI 호환 표면도 제공합니다. 통합 이야기는 그게 전부입니다. OpenAI용으로 만들어진 것이라면 — 공식 SDK, 프레임워크 래퍼, 자동화 노드까지 — 기본 URL과 키만 바꾸면 작동하며, 그 외에는 아무것도 바뀌지 않습니다.

curl -s https://llm.example.com/v1/chat/completions \
  -H "Authorization: Bearer THE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.1:8b",
    "messages": [{"role":"user","content":"Reply with the word OK."}]
  }' | jq -r '.choices[0].message.content'

Python에서는, 호스팅형 설정과 다른 부분이 맨 위 두 줄뿐입니다:

from openai import OpenAI

client = OpenAI(
    base_url="https://llm.example.com/v1",
    api_key="THE_TOKEN",
)

r = client.chat.completions.create(
    model="llama3.1:8b",
    messages=[{"role": "user", "content": "Classify: 'the invoice is overdue'"}],
)
print(r.choices[0].message.content)

JSON을 요청하면, JSON을 받습니다. 자동화에 가장 유용한 단 하나의 기능은 제약된 출력입니다. Ollama는 모델이 알아서 잘하기를 바라는 대신 답을 유효한 JSON으로 강제할 수 있으며, 이는 작은 모델을 신뢰할 수 없는 이야기꾼에서 믿을 만한 파서로 바꿔 놓습니다 — 그리고 이것이 무인으로 돌아가는 워크플로와 마흔 개마다 하나씩 깨지는 워크플로의 차이입니다:

curl -s http://127.0.0.1:11434/api/generate -d '{
  "model":  "llama3.1:8b",
  "prompt": "Extract the total and the currency: Invoice 4021, 1 249,90 EUR due 30 days.",
  "format": "json",
  "stream": false
}' | jq -r .response
# → {"total": 1249.90, "currency": "EUR"}

자동화 스택에서도 마찬가지입니다. n8n은 전용 Ollama 노드를 제공하고, OpenAI 노드는 사용자 지정 기본 URL을 받아들이므로, 기존 워크플로는 자격 증명 하나만 바꾸면 로컬 추론으로 옮겨갑니다. n8n 셀프호스팅 가이드가 자동화 엔진 자체를 다룹니다. 가능하다면 두 서버를 분리해서 운영하십시오. 유휴 상태에서도 700MB를 차지하는 엔진과 5기가바이트를 원하는 모델은 8기가바이트짜리 머신에서 서로 불편한 이웃이기 때문입니다.

그리고 임베딩 엔드포인트, 이 서버가 제 몫을 하는 지점입니다. 임베딩 모델은 생성 모델보다 두 자릿수(약 100배) 더 작고, 생성할 것 없이 청크당 한 번의 연산만 수행하므로, CPU로도 즉각적으로 느껴지는 속도로 처리됩니다:

ollama pull nomic-embed-text      # ~275 MB

curl -s http://127.0.0.1:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": ["the first chunk of a document", "the second chunk"]
}' | jq '.embeddings | length'
6단계 · 제한

한도 없는 모델 러너는 가진 것을 전부 써버립니다. 경계를 정해주십시오.

컨텍스트에 상한을 두십시오. 컨텍스트 길이는 메모리 사용량을 좌우하는 주요 손잡이이며, 기본값은 작은 서버가 감당하기에는 다소 넉넉합니다. 실제로 가장 긴 프롬프트가 필요로 하는 값으로 전역 설정을 해 두십시오 — 대부분의 분류·추출 작업은 4천 토큰 이내로 충분합니다 — 그리고 드물게 더 필요한 요청에서만 개별적으로 올리십시오:

Environment="OLLAMA_CONTEXT_LENGTH=4096"
curl -s http://127.0.0.1:11434/api/generate -d '{
  "model": "llama3.1:8b",
  "prompt": "…a long document…",
  "options": { "num_ctx": 16384 },
  "stream": false
}'

모델이 메모리에 얼마나 머물지 정하십시오. 상주 중인 모델은 즉시 호출할 수 있는 대신 여러 기가바이트를 계속 붙잡아 둡니다. 추론 전용 머신이라면 영구히 로드해 두고, 공유 머신이라면 일정 시간 후 내려가게 두십시오. 이 값은 요청 단위로도 지정할 수 있어서, 야간 배치는 실행 동안 모델을 고정해 두었다가 끝나면 해제할 수 있습니다:

OLLAMA_KEEP_ALIVE=-1     # resident until the service restarts
OLLAMA_KEEP_ALIVE=30m    # a sensible default on a shared box
OLLAMA_KEEP_ALIVE=0      # unload immediately after each request

ollama ps                # what is resident right now, and how much it holds

큐를 직렬화하십시오. 하나의 모델에 동시 요청 두 개를 보낸다고 두 배 빨라지지 않습니다. 둘은 이미 포화된 같은 메모리 경로를 두고 경쟁하며 각각 더 느려지고, Ollama가 이를 처리하려고 두 번째 사본을 로드하기로 하면 서버는 RAM이 바닥납니다. 이런 부류의 하드웨어에서는 앞에 큐를 두고 한 번에 요청 하나씩 처리하는 것이 가장 빠르면서 동시에 유일하게 안전한 설정입니다 — 그래서 2단계에서 OLLAMA_NUM_PARALLEL과 OLLAMA_MAX_LOADED_MODELS를 1로 고정해 둔 것입니다.

디스크를 지켜보십시오. 모델 네 개를 비교하면 네 개가 그대로 남고, 각각 5기가바이트씩이라 아무 경고도 없이 디스크가 조용히 채워집니다. 정리를 나중 일로 미루지 말고 비교 과정 자체에 포함시키십시오:

ollama list
du -sh /var/lib/ollama/models
ollama rm mistral:7b qwen2.5:14b

마지막으로, 재현할 수 없는 것을 백업하십시오. 모델 가중치는 재현 가능합니다 — 다시 받으면(pull) 그만입니다. 저장소에 넣을 가치가 있는 것은 설정, Caddyfile, 토큰, 3주에 걸쳐 다듬은 프롬프트, 그리고 직접 만들었다면 검색의 기반이 되는 벡터 인덱스입니다. 암호화 백업 가이드가 그 방법을 다루며, 이 서버를 위한 백업 목록은 짧지만 적어 둘 가치가 있습니다.

좋은 부분 · 검색

CPU가 통념을 뒤집는 지점. 임베딩은 느리지 않습니다.

지금까지는 전부 생성에 관한 이야기였고, 이는 CPU가 느리게 처리하는 부분입니다. 검색은 쓸모 있는 시스템 대부분에서 나머지 절반을 차지하며, 상황을 완전히 뒤집습니다 — 그래서 이 페이지에서 가장 저렴한 등급으로도, 단 한 개의 토큰도 생성하지 않으면서 진짜 가치 있는 일을 해낼 수 있는 것입니다.

임베딩 모델은 텍스트 한 조각을 벡터로 바꿉니다. 크기는 기가바이트가 아니라 수백 메가바이트 단위이고, 청크마다 정확히 한 번의 순전파만 수행하며, 메모리 대역폭에 발목 잡히는 토큰 단위 반복 루프가 없습니다. 8B 모델이 초당 세 단어를 쓰는 것과 같은 서버에서, 임베딩 모델은 문서 라이브러리를 파일 복사와 비슷한 속도로 처리합니다.

그 형태. 문서를 수백 단어 단위의 청크로 나누십시오. 각 청크를 한 번 임베딩해 벡터로 저장하십시오. 질문이 들어오면 그 질문을 임베딩하고, 가장 가까운 청크 몇 개를 찾아, 질문과 함께 모델에 건네십시오. 저장소에 특별한 것이 필요하지는 않습니다. 벡터 확장을 갖춘 SQLite 데이터베이스면 단일 VPS에서 수만 개의 청크를 처리하기에 충분하고, pgvector를 갖춘 PostgreSQL은 그보다 훨씬 더 많은 양을 감당합니다. 전용 벡터 데이터베이스는 나중에 원할 만한 좋은 선택이지만, 첫날부터 필요한 종속성은 아닙니다.

속도보다 이것이 더 중요한 이유. 각 절반이 무엇을 건드리는지 보십시오. 생성 단계는 질문 하나와 몇 문단만 봅니다. 임베딩 단계는 <em>당신이 가진 모든 문서</em>를 봅니다 — 전체 아카이브, 모든 계약서, 모든 메모, 모든 메시지가 청크 단위로 모델을 거쳐 갑니다. 이 단계가 호스팅형 엔드포인트에서 실행된다면, 색인을 만들기 위해 당신의 전체 말뭉치가 제3자에게 전송된 셈입니다. 자신의 머신에서 실행된다면, 아무것도 옮겨가지 않습니다.

이는 프런티어 수준의 품질을 포기하고 싶지 않은 이에게 진짜로 훌륭한 하이브리드를 제공합니다. 색인은 로컬에서, 검색도 로컬에서 하고, 답이 뛰어나야 할 때만 질문과 검색된 청크 세 개만 호스팅형 모델로 보내십시오. 말뭉치는 집에 머물고, 그중 얇은 조각만, 필요할 때만 이동합니다.

이 사이트의 이웃 가이드 두 개가 이 패턴을 구체적으로 보여줍니다. 셀프호스팅 SearXNG는 말뭉치 대신 열린 웹을 위한 프라이빗 프런트엔드를 검색 계층에 제공하고, 셀프호스팅 문서 저장소는 그 말뭉치를 제공합니다. 이 둘에 모델까지 더해도, 호스팅형 좌석 하나보다 저렴한 월 비용의 등급에서 충분히 돌아갑니다.

모델 아래의 계층

민감한 것은 프롬프트입니다. 답변이 아니라 — 질문입니다.

사람들은 모델 프라이버시를 마치 위험이 출력에 있는 것처럼 따집니다. 그렇지 않습니다. 출력은 범용적인 텍스트일 뿐이고, 다른 수천 명도 비슷한 것을 받았습니다. 정체를 드러내는 것은 입력이며 — 1년치 입력은 한 조직의 놀랍도록 완전한 초상화입니다.

요청 로그에 실제로 무엇이 담기는지 생각해 보십시오. 요약을 맡기려고 붙여 넣은 계약서. 분류를 요청한 고객 이메일, 그 안의 고객 정보까지. 진단서, 연봉 수치, 초안 작성 중이던 사직서, 공개되지 않은 저장소의 코드. 그리고 그 주변의 메타데이터: 어떤 질문을, 어떤 순서로, 몇 시에, 어느 주소에서, 몇 달에 걸쳐 했는지. “이것이 우리의 전략입니다”라고 서명하는 문서는 아무도 만들지 않지만, 그 질문들의 연쇄가 바로 그 문서입니다. 당신이, 한 번에 한 통씩, 정직하게 조립한 것입니다.

1계층 — 엔드포인트가 보관하는 것. 제대로 된 업체는 제대로 된 정책을 공개하며, 훌륭한 업체는 실제로 비즈니스 API 트래픽으로 학습하지 않습니다. 하지만 이는 보관하지 않는다는 약속과는 다릅니다. 요청은 보통 남용 감시를 위해 일정 기간 저장되고, 정해진 조건 아래 직원이 열람할 수 있으며, 법적 절차에 따라 제출될 수 있습니다 — 이는 대형 플랫폼을 운영하는 데는 정확히 옳은 방식이지만, 낯선 사람에게 이메일로 보내지 않을 텍스트를 두기에는 정확히 잘못된 곳입니다. 자신의 머신에 있는 모델은 직접 기록을 남기지 않는 한 그런 로그를 갖지 않습니다.

2계층 — 로그와 연결되는 신원. 보관 그 자체는 노출의 절반에 불과합니다. 나머지 절반은 그것이 연결되는 열쇠입니다. 계정, 회사명, 청구 주소, 카드. 그 연결이 “누군가 경쟁사 인수에 대해 물었다”를 “이 회사가, 그 화요일에 물었다”로 바꿔 놓습니다. 방정식에서 모델을 빼면 보관이 사라지고, 머신에서 신원을 빼면 그 연결이 사라집니다. 이메일 주소도 신분증도 없이, 노르딕 관할권에서, Monero로 결제해 개설한 VPS는 바로 같은 조치의 나머지 절반입니다.

3계층 — 직접 작성하는 로그. 셀프호스팅은 위험을 없애는 것이 아니라 옮길 뿐이며, 그것이 어디에 떨어지는지 명확히 알아 둘 가치가 있습니다. 당신의 애플리케이션은 아마 자체적으로 프롬프트를 기록할 것입니다. 리버스 프록시는 모든 요청 줄을 기록합니다. 두 달 전 디버깅 세션이 저널에 장황한 출력을 남겨 두었을 수도 있습니다. 모델 자체는 호출 사이에 아무것도 유지하지 않지만, 그 주변 장치는 모든 것을 유지할 수 있습니다 — 그러니 무엇을 기록할지 의도적으로 정하고, 보관 기간을 설정하고, 다른 누군가에게는 용납하지 않았을 기준으로 그 로그를 관리하십시오.

이 중 어느 것도 로컬 모델 자체를 프라이버시 보장으로 만들어 주지는 않습니다. 다만 이는 그 보장을 당신 스스로 부여할 수 있는 유일한 구조로 만들어 줍니다. 텍스트는 당신이 임대한 하드웨어에, 당신이 선택한 관할권 아래, 당신이 발급한 토큰 뒤에 머무르며, 그 밖의 무엇에도 답할 필요가 없습니다.

현장 노트 · 여섯 가지 함정

이것이 사람들을 실망시키는 여섯 가지 방식. 그중 다섯 가지는 피할 수 있습니다.

함정 01 · 메모리

느려지는 대신 서버가 멈춰 버림

모델과 컨텍스트 캐시를 합친 크기가 RAM을 초과해, 커널이 토큰마다 가중치를 페이징하기 시작함. 메모리에 맞추거나 한 단계 작은 크기로 내리십시오 — 중간 설정은 없습니다.

함정 02 · 노출

누군가 다른 사람이 당신의 CPU를 쓰고 있었음

클라이언트를 작동시키려고 OLLAMA_HOST를 0.0.0.0으로 설정함. API에는 인증이 전혀 없고, 11434는 스캔당함. 해법: 루프백과 토큰을 확인하는 프록시.

함정 03 · 기대

작동은 하지만, 팩스처럼 느리게 타자를 침

대화형 어시스턴트에 32B 모델을 선택했습니다. 크기는 상호작용 방식에 맞추십시오. 대화형은 작은 모델을, 품질은 비동기 처리를 원합니다.

함정 04 · 컨텍스트

첫 요청은 멀쩡했지만, 열 번째는 기어감

대화가 길어질수록 캐시도 커지며, 매 턴마다 전체 기록을 다시 읽습니다. 컨텍스트에 상한을 두고, 끝없이 이어 붙이는 대신 새 대화를 시작하십시오.

함정 05 · 상주

5기가바이트가 사라졌는데 아무것도 실행 중이 아님

모델은 설계상 마지막 호출 이후에도 상주 상태를 유지합니다. OLLAMA_KEEP_ALIVE를 서버 사정에 맞게 설정하고, 다른 무언가를 탓하기 전에 ollama ps부터 확인하십시오.

함정 06 · 디스크

한 번 비교해 본 모델들로 디스크가 가득 참

각각 5기가바이트인 후보 네 개, 하나도 지우지 않음. ollama rm을 비교 과정의 일부로 삼고, 디스크 경고가 뜨면 모델 디렉터리를 확인하십시오.

자주 묻는 질문 · 로컬 모델

질문들, 답변됨.

CPU 전용 모델이 지금 염두에 둔 작업에 알맞은 도구인지 판가름하는 열 가지 질문.

정말로 GPU 없이 LLM을 구동할 수 있을까요?

네, 다만 속도에 관해 솔직히 짚어 둘 점이 하나 있습니다. 양자화된 모델은 평범한 서버 CPU에서도 완벽하게 잘 돌아갑니다 — 가중치는 RAM에 놓이고, 연산량은 충분히 감당할 수 있는 수준이며, 이 과정 어디에도 그래픽카드가 필요한 부분은 없습니다. GPU가 사 주는 것은 메모리 대역폭이고, 생성 속도를 결정하는 것이 바로 그 대역폭입니다. 그래서 CPU 전용 서버는 모델에 따라 초당 몇 단어에서 몇십 단어 사이의 속도로, 정확하고 완전하게 답합니다. 이는 채팅창으로는 느리지만, 대부분의 사람이 실제로 자동화하는 작업 — 메시지 분류, 문서에서 구조화된 JSON 뽑아내기, 페이지 요약, 검색용 텍스트 임베딩, 문단 다시 쓰기 — 에는 전혀 문제가 없습니다. 질문은 “할 수 있는가”가 아니라, 언제나 “어느 속도로, 그리고 그 속도가 이 작업에 중요한가”입니다.

초당 토큰 수는 어느 정도로 기대해야 할까요?

저희 것을 포함해 누구의 벤치마크도 믿지 말고, 직접 산술을 해 보십시오. 덴스 모델은 토큰 하나를 만들기 위해 자신의 가중치 전부를 메모리에서 읽으므로, 상한은 대략 메모리 대역폭을 모델 크기로 나눈 값입니다. 약 2GB로 양자화된 3B 모델은 실효 대역폭 20GB/s인 머신에서 상한이 초당 약 10토큰에 가깝고, 4.4GB인 7B는 약 4.5, 20GB인 32B는 1 미만입니다. 실제 수치는 상한 아래에 자리 잡습니다 — 대략 50~70퍼센트 정도로 보십시오 — 그리고 호스트, 이웃 인스턴스, 스레드 수에 따라 달라집니다. 프롬프트 처리는 완전히 다른 문제입니다. 이는 연산 집약적이라 훨씬 더 빠르게 실행되며, 그래서 긴 문서를 요약하는 것은 편안한 반면 큰 모델과 대화하는 것은 그렇지 않은 이유입니다.

8GB에서는 어떤 모델부터 시작해야 할까요?

Q4_K_M 기준 8B급 인스트럭트 모델은 약 4.5~5GB에 자리 잡아 운영체제와 컨텍스트 캐시가 들어갈 여유를 남깁니다. 이 크기가 현재의 최적점입니다. 지시를 안정적으로 따르고, 요청 시 유효한 JSON을 만들고, 요약·분류·재작성을 할 만큼 충분히 좋으면서도 반응성을 유지할 만큼 충분히 작습니다. 그 아래로는 3B 모델이 분류·태깅·라우팅에 실제로 유용하며 속도는 대략 두 배입니다. 그 위로는 14B가 다단계 추론에서 눈에 띄게 낫지만 속도는 대략 절반이며, 이는 배치 작업에는 합리적인 거래이지만 대화형 작업에는 좋지 않은 거래입니다. 8B에서 시작해 측정한 뒤, 측정치가 가리키는 방향으로 옮기십시오.

모델에는 실제로 RAM이 얼마나 필요할까요?

양자화된 파일 크기에, 컨텍스트 캐시를 더하고, 시스템을 위한 여유까지 더한 값 — 그 합계가 반드시 맞아야 합니다. 실패 양상이 느려짐이 아니라 붕괴이기 때문입니다. 모델이 맞지 않으면 커널이 모델 가중치를 디스크로 스와핑하기 시작하고, 4초면 될 생성이 4분이 걸리며 부하 평균은 수십까지 치솟습니다. Q4_K_M 기준 실무 규칙: 3B 모델은 약 2GB, 8B는 약 5GB, 14B는 약 9GB, 32B는 약 20GB, 70B는 약 40GB입니다. Debian과 그 서비스를 위해 2기가바이트를 더하고, 허용하는 컨텍스트 길이에 따라 키-값 캐시를 위해 1~4기가바이트를 더 더하십시오. 그런 다음 답에 정확히 맞는 등급이 아니라 그보다 한 단계 위의 등급을 사십시오.

Ollama와 llama.cpp, 어느 것을 써야 할까요?

Ollama는 사실상 llama.cpp에 모델 레지스트리, REST API, systemd 서비스를 감싼 것입니다. 특별한 이유가 없다면 Ollama를 쓰십시오. 설치 명령 한 줄, GGUF 파일을 찾아 헤매는 대신 쓰는 ollama pull, OpenAI 호환 엔드포인트, 스레드 수와 메모리에 대한 합리적인 기본값까지 갖추고 있습니다. Ollama가 노출하지 않는 플래그가 필요하거나, 재현성을 위해 정확한 빌드를 고정하고 싶거나, 하나의 모델을 하나의 설정으로 영원히 돌리면서 데몬이 아무것도 관리하지 않기를 바랄 때는 llama.cpp를 직접 쓰십시오. 둘 다 같은 가중치를 같은 속도로 실행합니다. 차이는 전적으로 운영 방식에 있습니다.

셀프호스팅한 모델이 대형 호스팅 모델만큼 좋을까요?

아닙니다. 그렇다고 여기는 것은 당신의 오후를 낭비하는 일입니다. API 뒤에 있는 프런티어 모델은 가상 머신에 들어갈 수 있는 그 무엇보다도 크고, 어려운 추론·긴 컨텍스트·코드에서 더 낫습니다. 작은 로컬 모델이 진짜로 경쟁력을 갖는 지점은 실제 업무의 거대한 중간 지대입니다. 이메일이 여섯 범주 중 어디에 속하는지 판단하기, 청구서에서 다섯 필드를 추출하기, 지원 스레드를 요약하기, 설명 문구를 다시 쓰기, 문서에 태그를 달기, 두 레코드가 같은 사람인지 판별하기. 이런 부류의 작업에서는 8B와 프런티어 모델의 격차가 작은 반면 비용 차이는 압도적이고 프라이버시 차이는 절대적입니다. 생산적인 태도는 “API를 대체하자”가 아니라 “애초에 나갈 필요가 없었던 90퍼센트를 그만 보내자”입니다.

Ollama에는 인증 기능이 있나요?

아니요 — 전혀 없습니다. 이것이 이 가이드에서 가장 중요한 운영상의 사실입니다. 비밀번호도, 토큰도, 사용자 모델도 없습니다. 포트 11434로 TCP 연결을 열 수 있는 무엇이든 텍스트를 생성하고, 보유한 모델 목록을 조회하고, 새 모델을 내려받고, 기존 모델을 삭제할 수 있습니다. 이 포트는 상시로 스캔되며, 보호되지 않은 인스턴스는 발견되어 낯선 이들의 무료 연산 자원으로 쓰이는데, 처음에는 알 수 없는 부하 평균으로, 나중에는 대역폭 청구서로 나타납니다. Ollama를 127.0.0.1에 바인딩하고, 그 앞에 리버스 프록시를 두고, 그곳에서 TLS를 종료하고, 프록시 단계에서 베어러 토큰이나 클라이언트 인증서를 요구하십시오. 이 서버 바깥에서 모델을 필요로 하는 것이 아무것도 없다면, 아예 노출하지 마십시오.

n8n이나 에이전트 런타임에서 로컬 모델을 쓸 수 있나요?

네, 그리고 보통 필드 하나만 바꾸면 됩니다. Ollama는 /v1에서 OpenAI 호환 API를 제공하므로, 기본 URL을 지정할 수 있는 클라이언트라면 무엇이든 — OpenAI SDK, LangChain, n8n의 OpenAI 노드, 대부분의 에이전트 프레임워크 — https://your-host/v1을 가리키고 키에는 비어 있지 않은 문자열을 아무거나 넣기만 하면 연결됩니다. n8n은 전용 Ollama 노드도 제공합니다. 실전에서 잘 통하는 패턴은 하이브리드입니다. 대량의 지루한 호출은 로컬 모델로 보내고, 진짜로 프런티어 수준의 추론이 필요한 소수의 단계만 호스팅형 API를 위해 남겨 두며, 로컬 모델이 유효한 JSON을 만들어내지 못할 때를 대비한 대체 경로를 두십시오.

CPU에서의 임베딩, 그럴 만한 가치가 있을까요?

이것은 이 페이지 전체에서 가성비가 가장 뛰어난 부분입니다. 임베딩 모델은 아주 작아서 — 기가바이트가 아니라 수십~수백 메가바이트 단위입니다 — 토큰 단위 생성 없이 청크당 한 번의 순전파만 실행하므로, CPU가 거뜬히 처리합니다. 즉 RAG 시스템에서 검색을 담당하는 절반 — 문서를 색인하고, 질의를 임베딩하고, 가장 가까운 청크를 찾는 일 — 은 가장 저렴한 등급에서도 무리 없이 돌아가며, 동시에 이는 당신이 가진 모든 문서를 건드리는 절반이기도 합니다. 생성 단계는 호스팅형 API에 맡기기로 하더라도, 임베딩 단계를 자신의 머신으로 옮기면 말뭉치가 다른 누군가의 손에 들어가지 않게 지킬 수 있습니다.

API가 더 빠르고 저렴한데, 왜 굳이 모델을 셀프호스팅해야 할까요?

중요도가 커지는 순서로 세 가지 이유가 있습니다. 비용에는 형태가 있습니다. API는 어느 지점까지는 저렴하지만 그 이후로는 아닙니다. 매달 5만 개의 메시지를 분류하는 워크플로는 청구서가 계속 커지는 반면, $7.90짜리 VPS는 그렇지 않습니다. 가용성: 속도 제한도 없고, 기반으로 삼은 모델이 단종되는 일도 없고, 남의 상태 페이지에 뜨는 장애도 없습니다. 그리고 결정적인 이유 — 당신의 프롬프트는 당신이 만들어내는 가장 많은 것을 드러내는 텍스트입니다. 답이 아니라 질문입니다. 무엇을, 누구에 대해, 어느 날, 어떤 순서로 물었는지. 호스팅형 엔드포인트는 그 전부를 청구 신원과 연결해서 봅니다. 신분증 없이, 노르딕 관할권에서, Monero로 결제해 빌린 머신에서 돌아가는 모델은 같은 텍스트를 보되 아무에게도 보고하지 않습니다.

서버를 확보하십시오

오직 당신에게만 응답하는 모델을 위한 노르딕 VPS. KYC 없음, 암호화폐 결제.

Garrison(4 vCPU, 8 GB, 240 GB NVMe, $7.90/월)은 컨텍스트 캐시와 시스템을 위한 여유를 남기고 8B 모델을 구동합니다 — 대부분이 시작해야 할 등급입니다. Ravelin은 메모리를 두 배로 늘려 14B와 긴 컨텍스트를 지원합니다. 가입 시 이메일 불필요, 신분증 불필요, 토큰당 과금 없음.

마지막 검토일 · 2026-08-24 · 출처 · Ollama 문서 및 API 레퍼런스, llama.cpp 문서, Caddy 리버스 프록시 문서, 참조한 양자화 빌드의 공개 모델 카드 · 주기 · 연간