SSD Nodes Learn
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-07-23

Cách cài Ollama trên VPS an toàn

Hướng dẫn cài Ollama trên VPS và cấu hình để tránh lộ API. Lưu ý mô hình 7B cần ít nhất 8 GB RAM và tốc độ CPU chỉ đạt 4-10 tokens/giây.

Những gì bạn đang xây dựng

Một mô hình ngôn ngữ open-weight duy nhất chạy trên server của riêng bạn, được phản hồi qua HTTP API và, nếu muốn, một trang chat trên trình duyệt. Ollama là thành phần tải mô hình, nạp vào memory và phục vụ các request trên http://127.0.0.1:11434. Việc cài đặt chỉ mất một câu lệnh. Những phần khó nhất nằm ở chỗ khác: chọn một mô hình mà VPS của bạn thực sự đủ RAM để chứa, và không vô tình công khai một inference server không có authentication ra toàn bộ internet.

Trước hết, có hai cảnh báo thực tế. Một VPS chỉ có CPU sẽ chạy các mô hình nhỏ rất chậm, và API hoàn toàn không có sẵn authentication. Cả hai vấn đề này đều được giải thích chi tiết bên dưới, vì đây là những lỗi khiến người dùng gặp rắc rối.

Kiểm tra thực tế về kích thước, bằng con số cụ thể

Dung lượng bộ nhớ của một mô hình xấp xỉ bằng kích thước file của nó, cộng thêm khoảng 1 GB overhead khi runtime, và thêm một chút cho context window. Các mô hình mặc định của Ollama được quantized ở mức 4-bit (nhãn Q4), tiêu tốn khoảng nửa GB RAM cho mỗi tỷ tham số. Vì vậy, phép tính rất đơn giản và nó quyết định mọi thứ.

Một mô hình 3B như llama3.2:3b có dung lượng tải về khoảng ~2 GB và cần khoảng 4 GB RAM trống để chạy. Một mô hình 7B hoặc 8B như mistral:7b hoặc llama3.1:8b nặng ~5 GB trên disk và cần khoảng 8 GB RAM, hoặc 16 GB để chạy thoải mái. Một mô hình 13B hoặc 14B cần khoảng 16 GB. Bất kỳ thứ gì trong khoảng 30B-đến-70B đều cần một máy có dung lượng RAM lớn hoặc, thực tế hơn, là một GPU — trên một VPS chỉ có CPU, nó sẽ không vừa hoặc sẽ trả lời chậm đến mức không thể sử dụng được.

Tiếp theo là tốc độ, vì đây là phần mà mọi người thường đánh giá thấp. CPU inference bị giới hạn bởi memory bandwidth chứ không phải clock speed, và một VPS vCPU dùng chung có bandwidth khiêm tốn. Hãy kỳ vọng tốc độ từ một chữ số đến hai chữ số đầu tiên tokens mỗi giây: một mô hình 7-8B Q4 có thể đạt 4 đến 10 tokens mỗi giây, một mô hình 3B đạt 10 đến 25. Một GPU nhanh hơn khoảng một bậc (order of magnitude). Đây là những con số ước tính — cách chính xác nhất là tự đo trên máy của bạn, phần hướng dẫn chạy bên dưới sẽ chỉ cách làm. Hãy tin vào eval rate của bạn, chứ không phải một con số trong bất kỳ bài viết nào, kể cả bài này.

Kết luận thực tế: các mô hình quantized nhỏ trên CPU thực sự hữu ích để soạn thảo, tóm tắt và phân loại nếu bạn chấp nhận được tốc độ đó. Đối với bất kỳ thứ gì lớn hơn hoặc nhanh hơn, hãy chuẩn bị ngân sách cho một instance có GPU.

Để so sánh một mô hình cụ thể với một cấu hình máy cụ thể, hãy ước tính dung lượng bộ nhớ tại đây:

ToolLLM VRAM and model-size calculator

Cài đặt Ollama

Có hai cách sạch sẽ. Script chính thức là cách đơn giản nhất trên một VPS trống:

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

Lệnh này tạo một system user tên là ollama, cài đặt binary vào /usr/local/bin/ollama, và đăng ký một systemd service tên là ollama.service để tự khởi động khi boot và bind 127.0.0.1:11434. Kiểm tra xem nó đã chạy chưa:

