Paano i-self-host ang LiteLLM bilang LLM gateway
Magpatakbo ng isang OpenAI-compatible endpoint para sa lahat ng provider gamit ang LiteLLM sa VPS, virtual keys, per-key budgets, fallbacks, at pinned images.
Gamit ng self-hosted LLM gateway
Ang LiteLLM ay isang open source na LLM gateway na ikaw mismo ang nagho-host: isang HTTP endpoint na tinatawagan ng lahat ng application mo, at ipinapasa nito ang bawat request sa provider na dapat sumagot dito. Ang LLM ay nangangahulugang large language model. Ginagamit ng gateway ang OpenAI chat completions API (application programming interface), kaya gagana rito ang anumang client library na nakikipag-ugnayan na sa OpenAI matapos baguhin ang dalawang bagay: ang base URL at ang key.
Iyan ang layunin ng isang layer of indirection. Hindi na nagtatago ang iyong mga application ng provider credentials. Ang pagpapalit ng model ay nagiging isang linya lamang sa config file sa server, sa halip na code change sa limang serbisyo. Dahil dumadaan ang bawat call sa iisang process, mayroon kang lugar para magtakda ng budget at magtala ng nagastos.
Kapag tumatakbo na ito, mayroon ka ng sumusunod:
- Isang endpoint. Tinutukoy ng mga application ang
https://gateway.example.com/v1at humihingi ng model name na ikaw ang nagtakda, gaya ngbulkostrong. - Virtual keys. Bawat application ay may sariling key, sariling model allowlist, at sariling spend ceiling. Maaari mong i-revoke ang isang key nang hindi naaapektuhan ang iba.
- Fallbacks. Kapag nabigo ang isang call o masyadong malaki ang prompt, awtomatiko itong nire-retry gamit ang ibang model.
- Naka-log na record. Sa bawat request, nagsusulat ng row na naglalaman ng cost nito, kaya masasagot kung aling app ang gumastos nito.
Bakit ikaw mismo ang magpatakbo ng gateway
Ang managed router ay kapareho ng setup, pero may proseso ng ibang provider sa pagitan ng bawat request. Kapag ikaw mismo ang nagpapatakbo nito, nananatili sa server na kontrolado mo ang mga key ng provider at prompt text mo. Totoo ang kapalit nito: ikaw na ang nag-ooperate ng component na umaasa rito ang bawat application. Tungkol sa gastos na ito ang huling section ng gabay na ito, dahil ito ang bahaging kadalasang hindi kasama sa ibang write-up.
Mga kailangan
- Isang VPS (virtual private server) na nagpapatakbo ng Ubuntu 24.04, na may naka-install na Docker at Compose plugin.
- Isang domain name na nakaturo rito, kung maa-access ng mga machine sa labas ng server ang gateway gamit ang TLS (transport layer security).
- Hindi bababa sa isang provider API key.
Walang inference na isinasagawa ang gateway. Ipinapasa nito ang mga request at ini-stream pabalik ang mga sagot, kaya nakabatay ang CPU load nito sa dami ng request at hindi sa laki ng model. Kayang patakbuhin ng isang 1 vCPU na server ang ilang internal application nang walang problema. Ang lumalaki ay ang database, dahil nagsusulat ang gateway ng isang spend row para sa bawat request.
Isulat muna ang config.yaml
Tinutukoy ng config file kung aling mga modelo ang maaaring hilingin ng isang client. May apat na mahalagang top-level section: model_list, litellm_settings, router_settings at general_settings.
model_list:
- model_name: bulk
litellm_params:
model: anthropic/claude-haiku-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: anthropic/claude-sonnet-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: openai/gpt-5.5
api_key: os.environ/OPENAI_API_KEY
litellm_settings:
num_retries: 2
request_timeout: 120
allowed_fails: 3
cooldown_time: 30
json_logs: true
set_verbose: false
router_settings:
fallbacks: [{"bulk": ["strong"]}]
context_window_fallbacks: [{"bulk": ["strong"]}]
general_settings:
background_health_checks: true
health_check_interval: 300Ang model_name ang pangalang ipinapadala ng mga client. Ang litellm_params.model ang aktuwal na modelo, na isinusulat bilang provider/model. Pangalanan ang mga modelo batay sa trabaho ng mga ito, hindi sa vendor. Patuloy na gagana ang application na humihiling ng bulk kapag nagpasya ka sa susunod na buwan na ibang modelo ang gagamitin ng bulk.
Sinasabi ng api_key: os.environ/ANTHROPIC_API_KEY sa LiteLLM na basahin ang variable na iyon sa runtime. Hindi kailanman lumalabas sa file ang literal na key, na mahalaga dahil ang config.yaml ang file na kino-commit mo.
Sinasadyang dalawang entry ang may pangalang strong. Kapag higit sa isang deployment ang may parehong model_name, itinuturing ng router na magkakapantay ang mga ito at sinusubukan ang isa pa kapag nabigo ang una. Sa ganitong paraan, nananatiling gumagana ang strong kapag nagkakaroon ng problema ang isang provider.
Inuulit ng num_retries: 2 ang parehong deployment kapag may retryable error. Mag-a-activate lamang ang fallback matapos maubos ang mga retry na iyon. Sa pamamagitan ng allowed_fails: 3 at cooldown_time: 30, inaalis ang deployment sa rotation nang 30 segundo kapag 3 beses na itong nabigo. Dahil dito, hindi sinusubukan sa bawat request ang provider na nagbabalik ng 500s.
Magkaiba ang trigger ng fallbacks at context_window_fallbacks, at ang ikalawa ang kapaki-pakinabang na madalas nalalampasan.
- Nag-a-activate ang
fallbackskapag nabigo ang primary call. - Nag-a-activate ang
context_window_fallbackskapag tinanggihan ng provider ang request dahil mas mahaba ito sa context window ng model. Dahil dito, ipinapadala ang oversized prompt sa model na may sapat na kapasidad sa halip na magbalik ng error sa caller.
Mayroon ding content_policy_fallbacks para sa provider na tumatanggi dahil sa content policy. Itakda lamang ito kung may maayos kang destinasyon para sa mga call na iyon.
Mag-deploy ng LiteLLM sa isang VPS gamit ang Docker Compose
Gumawa ng directory na naglalaman ng tatlong file: config.yaml, docker-compose.yml, at .env. Kinukuha ng upstream quickstart ang latest tag. Sa halip, mag-pin ng release tag para sa docker compose up -d sa susunod na buwan ay pareho pa rin ang gateway na ginagamit mo ngayon, at para isang linya lang ang kailangan sa rollback.
services:
litellm:
image: ghcr.io/berriai/litellm:v1.95.0
restart: unless-stopped
command: ["--config", "/app/config.yaml", "--num_workers", "1"]
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
env_file: .env
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 5s
timeout: 5s
retries: 10
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:Binabasa ng Compose ang .env nang dalawang beses dito. Una, para i-substitute ang ${POSTGRES_PASSWORD} sa mismong compose file. Ikalawa, sa pamamagitan ng env_file, para maipasa ang bawat variable sa container.
Ang v1.95.0 ang kasalukuyang release noong August 2026. Tingnan ang releases page ng proyekto at i-pin ang kasalukuyang release kapag nag-deploy ka. Nagpa-publish ang bawat release ng signature, kaya maaari mong i-check ang image bago ito pagkatiwalaan:
cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0Ang port line ay 127.0.0.1:4000:4000, na nagpa-publish ng port sa loopback interface lamang. Isulat ang 4000:4000 sa halip, at maa-access ang gateway mula sa buong internet dahil nagdaragdag ang Docker ng sarili nitong rules sa iptables FORWARD chain. Sinusuri ang mga ito bago ang rules ng ufw, kaya hindi ito mapipigilan ng ufw deny 4000. Ito ang pinakakaraniwang paraan kung paano nagiging bukas sa internet ang isang self-hosted gateway: tingnan ang kung paano direktang nagpa-publish ang Docker ng container port lampas sa ufw. Sa halip, dumadaan ang traffic mula sa labas sa reverse proxy.
Panatililiing wala sa image ang provider keys
Nasa .env file ang lahat ng secret. Ipinapasa ito bilang environment variable sa runtime, kaya hindi ito kailanman isinasama sa image at hindi rin ito kailanman kino-commit.
LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...Bumuo ng dalawang LiteLLM key gamit ang tunay na randomness, pagkatapos ay higpitan ang permission ng file:
printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .envAng LITELLM_MASTER_KEY ang admin credential. Ginagamit ito para mag-authenticate sa management API at ito rin ang password para sa Admin UI sa /ui. Hindi ito dapat hawakan ng anumang application.
Ini-encrypt ng LITELLM_SALT_KEY ang mga provider credential na naka-store sa database. Itakda ito nang isang beses at huwag nang palitan. Kapag pinalitan ito kalaunan, hindi na made-decrypt ang mga credential na naka-store na. Karaniwang mag-i-start ang gateway, pero mabibigo sa authentication ang bawat call sa mga provider na iyon.
Hinahayaan ka ng STORE_MODEL_IN_DB=True na magdagdag at mag-edit ng mga model mula sa Admin UI nang hindi binabago ang config.yaml. Maginhawa ito, pero nahahati sa dalawang source of truth ang configuration. Piliin kung alin ang authoritative at isulat ang desisyong iyon sa tabi ng config.
Ang dahilan kung bakit hindi dapat nasa config file ang mga key ay siya ring dahilan kung bakit hindi dapat mapunta ang mga ito sa tools na ibinibigay mo sa isang agent. Tinalakay sa Pag-iwas na mapunta ang provider secrets sa AI agents ang pattern na iyon, at sa env files at secrets sa Docker Compose naman ang mechanics nito.
I-start ito at i-monitor ang unang boot:
docker compose up -d
docker compose logs -f litellmTiyaking aktuwal na gumagana ito
May dalawang probe na walang authentication at isang probe na may authentication. Magkakaiba ang dahilan ng kanilang failure.
curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readinessHindi nangangailangan ng authentication ang /health/liveliness at sumasagot ito ng "I'm alive!" habang tumatakbo ang process. Hindi rin nangangailangan ng authentication ang /health/readiness. Nagbabalik ito ng JSON object na may "status": "healthy" at field na db, o 503 kapag hindi maabot ang database. Ituro ang monitoring sa readiness, dahil mananatiling green ang liveliness sa isang gateway na hindi makahanap ng kahit isang virtual key.
Ang authenticated check ang kumokonekta sa mga provider:
curl -s http://127.0.0.1:4000/health \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"Sumasagot ito gamit ang mga array na healthy_endpoints at unhealthy_endpoints. Kapag may model sa unhealthy_endpoints na may authentication error, nangangahulugan itong mali o nawawala ang provider key sa .env. Ito ang failure na kailangan mong mahanap ngayon. Dahil naka-set ang background_health_checks: true, awtomatikong pinapatakbo ng proxy ang mga probe na ito bawat health_check_interval segundo, at ibinabalik ng /health ang pinakahuling resulta. Kaya kapag nag-poll dito, hindi ito nagpapadala ng test request sa iyong mga provider sa bawat pagkakataon.
Mga virtual key at budget para sa bawat key
May sariling key ang bawat application, na nililikha gamit ang master key.
curl -s http://127.0.0.1:4000/key/generate \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"key_alias": "nightly-summariser",
"models": ["bulk"],
"max_budget": 5,
"budget_duration": "30d",
"rpm_limit": 60,
"tpm_limit": 200000
}'May field na key ang response na nagsisimula sa sk-. Ang string na iyon ang ibinibigay sa application, at iyon lang ang matatanggap nito.
- Ang
modelsay allowlist ng mga request na maaaring gawin ng key na ito. Ang key sa itaas ay maaaring humiling ngbulkat wala nang iba. - Ang
max_budget: 5kasama ngbudget_duration: "30d"ay limang US dollars bawat rolling 30 days, pagkatapos ay hihinto sa paggana ang key. - Nililimitahan ng
rpm_limitattpm_limitang requests per minute at tokens per minute para sa key na ito lamang. - Ang
key_aliasang makikilala mo sa spend log pagkalipas ng anim na linggo. Palaging magtakda nito.
Kapag naubos ang budget, mabibigo ang call na may HTTP 401 at body na ganito ang anyo:
ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07Ang status code ang dahilan kung bakit nakalilito ito. Iniuulat ng client library ang 401 bilang authentication problem, kaya susuriin ng developer na nagbabasa ng stack trace kung valid ang key. I-log ang response body kasabay ng status code; kung hindi, magmumukhang sirang credential ang pagkaubos ng budget sa bawat pagkakataon.
Suriin at baguhin ang mga key gamit ang parehong management API:
curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
curl -s -X POST http://127.0.0.1:4000/key/update \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{"key": "sk-...", "max_budget": 25}'Mananatiling epektibo ang budget na ipinapatupad sa gateway kahit ang mismong agent ang may problema. Kaya ito ang pundasyon ng cost control para sa AI agents sa VPS.
Magpadala ng bulk work sa murang model
Ituro ang client sa gateway. Base URL, key, at model name:
curl -s http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{
"model": "bulk",
"messages": [{"role": "user", "content": "Say hello in five words."}]
}'Pareho ang gawi ng anumang OpenAI client library: itakda ang base_url sa https://gateway.example.com/v1 at ang api_key sa virtual key.
Awtomatikong nalalapat ang routing policy mula sa config.yaml nang hindi ito kailangang malaman ng caller. Ipapadala sa murang model ang request para sa bulk. Kung mabigo ang tawag na iyon matapos ang mga retry nito, muling susubukan ang request gamit ang strong. Kung masyadong mahaba ang prompt para sa bulk, ipapadala ito ng context_window_fallbacks sa strong sa halip na magbalik ng error. Ang bulk work gaya ng classification pass o pagbubuod ng backlog ay murang model ang ginagamit bilang default, at ang mahihirap na request lamang ang mas magastos.
Dito rin nagiging kapaki-pakinabang ang gateway para sa mga agent na gumagamit ng tool. Ang isang MCP (model context protocol) server sa parehong VPS at ang agent na kumokontrol dito ay maaaring parehong tumuro sa iisang endpoint, kaya maaaring magbago ang model sa likod ng mga ito nang hindi nire-redeploy ang alinman.
Paano mo malalaman na nagkaroon ng fallback?
Ito ang failure mode na nagdudulot ng gastos dahil walang mukhang sira. Ang matagumpay na fallback ay nagbabalik ng HTTP 200 na may karaniwang response body. Maaaring down nang isang araw ang murang model, habang tahimik na sinasagot ng mamahaling model ang bawat call. Ang unang ebidensiya ay ang invoice.
Nasa response headers ang ebidensiya. Hingin ang mga ito:
curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
| grep -i '^x-litellm'- Ang
x-litellm-model-groupang hiningi ng client. Angx-litellm-model-idang deployment na sumagot. Kapag hindi nagtutugma ang dalawang ito, nagkaroon ng fallback. - Binibilang ito ng
x-litellm-attempted-fallbacksatx-litellm-attempted-retries. Sa isang healthy na call, parehong 0 ang mga ito. - Ang
x-litellm-response-costang gastos ng call na iyon sa US dollars. - Ang
x-litellm-call-idang identifier na ginagamit para hanapin ang parehong call sa logs.
I-record ang x-litellm-attempted-fallbacks sa bawat request at mag-set ng alert kapag hindi na ito 0. Ang nag-iisang numerong ito ang pagkakaiba sa pagitan ng routing policy na gumagana at routing policy na tahimik nang naging “palaging gamitin ang mamahaling model.”
Ang kumpletong bersyon nito ay tracing, at kailangan nito ng hiwalay na setup: self-hosted Langfuse para sa tracing ng agent calls. Kasama na sa LiteLLM ang callback, kaya dalawang linya lang kasama ang credentials para maikonekta ito.
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.comItakda ang failure_callback pati ang success_callback. Kapag nilaktawan mo ito, ang tanging traces na maiingatan mo ay ang mga request na walang naging problema. Hiwalay sa mga ito, nagsusulat ang LiteLLM ng spend row para sa bawat request sa Postgres, at binabasa ng Admin UI sa /ui ang table na iyon. Lumalaki ito kasabay ng traffic, kaya subaybayan ito kapag maliit ang disk.
Ilagay ang gateway sa likod ng reverse proxy
Walang dapat nasa labas ng box ang makakaabot sa port 4000. I-terminate ang TLS sa nginx o Caddy at i-forward ito sa loopback address.
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 600s;
}Dalawa sa mga linyang iyon ang madalas iniiwan. Mahalaga ang proxy_buffering off dahil ang streaming completion ay serye ng server-sent events. Kapag naka-enable ang buffering, hinahawakan ng nginx ang mga chunk hanggang matapos ang response. Dahil dito, tahimik na naghihintay ang client at saka lamang natatanggap ang lahat nang sabay-sabay. Mahalaga ang proxy_read_timeout 600s dahil lumalampas ang matagal na generation sa default na 60 segundo ng nginx. Kapag nangyari ito, makakatanggap ang client ng 504, habang itinatala ng error log ang upstream timed out (110: Connection timed out) while reading response header from upstream.
Para sa certificate, ang Certbot gamit ang Let’s Encrypt sa nginx ang pinakamaikling paraan. Kung naghahain na ang box ng ilang container, ang Traefik sa harap ng maraming Compose app ang namamahala sa routing at certificates sa iisang lugar.
Hindi na nag-iisa ang gateway bilang single point of failure
Maging tapat sa ginawa mong setup. Nakadepende na ngayon ang bawat application na pagmamay-ari mo sa isang container sa isang VPS. Habang down ito, walang makakatawag sa kahit anong model, kabilang ang mga provider na gumagana nang maayos. Apat na bagay ang kasunod nito.
- Kapag may maling config, sabay-sabay mawawala ang lahat. Nire-restart ng
restart: unless-stoppedang nag-crash na container, kabilang ang container na hindi makapag-parse ng config.yaml, nang paulit-ulit. Basahin angdocker compose logs litellmpagkatapos ng bawat pagbabago sa config, at gumawa ng mga pagbabago kapag may oras kang i-monitor ang resulta. - Nasa request path ang Postgres. Parehong gumagamit nito ang virtual key lookup at pag-record ng spend. Babala mo ang pagbabalik ng
/health/readinessna 503: tumatakbo ang gateway, pero hindi nito magawa ang alinman sa dalawang iyon. - Mag-scale sa pamamagitan ng pagdaragdag ng instances, hindi sa pagpapalaki ng isang instance. Ayon sa sariling guidance ng proyekto, isang worker bawat instance (
--num_workers 1), at ilang instance ang dapat magbahagi ng isang database. Inaalis ng dalawang maliit na gateway sa likod ng load balancer ang single container bilang single point of failure. Hindi nito inaalis ang database. - I-back up ang mga bagay na hindi mo kayang buuing muli. Kabilang dito ang
config.yamlat.env, kasama ang isangpg_dumpng database. Kapag nawala angLITELLM_SALT_KEY, magiging walang silbi ang mga naka-encrypt na provider credential sa loob ng dump na iyon. Kaya dapat nasa iisang backup job ang env file at ang dump: restic backups sa off-box storage.
Ang pag-upgrade ay pag-edit sa image tag at pagpapatakbo ng docker compose up -d. Bilang default, pinapatakbo ng LiteLLM ang prisma migrate deploy sa startup. Kaya mina-migrate ng bagong container ang database schema sa unang boot nito. Gawin ang dump bago baguhin ang tag, dahil hindi ibinabalik ng pag-revert sa lumang image ang migration na naisagawa na.
FAQ
Nagdaragdag ba ang LiteLLM ng kapansin-pansing latency sa bawat call?
Naglalabas ang project ng 8 ms sa 95th percentile sa 1000 requests bawat segundo, ayon sa README nito noong August 2026. Ituring iyon bilang vendor figure. Ang aktuwal na higit na nakaaapekto sa latency ay ang network distance sa pagitan ng iyong applications at gateway, dahil nagdagdag ka ng isang round trip sa bawat call. Patakbuhin ang gateway sa parehong region ng mga application na tumatawag dito, pagkatapos sukatin ang sarili mong overhead gamit ang x-litellm-overhead-duration-ms header sa isang aktuwal na response.
Bakit tumigil ang streaming matapos kong ilagay ang nginx sa unahan?
Dahil bina-buffer ng nginx ang upstream responses bilang default, at ang streaming completion ay binubuo ng serye ng server-sent events. Kapag naka-on ang proxy_buffering, kinokolekta ng nginx ang mga chunk at inilalabas lamang ang mga ito kapag tapos na ang response. Dahil dito, tahimik na naghihintay ang client at saka nito natatanggap ang buong sagot nang sabay-sabay. Itakda ang proxy_buffering off; sa location block. Itaas ang proxy_read_timeout sa parehong block, dahil kung hindi, lalampas ang mahabang generation sa default na 60 segundo ng nginx at makakatanggap ang client ng 504.
Ano ang nangyayari kapag naubos ang budget ng isang virtual key?
Bumabagsak ang call na may HTTP 401 at body na nasa anyong ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07. Ang 401 ang nakalilinlang: iniuulat ito ng client library bilang authentication failure, kaya nagsisimulang suriin ng mga tao kung valid ang key sa halip na basahin ang message. I-log ang response body kasama ng status code. Kumpirmahin ang aktuwal na posisyon ng key gamit ang /key/info?key=sk-... laban sa master key, at itaas ang ceiling gamit ang /key/update kung masyadong mababa ang itinakdang budget.
Maaari bang mag-route ang gateway sa local model pati sa mga hosted model?
Oo, at isa pa itong entry sa model_list. Gamitin ang ollama_chat/ prefix na may api_base, halimbawa model: ollama_chat/llama3.1 kasabay ng api_base: http://ollama:11434. Mula sa loob ng container, ang localhost ay nangangahulugang container na iyon, kaya gamitin ang Compose service name o ang address ng host sa Docker network, hindi kailanman ang 127.0.0.1. Hiwalay na gawain ang pag-stand up ng local model: tingnan ang pag-self-host ng LLM gamit ang Ollama sa isang VPS.