SSD Nodes Learn
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-07-24

VPS에 Ollama 설치하여 LLM 구축하는 방법

VPS에서 Ollama를 사용하여 LLM을 안전하게 호스팅하는 방법을 설명합니다. 7B 모델 기준 8 GB RAM이 필요하며 CPU 사용 시 초당 4~10 tokens가 생성됩니다. 포트 11434를 폐쇄하여 보안을 유지하는 법을 확인하세요.

구축 목표

사용자 소유의 서버에서 실행되는 단일 open-weight 언어 모델을 구축합니다. 이 모델은 HTTP API를 통해 응답하며, 필요에 따라 브라우저의 채팅 페이지를 통해 사용할 수 있습니다. Ollama는 모델을 다운로드하고, 메모리에 로드하며, http://127.0.0.1:11434에서 요청을 처리하는 역할을 합니다. 설치는 명령어 하나로 완료됩니다. 기술적으로 어려운 부분은 다른 영역에 있습니다. VPS의 RAM 용량에 맞는 모델을 선택하는 것과, 인증되지 않은 추론 서버를 인터넷 전체에 실수로 공개하지 않는 것입니다.

두 가지 주의 사항을 먼저 전달합니다. CPU 전용 VPS는 소형 모델도 느리게 실행됩니다. 또한 API에는 기본 인증 기능이 전혀 포함되어 있지 않습니다. 이 두 가지 사항은 발생 시 문제가 될 수 있으므로 아래에서 자세히 다룹니다.

수치로 확인하는 실제 크기 산정

모델의 메모리 점유율은 대략 파일 크기에 런타임 오버헤드 약 1 GB를 더한 값이며, 여기에 컨텍스트 윈도우를 위한 추가 메모리가 필요합니다. Ollama의 기본 모델은 4-bit 양자화(Q4로 표시됨) 모델입니다. 이 경우 파라미터 10억 개당 약 0.5 GB의 RAM이 소모됩니다. 따라서 계산 방식은 단순하며, 이것이 모든 것을 결정합니다.

llama3.2:3b와 같은 3B 모델은 다운로드 크기가 약 2 GB이며, 실행을 위해 약 4 GB의 여유 RAM이 필요합니다. mistral:7b 또는 llama3.1:8b와 같은 7B 또는 8B 모델은 디스크 용량이 약 5 GB이며, 약 8 GB의 RAM이 필요합니다. 원활한 실행을 위해서는 16 GB가 필요합니다. 13B 또는 14B 모델은 약 16 GB를 요구합니다. 30B에서 70B 사이의 모델은 대용량 RAM을 갖춘 시스템 또는 현실적으로 GPU가 필요합니다. CPU 기반 VPS에서는 메모리가 부족하거나 응답 속도가 너무 느려 사용이 불가능합니다.

다음은 사람들이 과소평가하는 속도에 관한 내용입니다. CPU 추론은 클럭 속도가 아닌 메모리 대역폭에 의해 제한됩니다. 공유 vCPU VPS는 대역폭이 낮습니다. 초당 토큰 생성량(tokens per second)은 한 자릿수에서 낮은 두 자릿수 정도를 예상하십시오. 7-8B Q4 모델은 초당 4~10 토큰, 3B 모델은 10~25 토큰을 생성할 수 있습니다. GPU는 이보다 대략 10배 정도 빠릅니다. 이 수치들은 대략적인 값입니다. 가장 정확한 방법은 실제 시스템에서 직접 측정하는 것이며, 아래의 실행 단계에서 그 방법을 설명합니다. 이 문서를 포함하여 그 어떤 문서의 수치보다 본인의 eval rate를 신뢰하십시오.

실질적인 결론은 다음과 같습니다. 속도를 수용할 수 있다면 CPU 기반의 소형 양자화 모델은 초안 작성, 요약, 분류 작업에 실제로 유용합니다. 그 이상의 크기나 속도가 필요하다면 GPU 인스턴스를 고려하십시오.

특정 모델과 특정 시스템을 비교하려면, 아래에서 메모리 점유율을 추정하십시오:

ToolLLM VRAM and model-size calculator

Ollama 설치

두 가지 깔끔한 방법이 있습니다. 베어 VPS 환경에서는 공식 스크립트를 사용하는 것이 가장 간단합니다:

curl -fsSL https://ollama.com/install.sh | sh

이 스크립트는 ollama이라는 이름의 system user를 생성합니다. 바이너리는 /usr/local/bin/ollama에 설치됩니다. 또한 부팅 시 시작되고 127.0.0.1:11434을 바인딩하는 ollama.service systemd service를 등록합니다. 실행 여부를 확인하십시오:

systemctl status ollama
ollama --version

이미 Docker를 사용 중이라면 컨테이너를 사용하십시오:

docker run -d --name ollama \
  -p 127.0.0.1:11434:11434 \
  -v ollama:/root/.ollama \
  --restart always \
  ollama/ollama

포트 매핑의 127.0.0.1: 접두사에 주의하십시오. 이 설정은 포트를 localhost에만 바인딩합니다. -p 11434:11434를 사용하면 모든 인터페이스에 포트가 공개됩니다. 이는 보안 섹션에서 경고하는 실수입니다. 한 가지 설치 방법만 선택하십시오. 스크립트와 컨테이너를 동시에 실행하면 두 프로세스가 포트를 점유하기 위해 충돌합니다.

첫 번째 모델을 pull하고 실행하기

ollama pull llama3.2:3b
ollama run llama3.2:3b

pull이 모델 레이어를 디스크에 다운로드합니다 (이 모델은 약 2 GB입니다). run이 모델을 메모리에 로드하고 >>> 프롬프트를 실행합니다. 질문을 입력하십시오. 가중치가 디스크에서 RAM으로 로드되는 동안 첫 번째 토큰 생성에 몇 초가 걸릴 수 있으며, 이후 답변이 스트리밍됩니다. 채팅을 종료하려면 /bye를 입력하십시오. Ollama는 백그라운드에서 계속 실행됩니다.

로드된 상태와 메모리 점유율을 확인하십시오:

ollama ps

PROCESSOR 열을 통해 실제 상태를 확인할 수 있습니다. 100% CPU은 GPU를 사용하지 않음을 의미하며, 이것이 속도가 느려지는 원인입니다. verbose flag를 사용하여 실제 속도를 측정하십시오:

ollama run --verbose llama3.2:3b "Write two sentences about Linux."

마지막에 출력되는 eval rate 라인은 해당 하드웨어에서의 초당 토큰 수(tokens per second)입니다. 이 수치를 기준으로 계획을 세우십시오.

모델 저장 위치 및 권장 디스크 용량

스크립트로 설치하여 서비스로 실행하는 경우, 모델은 ollama 사용자의 홈 디렉토리에 저장됩니다:

sudo du -sh /usr/share/ollama/.ollama/models

사용자 계정으로 대화형 실행을 하는 경우, 모델은 ~/.ollama/models에 저장됩니다. 컨테이너 환경에서는 ollama 이름의 volume에 저장됩니다. 양자화된 가중치는 용량이 빠르게 증가하므로 주의해야 합니다. 3B 모델은 약 2 GB, 7-8B 모델은 약 5 GB, 14B 모델은 약 9 GB를 차지합니다. 모델 4개를 다운로드하여 비교하면 인지하지 못한 사이에 20 GB를 사용하게 됩니다. 유지할 모델의 개수에 맞춰 디스크 크기를 결정하고, 나머지 모델은 ollama rm <model>를 사용하여 삭제하십시오.

제어 가능한 서비스로 실행하기

설치 스크립트가 이미 ollama.service을(를) 등록했으므로, 추가 작업 없이도 부팅 시 자동으로 재시작됩니다. 변경이 필요한 설정은 모델 유지 시간과 일부 환경에서의 bind address입니다. Ollama 업그레이드 시 설정이 덮어씌워지는 것을 방지하기 위해, 두 설정 모두 systemd drop-in 파일에 작성해야 합니다:

sudo systemctl edit ollama.service

에디터에 표시되는 [Service] 헤더 아래에 다음 내용을 추가하십시오:

[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"

OLLAMA_KEEP_ALIVE는 마지막 요청 후 모델이 메모리에 머무는 시간입니다(기본값 5분). 하루 종일 쿼리를 보내는 서버에서는 매번 가중치를 다시 로드하는 것을 방지하기 위해 이 값을 높이십시오. 자원이 부족한 서버에서는 요청이 끝나자마자 RAM을 확보할 수 있도록 0으로 설정하십시오. systemctl edit을(를) 실행하면 unit 파일이 다시 로드됩니다. 변경 사항을 적용하려면 재시작하십시오:

sudo systemctl restart ollama

가장 중요한 보안 사항

기본적으로 Ollama는 127.0.0.1:11434에 바인딩되므로 VPS 내부의 프로세스만 접근할 수 있습니다. 이 기본 설정은 올바릅니다. 그대로 유지하십시오.

API에는 인증 기능이 없습니다. 전혀 없습니다. API key, 로그인, rate limit, allow-list가 존재하지 않습니다. 11434 포트에 접근할 수 있는 사용자라면 누구나 사용자가 pull한 모든 모델을 실행하고, 새로운 모델을 pull하거나 삭제할 수 있으며, CPU 또는 GPU를 무한히 풀 로드로 점유할 수 있습니다. Shodan과 같은 스캐너는 수천 개의 공개된 Ollama 인스턴스를 인덱싱하며, 노출된 인스턴스는 몇 시간 내에 발견되어 악용됩니다.

따라서 절대 해서는 안 될 단 하나의 실수는 다음과 같습니다. OLLAMA_HOST=0.0.0.0을 설정하고 방화벽에서 11434 포트를 개방하지 마십시오. 이는 인증되지 않은 추론 서버를 인터넷 전체에 공개하는 것입니다. 0.0.0.0에서 11434 포트를 직접 개방하는 것은 어떤 설정으로도 안전하게 만들 수 없습니다. Ollama에는 설정할 인증 기능 자체가 존재하지 않기 때문입니다.

서버 외부에서 모델에 접근하는 안전한 방법은 세 가지가 있습니다.

  • 로컬로 유지하십시오. 호출자가 동일한 VPS의 다른 프로그램(cron script, bot, 도구와 모델을 연결하는 MCP server)인 경우, 바인딩을 127.0.0.1로 유지하고 해당 프로그램이 http://127.0.0.1:11434을 호출하도록 하십시오. 외부로 노출되는 것이 없으며 추가 설정도 필요하지 않습니다.
  • 프라이빗 터널을 통해 접근하십시오. VPS를 직접 호스팅하는 WireGuard VPN에 연결하고, OLLAMA_HOST을 터널 주소(예: 10.8.0.1, 0.0.0.0 아님)로 설정하십시오. 그러면 VPN 피어만 연결할 수 있습니다. 공용 인터넷에서는 11434 포트가 여전히 보이지 않습니다.
  • 인증 기능이 있는 리버스 프록시를 앞에 배치하십시오. nginx, Traefik 또는 Caddy에서 TLS를 종료하고 비밀번호나 토큰을 요구하도록 설정한 다음, 127.0.0.1:11434으로 프록시를 전달하십시오. Ollama는 localhost 바인딩을 유지하며, 프록시만 공용 포트에서 대기합니다. 이는 로컬 서비스 앞에 nginx에 Let's Encrypt 인증서를 배치하는 방식과 동일합니다.

리버스 프록시 옵션은 다음에 설명할 실제 로그인이 포함된 chat UI가 제공하는 방식과 정확히 일치합니다.

TLS를 적용한 Open WebUI 채팅 UI 추가

Open WebUI는 자체 호스팅 방식의 채팅 인터페이스입니다. Docker로 실행하고 로컬 Ollama를 가리키도록 설정하십시오.

docker run -d \
  --name open-webui \
  --network=host \
  -e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
  -v open-webui:/app/backend/data \
  --restart always \
  ghcr.io/open-webui/open-webui:main

Linux VPS에서는 --network=host flag가 중요합니다. 이 flag는 컨테이너를 호스트의 network namespace에 배치합니다. 따라서 컨테이너 내부의 127.0.0.1는 호스트의 loopback이 되며, Ollama가 다른 interface에서 대기하지 않아도 컨테이너가 127.0.0.1:11434를 통해 Ollama에 접속할 수 있습니다. 다른 곳에서 볼 수 있는 bridge-network 방식인 --add-host=host.docker.internal:host-gatewayOLLAMA_BASE_URL=http://host.docker.internal:11434 조합은 여기에서 작동하지 않습니다. 해당 이름은 Docker bridge gateway로 해석됩니다. 호스트의 127.0.0.1에 바인딩된 service는 bridge를 통해 도달할 수 없으므로, Open WebUI는 Ollama에 연결할 수 없다는 오류를 출력합니다.

host networking을 사용하면 Open WebUI가 모든 interface의 호스트 port 8080에서 대기하게 됩니다. 모든 -p mapping은 무시되며, Docker는 이에 대한 warning을 출력합니다. 따라서 호스트와 provider firewall 모두에서 8080를 닫고, TLS reverse proxy만 공용 통로로 사용하십시오. 처음 접속 시 Open WebUI는 admin account 생성을 요청합니다. 이 account가 인증 계층 역할을 하므로 강력한 password를 설정하십시오.

노트북에서 HTTPS를 통해 채팅을 이용하려면 127.0.0.1:8080 앞에 TLS reverse proxy를 배치하십시오. 이미 서버에서 여러 Docker app을 라우팅 중이라면 여러 app에 자동 TLS를 적용하는 Traefik 방식이 가장 적합합니다. 하나의 label block으로 certificate를 발급하고 chat.example.com를 Open WebUI로 라우팅할 수 있습니다. 보안 섹션의 규칙은 동일하게 적용됩니다. proxy가 public port와 login을 담당하며, Ollama는 localhost에 머물고 Open WebUI의 8080는 firewall로 보호됩니다.

코드에서 OpenAI 호환 엔드포인트 사용하기

Ollama는 /v1에서 OpenAI chat API의 일부를 지원합니다. 따라서 base URL과 임의의 key로 두 가지를 변경하면 대부분의 OpenAI client library를 사용할 수 있습니다.

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")

resp = client.chat.completions.create(
    model="llama3.2:3b",
    messages=[{"role": "user", "content": "Name three Linux distributions."}],
)
print(resp.choices[0].message.content)

api_key는 client library에서 요구하지만 Ollama는 이를 무시하므로 아무 문자열이나 입력하면 됩니다. model는 이미 pull한 모델 이름이어야 합니다. 알 수 없는 이름을 입력하면 model "x" not found, try pulling it first 오류가 발생합니다. curl 명령어를 사용하는 방식도 동일합니다.

curl http://127.0.0.1:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"llama3.2:3b","messages":[{"role":"user","content":"Hello"}]}'

이 방식은 모델을 agent 및 editor 도구에 연결할 때도 사용됩니다. 로컬 환경에서 개발 중이라면, tmux 내부 VPS에서 실행되는 Claude Code와 함께 로컬 모델을 스크립트 및 플러그인용으로 사용할 수 있습니다. 이를 통해 비용이 저렴하고 개인적인 초안 작성 작업은 로컬에서 처리하고, 복잡한 추론 작업은 호스팅된 모델을 사용하도록 분리할 수 있습니다.

Failure modes, with the exact strings you will see

생성 도중 프로세스가 "Killed"됩니다. 대규모 모델을 실행하는 중 터미널에 Killed이(가) 출력되거나 서버 로그에 llama runner process has terminated: signal: killed이(가) 나타납니다. 모델이 시스템의 RAM 용량보다 더 많은 메모리를 요구하여 Linux OOM killer가 프로세스를 중단시킨 것입니다. sudo dmesg | grep -i oom를 사용하여 원인을 확인하십시오. Out of memory: Killed process ... (ollama)과 같은 라인이 표시됩니다. 해결 방법은 더 작거나 양자화(quantized)가 더 많이 된 모델을 사용하는 것입니다. 예를 들어 13B 대신 llama3.2:3b을(를) 사용하십시오. 또는 swap을 추가하여 물리 RAM을 약간 초과하는 로드가 종료되지 않고 느리게나마 완료되도록 할 수 있습니다. swap은 즉각적인 충돌을 느린 응답으로 전환할 뿐, 4 GB 메모리에서 70B 모델을 실용적으로 만들어주지는 않습니다.

"Error: model requires more system memory". Ollama가 모델 실행을 거부하고 Error: model requires more system memory (X GiB) than is available (Y GiB)을(를) 출력합니다. 이는 앞서 언급한 충돌의 완곡한 표현입니다. Ollama가 계산을 수행한 결과, OOM killer가 개입하기 전에 스스로 중단한 것입니다. Ollama는 필요한 메모리 수치 두 개를 함께 제공합니다. 사용 가능한 RAM 용량보다 요구 사양이 낮은 모델을 선택하십시오(free -h으로 확인). 또는 context length를 줄이거나 더 큰 VPS로 이동하십시오. 어떤 flag를 사용해도 모델을 메모리에 맞출 수는 없습니다. 메모리 용량은 물리적인 한계입니다.

첫 번째 token 생성에 시간이 매우 오래 걸린 후 정상적으로 작동합니다. 모델이 처음 로드될 때 5초에서 30초 동안 아무것도 출력되지 않다가 스트리밍이 시작됩니다. 이 지연은 디스크에서 RAM으로 가중치(weights)를 처음 로드하는 과정이며, 저장 장치의 속도가 느릴수록 심해집니다. 로드가 완료되면 모델은 OLLAMA_KEEP_ALIVE 동안 메모리에 상주하므로 두 번째 프롬프트부터는 즉시 응답합니다. 지연 시간이 불편하다면 해당 값을 높이십시오. 모델이 현재 로드되어 있는지 확인하려면 ollama ps을(를) 사용하십시오.

모든 동작이 단순히 느립니다. 오류는 없으나 초당 10개 이하의 token이 생성됩니다. 이는 CPU inference가 작동하는 일반적인 방식입니다. ollama ps100% CPU이(가) 표시되면 GPU가 없음을 의미합니다. 이는 버그가 아니며 설정으로 해결할 수 없습니다. 제한 사항은 설정 오류가 아니라 메모리 대역폭이기 때문입니다. 더 작은 모델을 사용하거나, 속도를 수용하거나, GPU 인스턴스로 이동하십시오. 문제가 있다고 판단하기 전에 --verbose으로 실제 생성 속도를 측정하십시오.

다른 머신에서 Connection refused 오류가 발생합니다. 노트북에서 curl: (7) Failed to connect to <ip> port 11434: Connection refused이(가) 발생합니다. 이는 의도된 동작입니다. Ollama는 localhost에만 바인딩됩니다. 0.0.0.0으로 바인딩하여 이를 "해결"하려고 하지 마십시오. 이는 보안 노출을 초래하는 실수입니다. 대신 VPN 또는 인증 프록시를 통해 모델에 접속하십시오.

11434 포트를 인터넷에 노출했습니다. 만약 OLLAMA_HOST=0.0.0.0을(를) 설정하고 방화벽을 열어, 실행하지 않은 모델 pull이 발생하거나 알 수 없는 클라이언트에 의해 CPU 점유율이 100%가 된다면, 공격자가 시스템을 발견하여 사용 중인 것입니다. 이는 예외적인 사례가 아니라 가장 대표적인 실수입니다. 127.0.0.1 또는 VPN 주소로 다시 바인딩하고, 방화벽에서 11434 포트를 닫은 뒤, 앞에 인증 레이어를 배치하십시오. 포트가 열려 있는 동안 해당 주소로 접근 가능한 모든 요청은 외부인에 의해 수행된 것으로 간주해야 합니다.

Backups and upgrades

손실될 상태 데이터는 거의 없습니다. 모델은 다시 다운로드할 수 있습니다. 따라서 백업이 필요한 항목은 Open WebUI의 data volume(계정, 채팅 기록, 설정)과 직접 작성한 systemd drop-in 파일뿐입니다. 임시 컨테이너를 사용하여 volume을 백업하십시오:

docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
  tar czf /backup/open-webui.tgz -C /data .

설치 스크립트를 다시 실행하여 Ollama를 업그레이드하십시오. Open WebUI는 docker pull ghcr.io/open-webui/open-webui:main를 실행한 후 컨테이너를 다시 생성하여 업그레이드합니다. 특정 버전을 장기간 고정하지 마십시오. 모델 품질과 런타임 모두 빠르게 변화합니다. 지난 분기 수치를 신뢰하기보다 릴리스 노트를 확인하고 사용자의 장비에서 직접 벤치마크를 다시 수행하십시오.

FAQ

CPU만 있는 VPS에서 LLM을 실행할 수 있습니까?

제한적이지만 가능합니다. 3B에서 8B 범위의 작은 양자화 모델은 CPU에서 실행 가능하며 초안 작성, 요약, 분류 작업에 유용합니다. 다만 공유 vCPU 환경에서는 초당 1~10개 내외의 낮은 토큰 생성 속도를 보입니다. 13B 이상의 모델은 속도가 매우 느리거나 RAM 용량이 부족하여 실행되지 않을 수 있습니다. 빠른 속도나 대규모 모델이 필요하면 GPU 인스턴스를 사용해야 합니다.

모델마다 RAM이 얼마나 필요합니까?

기본 4-bit 양자화 모델의 대략적인 기준은 다음과 같습니다. 파라미터 10억 개당 약 0.5 GB의 RAM이 가중치 저장에 필요하며, 약 1 GB의 오버헤드와 컨텍스트를 위한 추가 여유 공간이 필요합니다. 따라서 3B 모델은 약 4 GB, 7-8B 모델은 약 8 GB, 14B 모델은 약 16 GB의 여유 RAM이 필요합니다. free -h를 사용하여 여유 공간을 확인하고 운영 체제 및 기타 프로세스를 위한 공간을 확보하십시오.

Ollama API에 인증 기능이 있습니까?

아니요. Ollama에는 내장된 인증, API key 또는 rate limit 기능이 없습니다. port 11434에 접근할 수 있는 사용자라면 누구나 모든 권한을 가집니다. 이 때문에 Ollama는 기본적으로 127.0.0.1에 바인딩되며, 0.0.0.0에서 11434 포트를 인터넷에 노출해서는 안 됩니다. 로컬에서 접속하거나, 프라이빗 VPN을 사용하거나, 로그인을 지원하는 reverse proxy를 통해 접속하십시오.

웹 채팅 인터페이스를 어떻게 추가합니까?

--network=host를 사용하여 Docker에서 Open WebUI를 실행하십시오. 이렇게 하면 호스트의 loopback을 공유하여 http://127.0.0.1:11434에 있는 Ollama에 접근할 수 있습니다. 그 다음, 노트북에서 접속할 수 있도록 port 8080 앞에 TLS reverse proxy를 설정하십시오. 방화벽에서 8080를 차단하여 proxy를 통해서만 외부 접속이 가능하도록 설정해야 합니다. Open WebUI 자체 관리자 계정으로 로그인하며, 첫 실행 시 비밀번호를 설정합니다.

자신의 애플리케이션에서 어떻게 호출합니까?

http://127.0.0.1:11434/v1에 있는 OpenAI 호환 엔드포인트를 사용하십시오. OpenAI SDK의 base URL을 해당 주소로 지정하고, API key에는 무시되는 임의의 문자열을 입력하십시오. 그리고 model를 이미 pull 받은 모델 이름으로 설정하십시오. 기존 OpenAI 코드는 base URL과 key를 제외하면 수정 없이 그대로 실행됩니다.