systemctl status ollama
ollama --version

Nếu bạn đã chạy Docker, hãy sử dụng container:

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

Lưu ý tiền tố 127.0.0.1: trong phần mapping port. Điều đó giúp bind port đó chỉ cho localhost. Viết -p 11434:11434 thay vào đó sẽ publish nó lên mọi interface, đây chính là lỗi mà phần bảo mật đã cảnh báo. Chỉ chọn một phương pháp cài đặt; không chạy cả script và container cùng lúc, nếu không hai process sẽ tranh chấp port.

Tải và chạy mô hình đầu tiên của bạn

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

pull tải các model layers về disk (khoảng 2 GB cho mô hình này). run nạp chúng vào memory và đưa bạn đến một >>> prompt. Hãy nhập một câu hỏi. Token đầu tiên có thể mất vài giây trong khi weights được nạp từ disk vào RAM, sau đó câu trả lời sẽ được stream ra. Nhập /bye để thoát chat; Ollama vẫn tiếp tục chạy ngầm.

Xem những gì đã được nạp và cách nó sử dụng tài nguyên:

ollama ps

Cột PROCESSOR cho bạn biết sự thật. 100% CPU nghĩa là không có GPU tham gia, và đó là lý do tại sao nó chậm. Đo tốc độ thực tế bằng flag verbose:

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

Dòng eval rate in ra ở cuối là số tokens mỗi giây trên phần cứng này của bạn. Đó là con số bạn cần để lập kế hoạch.

Nơi lưu trữ mô hình và dung lượng disk cần mua

Nếu được cài đặt bằng script và chạy như một service, các mô hình nằm trong home của user ollama:

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

Nếu chạy tương tác bằng user của chính bạn, chúng nằm ở ~/.ollama/models. Trong container, chúng nằm trong volume ollama. Điều này quan trọng vì các weights quantized cộng dồn rất nhanh: 3B là ~2 GB, 7-8B là ~5 GB, 14B là ~9 GB. Tải bốn mô hình để so sánh và bạn sẽ thấy mình đã dùng hết 20 GB mà không hề hay biết. Hãy tính toán dung lượng disk cho các mô hình bạn dự định giữ lại, và xóa phần còn lại bằng ollama rm <model>.

Chạy như một service do bạn kiểm soát

Script cài đặt đã đăng ký sẵn ollama.service, nên nó sẽ tự khởi động lại khi boot mà không cần thao tác thêm. Thiết lập đáng để thay đổi là thời gian một mô hình duy trì trong bộ nhớ, và trên một số thiết lập là bind address — cả hai đều nằm trong một systemd drop-in để khi nâng cấp Ollama không bị ghi đè:

sudo systemctl edit ollama.service

Thêm nội dung này dưới header [Service] mà editor hiển thị:

[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"

OLLAMA_KEEP_ALIVE là thời gian một mô hình duy trì trong memory sau request cuối cùng (mặc định là 5 phút). Hãy tăng giá trị này trên một máy mà bạn query cả ngày để tránh việc phải nạp lại weights mỗi lần; đặt thành 0 trên một máy hạn chế tài nguyên để giải phóng RAM ngay khi request kết thúc. systemctl edit sẽ nạp lại các unit files cho bạn, vì vậy hãy restart để áp dụng thay đổi:

sudo systemctl restart ollama

Điểm bảo mật quan trọng nhất

Theo mặc định, Ollama bind vào 127.0.0.1:11434, vì vậy chỉ các process trên chính VPS mới có thể truy cập. Thiết lập mặc định đó là đúng. Hãy giữ nguyên nó.

API không có authentication. Không có gì cả. Không có API key, không có login, không có rate limit, không có allow-list. Bất kỳ ai có thể truy cập port 11434 đều có thể chạy bất kỳ mô hình nào bạn đã tải, tải mô hình mới, xóa chúng, và khiến CPU hoặc GPU của bạn chạy full load vô thời hạn. Các scanner như Shodan index hàng ngàn instance Ollama đang mở, và một instance bị lộ sẽ bị phát hiện và lợi dụng trong vòng vài giờ.

Vì vậy, đây là lỗi duy nhất tuyệt đối không được mắc phải: không được set OLLAMA_HOST=0.0.0.0 và mở port 11434 trong firewall của bạn. Việc đó sẽ công khai một inference server không có authentication ra toàn bộ internet. Không có cấu hình nào có thể làm cho việc mở 11434 trên 0.0.0.0 trở nên an toàn, vì Ollama không có gì để cấu hình — authentication đơn giản là không tồn tại.

Có ba cách an toàn để truy cập mô hình từ một nơi khác ngoài máy chủ:

  • Giữ nó ở local. Nếu người gọi duy nhất là một chương trình khác trên cùng một VPS — một cron script, một bot, hoặc một MCP server kết nối các công cụ của bạn với mô hình — hãy để bind ở 127.0.0.1 và cho chương trình đó gọi http://127.0.0.1:11434. Không có gì bị lộ và không cần gì thêm.
  • Truy cập qua một tunnel riêng tư. Đưa VPS vào một WireGuard VPN do bạn tự host, đặt OLLAMA_HOST thành địa chỉ tunnel (ví dụ 10.8.0.1, không phải 0.0.0.0), và chỉ các peer VPN mới có thể kết nối. Internet công cộng vẫn không thấy gì trên port 11434.
  • Đặt một reverse proxy có authentication ở phía trước. Terminate TLS và yêu cầu password hoặc token tại nginx, Traefik, hoặc Caddy, sau đó proxy đến 127.0.0.1:11434. Ollama vẫn giữ bind localhost; proxy là thứ duy nhất lắng nghe trên port công khai. Cách này giống hệt như việc đặt một chứng chỉ Let's Encrypt trên nginx phía trước bất kỳ service local nào.

Tùy chọn reverse-proxy chính là những gì chat UI tiếp theo sẽ cung cấp cho bạn, với một lớp login thực sự.

Thêm chat UI với Open WebUI, phía sau TLS

Open WebUI là một giao diện chat tự host. Hãy chạy nó trong Docker và trỏ nó đến Ollama local:

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

Flag --network=host là chi tiết quan trọng trên một Linux VPS. Nó đưa container vào network namespace của host, vì vậy 127.0.0.1 bên trong container chính là loopback của host và container sẽ kết nối tới Ollama tại 127.0.0.1:11434 mà không cần Ollama phải lắng nghe trên bất kỳ interface nào khác. Công thức dùng bridge-network mà bạn thấy ở nơi khác — --add-host=host.docker.internal:host-gateway với OLLAMA_BASE_URL=http://host.docker.internal:11434 — sẽ không hoạt động ở đây: tên đó sẽ resolve về Docker bridge gateway, và một service bind vào 127.0.0.1 trên host sẽ không thể truy cập được qua bridge, do đó Open WebUI sẽ chỉ đứng yên và báo lỗi không thể kết nối tới Ollama.

Đánh đổi của host networking là Open WebUI giờ đây lắng nghe trên port 8080 của host trên mọi interface; mọi mapping -p đều bị bỏ qua, và Docker sẽ in ra một cảnh báo về việc đó. Vì vậy, hãy đóng 8080 tại cả host và firewall của nhà cung cấp, và để TLS reverse proxy là cửa ngõ công khai duy nhất. Trong lần truy cập đầu tiên, Open WebUI sẽ yêu cầu bạn tạo tài khoản admin — tài khoản đó chính là lớp authentication của bạn, vì vậy hãy chọn một password mạnh.

Để mở chat từ laptop qua HTTPS, hãy đặt một TLS reverse proxy phía trước 127.0.0.1:8080. Nếu bạn đã route nhiều ứng dụng Docker trên máy, Traefik với tự động TLS cho nhiều ứng dụng là lựa chọn gọn gàng nhất: một block label sẽ cấp chứng chỉ và route chat.example.com tới Open WebUI. Quy tắc từ phần bảo mật vẫn giữ nguyên — proxy sở hữu port công khai và login, trong khi Ollama vẫn ở localhost và 8080 của riêng Open WebUI vẫn được firewall bảo vệ.

Sử dụng endpoint tương thích OpenAI từ code của bạn

Ollama nói một tập hợp con của OpenAI chat API tại /v1, vì vậy hầu hết các thư viện client của OpenAI đều hoạt động sau khi thay đổi hai thứ: base URL và một key tạm thời.

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 là bắt buộc đối với thư viện client nhưng bị Ollama bỏ qua, nên bất kỳ chuỗi nào cũng được. model phải là tên mô hình bạn đã tải; một tên không tồn tại sẽ trả về model "x" not found, try pulling it first. Một lệnh curl đơn giản cũng có ý tưởng tương tự:

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"}]}'

Đây cũng là cách bạn kết nối mô hình vào các công cụ agent và editor. Nếu bạn đã phát triển trên máy này, một mô hình local có thể hỗ trợ các script và plugin bên cạnh Claude Code chạy trên VPS bên trong tmux, giúp giữ các công việc soạn thảo rẻ tiền và riêng tư tách biệt khỏi các API trả phí trong khi các tác vụ suy luận nặng vẫn nằm ở một mô hình được host.

Các lỗi thường gặp, kèm theo các chuỗi ký tự chính xác bạn sẽ thấy

Process bị "Killed" giữa chừng khi đang generate. Bạn bắt đầu một mô hình lớn và terminal in ra Killed, hoặc log server hiển thị llama runner process has terminated: signal: killed. Linux OOM killer đã dừng nó vì mô hình cần nhiều RAM hơn mức máy có. Xác nhận nguyên nhân bằng sudo dmesg | grep -i oom, nơi bạn sẽ thấy một dòng như Out of memory: Killed process ... (ollama). Cách khắc phục là dùng một mô hình nhỏ hơn hoặc được quantized nặng hơn — llama3.2:3b thay vì 13B — hoặc thêm swap để một tải trọng chỉ vừa vượt quá RAM vật lý có thể chạy chậm thay vì bị chết ngay lập tức. Swap biến một vụ crash tức thì thành một câu trả lời chậm; nó không làm cho một mô hình 70B trở nên khả thi trên 4 GB.

"Error: model requires more system memory". Ollama từ chối khởi động mô hình và in ra Error: model requires more system memory (X GiB) than is available (Y GiB). Đây là phiên bản "lịch sự" của lỗi crash ở trên: Ollama đã tính toán và dừng lại thay vì để OOM killer làm việc đó. Nó thậm chí còn đưa cho bạn hai con số. Hãy chọn một mô hình có yêu cầu thấp hơn RAM trống của bạn (kiểm tra bằng free -h), giảm độ dài context, hoặc chuyển sang một VPS lớn hơn. Không có flag nào giúp mô hình vừa đủ — bộ nhớ là tài nguyên thực tế.

Token đầu tiên mất rất nhiều thời gian, sau đó thì bình thường. Một mô hình "lạnh" không in ra gì trong khoảng 5 đến 30 giây, sau đó stream bình thường. Khoảng dừng đó là lúc weights đang được nạp từ disk vào RAM lần đầu tiên, và storage chậm sẽ làm tình trạng này tệ hơn. Sau khi đã nạp, mô hình sẽ duy trì trong khoảng OLLAMA_KEEP_ALIVE, nên prompt thứ hai sẽ trả lời ngay lập tức. Hãy tăng giá trị đó nếu các khoảng ngắt quãng làm bạn khó chịu, và dùng ollama ps để xem liệu một mô hình hiện có đang được nạp hay không.

Mọi thứ đơn giản là chậm. Mười tokens mỗi giây hoặc ít hơn, và không có lỗi nào cả. Đó là CPU inference đang hoạt động đúng như bản chất của nó. ollama ps cho thấy 100% CPU, nghĩa là không có GPU. Đây không phải là lỗi và không có thiết lập nào sửa được, vì giới hạn nằm ở memory bandwidth chứ không phải do cấu hình sai. Hãy dùng mô hình nhỏ hơn, chấp nhận tốc độ đó, hoặc chuyển sang một instance có GPU — và hãy đo tốc độ thực tế của bạn với --verbose trước khi quyết định có gì đó bị hỏng.

Connection refused từ máy khác. Từ laptop, bạn nhận được lỗi curl: (7) Failed to connect to <ip> port 11434: Connection refused. Điều này hoạt động đúng như thiết kế: Ollama chỉ bind vào localhost. Đừng "sửa" nó bằng cách bind vào 0.0.0.0, đó chính là lỗi lộ thông tin đã nêu ở trên. Thay vào đó, hãy truy cập mô hình qua VPN hoặc thông qua một proxy có authentication.

Bạn đã để lộ port 11434 ra internet. Nếu bạn đã set OLLAMA_HOST=0.0.0.0, mở firewall, và bây giờ thấy các lệnh tải mô hình mà bạn chưa từng bắt đầu hoặc CPU bị chiếm dụng 100% bởi các client không xác định, nghĩa là bạn đã bị phát hiện và lợi dụng. Đây là lỗi nghiêm trọng nhất, không phải là một trường hợp hy hữu. Hãy rebind lại về 127.0.0.1 hoặc địa chỉ VPN, đóng port 11434 tại firewall, và đặt authentication ở phía trước. Hãy giả định rằng bất kỳ thứ gì có thể truy cập được tại địa chỉ đó trong khi nó đang mở đều đã bị người lạ truy vấn.

Backup và nâng cấp

Có rất ít dữ liệu trạng thái (state) để mất. Các mô hình có thể tải lại được, vì vậy những thứ duy nhất đáng để backup là volume dữ liệu của Open WebUI — tài khoản, lịch sử chat, settings — và bất kỳ systemd drop-in nào bạn đã viết. Backup volume bằng một container tạm thời:

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

Nâng cấp Ollama bằng cách chạy lại script cài đặt; nâng cấp Open WebUI bằng docker pull ghcr.io/open-webui/open-webui:main sau đó tạo lại container. Đừng cố cố định (pin) bất cứ thứ gì lâu dài: cả chất lượng mô hình và runtime đều thay đổi rất nhanh, vì vậy hãy đọc release notes và tự benchmark lại trên máy của mình thay vì tin vào các con số của quý trước.

FAQ

Tôi có thực sự có thể chạy một LLM trên một VPS chỉ có CPU không?

Có, trong giới hạn nhất định. Các mô hình quantized nhỏ trong khoảng 3B đến 8B có thể chạy trên CPU và thực sự hữu ích để soạn thảo, tóm tắt và phân loại — chỉ là chạy chậm, ở mức một chữ số đến hai chữ số đầu tiên tokens mỗi giây trên một vCPU dùng chung. Bất kỳ thứ gì từ 13B trở lên sẽ cực kỳ chậm hoặc sẽ không vừa trong RAM. Để có tốc độ thực sự hoặc các mô hình lớn hơn, bạn cần một instance có GPU.

Mỗi mô hình cần bao nhiêu RAM?

Một quy tắc ước tính cho các mô hình quantized 4-bit mặc định: khoảng 0.5 GB RAM cho mỗi tỷ tham số cho phần weights, cộng thêm khoảng 1 GB overhead và thêm một chút cho context. Vì vậy, một mô hình 3B cần khoảng 4 GB trống, mô hình 7-8B khoảng 8 GB, và mô hình 14B khoảng 16 GB. Kiểm tra dung lượng còn trống của bạn bằng free -h và để dành chỗ cho hệ điều hành và bất kỳ thứ gì khác trên máy.

API của Ollama có authentication không?

Không. Ollama không có authentication tích hợp, không có API key, không có rate limit — bất kỳ ai có thể truy cập port 11434 đều có toàn quyền kiểm soát nó. Đó chính là lý do tại sao nó bind vào 127.0.0.1 theo mặc định và tại sao bạn không bao giờ được để lộ 11434 trên 0.0.0.0 ra internet. Hãy truy cập nó ở local, qua VPN riêng tư, hoặc thông qua một reverse proxy có thêm login.

Làm thế nào để thêm giao diện chat web?

Chạy Open WebUI trong Docker với --network=host để nó chia sẻ loopback của host và kết nối tới Ollama native tại http://127.0.0.1:11434, sau đó đặt một TLS reverse proxy phía trước port 8080 của nó để truy cập từ laptop. Hãy giữ 8080 đóng tại firewall để proxy là cửa ngõ công khai duy nhất. Tài khoản admin của chính Open WebUI sẽ cung cấp lớp login, và bạn thiết lập password khi khởi chạy lần đầu.

Làm thế nào để gọi nó từ ứng dụng của riêng tôi?

Sử dụng endpoint tương thích OpenAI tại http://127.0.0.1:11434/v1. Trỏ bất kỳ OpenAI SDK nào tới base URL đó, truyền bất kỳ chuỗi nào làm API key vì nó bị bỏ qua, và đặt model thành tên mô hình bạn đã tải. Code OpenAI hiện có thường chạy bình thường mà không cần thay đổi gì ngoài base URL và key.