API Ollama Tanpa Kata Sandi: Risiko Port 11434
Server Ollama tidak menyediakan autentikasi. Siapa pun yang mencapai port 11434 dapat menjalankan, mengunduh, dan menghapus model. Ikuti 3 perbaikannya.
API Ollama tidak memiliki kata sandi
API Ollama tidak memiliki autentikasi. Tidak ada pengguna, kata sandi, pemeriksaan kunci, atau allowlist di mana pun pada server yang Anda jalankan. Apa pun yang dapat membuka koneksi TCP ke port 11434 dapat mencantumkan model Anda, menjalankannya, mengunduh model baru, dan menghapus model yang ada.
Dokumentasi resmi menyatakannya dengan jelas: "No authentication is required when accessing Ollama's API locally via http://localhost:11434." Kata locally mencakup seluruh model keamanan. Secara default, Ollama melakukan bind ke 127.0.0.1, sehingga pada laptop, antarmuka loopback berfungsi sebagai kontrol akses. Pindahkan listener tersebut ke alamat publik, maka kontrol akses itu hilang karena tidak ada mekanisme lain yang menggantikannya.
Inilah alasan hal ini penting pada VPS (virtual private server). Konfigurasi default aman. Perubahan pertama yang biasanya dilakukan adalah membuka listener agar mesin kedua dapat menggunakan model. Perubahan tersebut sekaligus menghapus semua perlindungan.
Hal yang diungkapkan oleh port 11434 yang terbuka
Setiap endpoint dapat diakses. Tidak ada mode read-only dan tidak ada port admin terpisah. Inilah request yang sebenarnya, yang ditujukan ke alamat server, bukan ke localhost:
# List every model on the box
curl http://SERVER_IP:11434/api/tags
# See what is loaded into memory right now
curl http://SERVER_IP:11434/api/ps
# Run a prompt on your hardware
curl http://SERVER_IP:11434/api/generate -d '{"model":"llama3.2","prompt":"Why is the sky blue?"}'
# Write several gigabytes to your disk
curl http://SERVER_IP:11434/api/pull -d '{"model":"llama3.2"}'
# Remove a model
curl -X DELETE http://SERVER_IP:11434/api/delete -d '{"model":"llama3.2"}'Dalam istilah operasional, ada empat masalah yang terjadi:
- CPU atau GPU Anda menjalankan inference untuk orang lain. Pada paket dengan alokasi CPU fair-use, beban yang terus-menerus berarti alokasi Anda digunakan oleh orang asing, dan menjaga biaya workload AI tetap terkendali di VPS menjadi jauh lebih sulit ketika Anda bukan satu-satunya pemanggil.
/api/pullmenulis data ke disk Anda. Setiap model berukuran dua hingga empat puluh gigabyte. Perulangan pull akan memenuhi volume, dan disk yang penuh akan mengganggu setiap service lain pada server, bukan hanya Ollama.- Request masuk ke dalam proses Anda dan dicatat dalam log. Pada tingkat log default, Ollama hanya mencatat metadata, sehingga Anda mendapatkan endpoint, status, latency, dan alamat client, bukan teks prompt. Namun, catatan tentang siapa yang menggunakan server Anda dan untuk tujuan apa tetap tersimpan di journal, padahal Anda tidak memilih untuk mengumpulkannya.
/api/deletemenghapus model. Untuk mendapatkannya kembali, Anda harus mengunduhnya lagi menggunakan bandwidth Anda sendiri.
Tidak satu pun dari hal ini memerlukan exploit. Ini adalah API yang terdokumentasi dan berjalan persis sesuai desain.
Kunci Ed25519 bukan kontrol akses
Cari "Ollama API key" dan Anda akan menemukan dua hal yang berbeda. Keduanya bukan kata sandi untuk server Anda. Memisahkan keduanya menghilangkan sebagian besar kebingungan.
Yang pertama adalah pasangan kunci identitas. Ollama membuat pasangan kunci Ed25519 saat pertama kali dijalankan. Di Linux, skrip instalasi membuat system user bernama ollama dengan home directory di /usr/share/ollama, sehingga pasangan kunci tersebut berada di sini:
/usr/share/ollama/.ollama/id_ed25519
/usr/share/ollama/.ollama/id_ed25519.pubKunci ini digunakan untuk koneksi keluar. ollama signin mendaftarkan bagian publiknya ke akun ollama.com Anda. Kunci ini juga digunakan untuk mengotorisasi push model ke registry atau pull model privat. Kunci tersebut membuktikan identitas mesin Anda kepada ollama.com. Kunci ini tidak meminta apa pun dari client yang terhubung ke mesin Anda. Menghapus atau merotasinya, atau tidak pernah membuatnya, tidak mengubah siapa yang dapat memanggil API Anda.
Yang kedua adalah OLLAMA_API_KEY. Variabel tersebut menyimpan kunci yang Anda buat di https://ollama.com/settings/keys. Client Anda mengirimkannya sebagai Authorization: Bearer $OLLAMA_API_KEY saat memanggil hosted API di https://ollama.com/api. Kunci ini adalah kredensial untuk layanan mereka dan digunakan oleh Anda sebagai client. ollama serve Anda sendiri tidak pernah membacanya. Menetapkan OLLAMA_API_KEY di VPS Anda tidak memasang kata sandi pada VPS tersebut.
Jadi, tidak ada pengaturan yang perlu diaktifkan. Ketiga pertahanan di bawah ini bekerja dengan cara yang sama: pastikan port tidak dapat dijangkau, lalu tempatkan sesuatu di depannya yang melakukan pemeriksaan.
Periksa port yang sedang digunakan server saat ini
sudo ss -tlnp | grep 11434Hasil yang aman mencantumkan alamat loopback:
LISTEN 0 4096 127.0.0.1:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))Hasil yang terekspos mencantumkan semua antarmuka:
LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))0.0.0.0 berarti semua alamat IPv4 pada server, termasuk alamat publiknya. *:11434 dan [::]:11434 memiliki arti yang sama dengan IPv6.
Sekarang, lakukan konfirmasi dari luar. Jalankan perintah ini di laptop Anda, bukan di server:
curl -m 5 http://YOUR_SERVER_IP:11434/api/versioncurl: (28) Connection timed out after 5001 milliseconds adalah hasil yang diharapkan, begitu juga curl: (7) Failed to connect ... Connection refused. Objek JSON yang memuat field version berarti seluruh API dapat diakses oleh siapa pun yang memintanya. Pengujian dengan curl di server itu sendiri tidak membuktikan apa pun karena loopback selalu memberikan respons.
Eksposur biasanya terjadi melalui salah satu dari dua cara. Cara pertama adalah perubahan konfigurasi yang dilakukan secara sengaja karena ada kebutuhan agar mesin kedua dapat mengakses model:
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"Satu baris tersebut sudah cukup untuk mengekspos layanan. Cara kedua adalah Docker, dan cara ini tidak mengharuskan Anda mengubah apa pun. Cara tersebut dibahas pada bagian tersendiri di bawah.
Defence 1: pertahankan pada localhost dan buat tunnel
Gunakan pendekatan ini terlebih dahulu. Pendekatan ini tidak memerlukan software baru dan tidak membuat kredensial yang dapat bocor. Port tersebut tidak pernah ada pada interface publik, sehingga pemindaian tidak dapat menemukannya.
Tetapkan alamat bind secara eksplisit, alih-alih mengandalkan nilai default:
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"Perintah tersebut menulis /etc/systemd/system/ollama.service.d/override.conf. Terapkan perubahan itu dan periksa:
sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo ss -tlnp | grep 11434ss sekarang seharusnya menampilkan 127.0.0.1:11434. Jika masih menampilkan 0.0.0.0, file drop-in kedua sedang diprioritaskan. Jalankan systemctl cat ollama.service untuk mencantumkan unit dan semua drop-in beserta path-nya, lalu hapus file yang sudah tidak digunakan.
Untuk menggunakan model tersebut dari laptop, teruskan port melalui SSH:
ssh -N -L 11434:127.0.0.1:11434 you@your-server-L 11434:127.0.0.1:11434 membuka port 11434 pada laptop dan mengirim semua data yang masuk ke sana ke 127.0.0.1:11434 sebagaimana terlihat dari server. -N memberi tahu SSH agar tidak menjalankan perintah remote, sehingga proses hanya mempertahankan tunnel tetap terbuka. Selama tunnel berjalan, perintah berikut dapat digunakan pada laptop:
curl -s http://localhost:11434/api/tagsAda dua kegagalan yang mungkin Anda temui. bind [127.0.0.1]:11434: Address already in use berarti laptop menjalankan Ollama sendiri pada port tersebut, sehingga pilih port lokal lain dengan -L 11500:127.0.0.1:11434 dan arahkan client Anda ke 11500. Balasan kosong melalui tunnel yang berhasil terhubung berarti SSH berfungsi, tetapi Ollama tidak sedang listening pada sisi server. Karena itu, periksa ss pada server sebelum mengubah perintah SSH.
Untuk beberapa mesin client, jaringan privat lebih baik daripada membuat satu tunnel untuk setiap pengguna. Hubungkan mesin-mesin tersebut ke WireGuard atau Tailscale, lalu bind Ollama ke alamatnya pada jaringan tersebut, bukan ke 0.0.0.0:
[Service]
Environment="OLLAMA_HOST=10.8.0.1:11434"Dengan demikian, port hanya ada pada interface yang memerlukan key untuk bergabung. Pendekatan ini juga tetap aman jika terjadi kesalahan firewall, karena rule yang secara tidak sengaja mengizinkan semua sumber tetap tidak dapat mengekspos listener yang tidak terdapat pada interface publik.
Defence 2: reverse proxy yang memeriksa bearer token
Jika sesuatu di Internet publik harus memanggil model, pertahankan Ollama pada loopback dan tempatkan proxy di depannya. Proxy menangani TLS (transport layer security) dan menolak permintaan tanpa header yang benar. Ollama tetap hanya menerima koneksi dari 127.0.0.1, sehingga proxy menjadi satu-satunya jalur masuk.
Buat token yang benar terlebih dahulu. Jangan membuatnya secara manual:
openssl rand -base64 36Situs nginx yang memeriksa token tersebut:
map $http_authorization $ollama_ok {
default 0;
"Bearer PASTE_YOUR_GENERATED_TOKEN_HERE" 1;
}
server {
listen 443 ssl;
server_name llm.example.com;
ssl_certificate /etc/letsencrypt/live/llm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;
location = /api/pull { return 403; }
location = /api/delete { return 403; }
location = /api/push { return 403; }
location / {
if ($ollama_ok = 0) { return 401; }
proxy_pass http://127.0.0.1:11434;
proxy_set_header Host 127.0.0.1:11434;
proxy_buffering off;
proxy_read_timeout 600s;
}
}Lima baris di sana melakukan pekerjaan penting, dan masing-masing mencegah kegagalan yang seharusnya Anda alami.
if di dalam blok location biasanya merupakan ide buruk di nginx, tetapi body dengan panjang tepat return adalah salah satu dari dua bentuk yang berperilaku konsisten, sehingga penggunaan ini aman.
location = /api/pull adalah pencocokan persis, dan nginx menempatkan pencocokan persis di atas prefix location /, sehingga ketiga endpoint tersebut ditolak sebelum token diperiksa. Token yang valid kemudian memberikan akses ke inference, bukan kemampuan untuk memenuhi disk Anda.
proxy_set_header Host 127.0.0.1:11434; penting karena Ollama memeriksa header Host dan Origin yang masuk. Meneruskan hostname publik proxy secara langsung dapat menghasilkan 403 Forbidden yang berasal dari Ollama, bukan dari nginx, sehingga proses debugging menjadi membingungkan. OLLAMA_ORIGINS adalah pengaturan lain untuk client browser yang memerlukan origin tertentu agar diizinkan.
proxy_buffering off; penting karena Ollama mengalirkan responsnya token demi token. Jika buffering aktif, nginx menahan stream tersebut dan mengirimkannya sekaligus pada akhir proses, sehingga client Anda terlihat macet selama seluruh proses pembuatan.
proxy_read_timeout 600s; penting karena nginx menggunakan nilai default 60 detik. Pembuatan yang lama pada CPU dapat dengan mudah melewati batas tersebut, client menerima 504 Gateway Time-out, dan /var/log/nginx/error.log mencatat upstream timed out (110: Connection timed out) while reading response header from upstream. Permintaan tersebut masih diproses. nginx menyerah terhadapnya.
Muat ulang dan uji kedua jalur:
sudo nginx -t && sudo systemctl reload nginx
curl -s -o /dev/null -w '%{http_code}\n' https://llm.example.com/api/tags
curl -s -H "Authorization: Bearer YOUR_TOKEN" https://llm.example.com/api/tagsPerintah pertama seharusnya mencetak 401. Perintah kedua seharusnya mencetak daftar model Anda. Jika perintah pertama juga mengembalikan daftar model, blok map berada dalam scope yang salah. Blok tersebut harus berada pada level http, jadi letakkan di file di bawah /etc/nginx/conf.d/ atau di atas blok server, jangan pernah di dalam server.
Caddy melakukan pekerjaan yang sama dengan basic authentication dalam empat baris, yang lebih sesuai untuk client browser daripada bearer token:
llm.example.com {
basic_auth {
apiuser PASTE_BCRYPT_HASH_HERE
}
reverse_proxy 127.0.0.1:11434
}Jalankan caddy hash-password untuk menghasilkan hash bcrypt yang diharapkan. Perhatikan perbedaan nama: directive tersebut bernama basicauth sebelum Caddy v2.8 dan sekarang bernama basic_auth, sehingga konfigurasi yang disalin dari panduan lama tidak dapat dimuat dan Caddy menyebutkan directive yang tidak dikenalnya.
Apa pun proxy yang Anda pilih, ini adalah satu shared secret untuk semua pengguna. Setiap client yang memilikinya mendapatkan akses yang sama, dan mencabutnya berarti mengedit konfigurasi serta memperbarui semua pemanggil secara bersamaan.
Pertahanan 3: gateway yang menerbitkan key untuk setiap client
Setelah lebih dari satu orang atau aplikasi memanggil model, token bersama tidak lagi memadai. Anda tidak dapat mengetahui client mana yang menyebabkan beban, dan tidak dapat memutus akses salah satunya tanpa memutus akses semuanya. Gateway ditempatkan di lokasi proxy sebelumnya, menggunakan API yang kompatibel dengan OpenAI, menerbitkan key terpisah untuk setiap client, dan mencatat penggunaan setiap key. Gateway LiteLLM yang di-host sendiri biasanya menjadi solusi, dan gateway tersebut menambahkan anggaran per key serta log request di atas kontrol akses.
Aturan dari pertahanan 1 tidak berubah. Ollama melakukan bind ke 127.0.0.1, gateway menjadi satu-satunya proses yang berkomunikasi dengannya, dan gateway menjadi satu-satunya service dengan listener publik. Gateway pada host yang masih membuka port 11434 ke seluruh jaringan tidak memberikan perlindungan, karena pemanggil dapat langsung melewatinya.
Jebakan firewall: port container yang dipublikasikan melewati UFW
Inilah alasan instance yang terekspos dapat ditemukan pada server yang pemiliknya telah mengonfigurasi firewall dengan benar.
UFW (uncomplicated firewall) menulis aturannya ke dalam chain INPUT pada table filter milik kernel, dan INPUT menangani paket yang ditujukan langsung ke host. Flag -p milik Docker menulis aturan destination NAT (network address translation) ke dalam chain PREROUTING pada table nat. Kernel mengevaluasi aturan ini sebelum menentukan tujuan paket. Saat keputusan routing dilakukan, tujuan paket sudah diubah menjadi alamat container. Karena itu, paket diteruskan, bukan dikirim secara lokal, dan melewati FORWARD, bukan INPUT. Aturan INPUT milik UFW tidak pernah diperiksa. Paket tersebut melewati firewall, bukan diproses olehnya.
Itulah alasan rangkaian perintah berikut membuat port 11434 terbuka ke Internet:
sudo ufw default deny incoming
sudo ufw enable
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollamaNamun, sudo ufw status tetap melaporkan bahwa firewall aktif dengan kebijakan default deny. Kedua hasil tersebut benar pada saat yang sama. Inilah alasan orang mempercayai hasil yang keliru. Anda dapat melihat aturan yang menyebabkannya:
sudo iptables -t nat -L DOCKER -nPerbaikannya adalah menggunakan satu alamat pada flag publish:
docker rm -f ollama
docker run -d -v ollama:/root/.ollama -p 127.0.0.1:11434:11434 --name ollama ollama/ollama-p 11434:11434 adalah singkatan dari -p 0.0.0.0:11434:11434. Dengan menetapkan 127.0.0.1, sisi host pada pemetaan tersebut terikat ke loopback. SSH tunnel dan reverse proxy Anda tetap dapat mengaksesnya, sedangkan Internet tidak dapat mengaksesnya. Membuat ulang container aman dilakukan karena model tersimpan di volume bernama ollama, bukan di dalam container.
Pastikan kedua tampilan tersebut memberikan hasil yang sama:
docker port ollama
sudo ss -tlnp | grep 11434docker port ollama seharusnya mencetak 11434/tcp -> 127.0.0.1:11434. Jika mencetak 0.0.0.0:11434, server masih terekspos. Setelah memahami mekanismenya, prinsip ini berlaku untuk setiap container yang Anda publikasikan: alasan port yang dipublikasikan Docker melewati UFW membahas chain DOCKER-USER dan aturan yang tetap ada setelah Docker dimulai ulang. Jika Anda masih menyusun kebijakan host itu sendiri, aturan UFW yang diperlukan VPS baru membahas dasar yang digunakan di sini. Pada Rocky atau AlmaLinux, tidak ada UFW yang perlu dikonfigurasi. Karena itu, kebijakan dasar yang sama menggunakan firewalld adalah titik awalnya.
Proses berjalan sebagai pengguna apa
Skrip instalasi Linux membuat akun khusus dan menjalankan service dengan akun tersebut:
useradd -r -s /bin/false -U -m -d /usr/share/ollama ollamaUnit pada /etc/systemd/system/ollama.service kemudian menetapkan User=ollama dan Group=ollama. Jangan mengubahnya. Perintah ollama serve yang dijalankan secara manual di terminal berjalan sebagai pengguna yang Anda gunakan untuk login. Jika pengguna tersebut adalah root, API tanpa autentikasi dapat menulis file sebagai root. Periksa pengguna yang digunakan:
ps -o user= -C ollamaHasilnya harus ollama. Hasil lain berarti proses yang dijalankan secara manual berjalan berdampingan dengan unit atau menggantikannya. Prinsip yang sama berlaku untuk setiap daemon yang Anda tambahkan nanti, dan menjalankan service sebagai pengguna dengan hak minimum menerapkannya dengan benar.
Cara memeriksa apakah endpoint API Ollama aman
Apa pun pilihan Anda, satu pengujian dapat memastikannya, dan pengujian tersebut harus dijalankan dari mesin lain:
curl -m 5 http://YOUR_SERVER_IP:11434/api/version
curl -m 5 http://YOUR_SERVER_IP:11434/api/tagsKeduanya harus mengalami timeout atau ditolak. Jika Anda menggunakan proxy, dua path yang sama pada hostname proxy harus mengembalikan 401 tanpa kredensial dan JSON yang valid dengan kredensial.
Selanjutnya, baca access log sekali. Log tersebut menunjukkan apakah ada pihak yang menemukan port saat port masih terbuka:
journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1Ollama menulis satu baris untuk setiap request dan menyertakan alamat client:
[GIN] 2026/08/12 - 14:01:10 | 200 | 103.965898ms | 127.0.0.1 | POST "/api/generate"Setiap baris harus menampilkan 127.0.0.1 satu kali setelah Ollama terikat ke loopback, karena hanya alamat tersebut yang dapat menjadi asal koneksi. Alamat publik pada kolom tersebut menunjukkan request dari luar, sedangkan timestamp menunjukkan waktunya. Tidak ada output sama sekali dari perintah tersebut adalah hasil yang diharapkan. Jika penggunaan model masih baru bagi Anda, menjalankan Ollama pada VPS membahas instalasi, penentuan ukuran model, dan batas memori yang menentukan model mana yang benar-benar dapat dimuat.
FAQ
Apakah Ollama memiliki API key atau kata sandi?
Tidak. Server yang Anda jalankan tidak memiliki autentikasi apa pun, dan dokumentasi resmi menyatakan bahwa autentikasi tidak diperlukan untuk mengakses API. Kedua hal yang disebut sebagai "Ollama API key" sebenarnya digunakan untuk tujuan lain. Pasangan Ed25519 di /usr/share/ollama/.ollama/ membuktikan identitas mesin Anda ke ollama.com agar Anda dapat mengirim model dan mengambil model privat. OLLAMA_API_KEY adalah kredensial yang dikirim client Anda ke hosted API di https://ollama.com/api. ollama serve Anda sendiri tidak membaca keduanya, sehingga kontrol akses harus berasal dari jaringan atau proxy di depannya.
Apakah OLLAMA_HOST=0.0.0.0 aman jika saya memiliki firewall?
Hanya selama tidak ada hal lain yang menulis aturan firewall pada server tersebut. 0.0.0.0 berarti listener benar-benar tersedia pada interface publik, dan Anda hanya mengandalkan firewall agar listener itu tidak dapat dijangkau. Kepercayaan tersebut tidak berlaku lagi saat Docker memublikasikan port, karena aturan DNAT yang ditambahkan Docker ke tabel nat dievaluasi sebelum paket mencapai chain INPUT tempat UFW bekerja. Akibatnya, paket diteruskan dan tidak pernah dilihat oleh UFW. Binding ke 127.0.0.1 atau ke alamat tunnel privat menghapus listener dari interface publik, sehingga kesalahan firewall tidak lagi memiliki sesuatu yang dapat diekspos.
Bagaimana cara memeriksa apakah port Ollama saya terbuka ke Internet?
Jalankan sudo ss -tlnp | grep 11434 pada server, lalu jalankan curl -m 5 http://YOUR_SERVER_IP:11434/api/version dari mesin lain. Jika ss menampilkan 127.0.0.1:11434 dan curl dari jarak jauh mengalami timeout, itulah hasil yang diharapkan. Jika ss menampilkan 0.0.0.0:11434 atau *:11434 sementara curl dari jarak jauh mengembalikan JSON, berarti seluruh API dapat dijangkau. Jangan pernah menguji dengan curl pada server itu sendiri, karena loopback akan memberikan respons apa pun alamat bind yang digunakan.
Apakah saya cukup memindahkan port dari 11434 ke port acak?
Tidak, dan alasannya perlu dijelaskan. Port yang berbeda hanya memperlambat pemindaian terhadap satu port tertentu. Scanner memeriksa seluruh rentang port, dan satu permintaan ke /api/tags dapat mengidentifikasi service tersebut, apa pun port yang digunakan. Memindahkan port juga merusak default setiap client dan membuat konfigurasi Anda sendiri lebih sulit dipahami di kemudian hari. Gunakan bind ke loopback, yang menghapus listener alih-alih memindahkannya.
Seseorang mengakses Ollama saya yang terbuka. Apa yang harus saya periksa?
Bind service tersebut ke 127.0.0.1 lalu restart terlebih dahulu agar paparan berhenti sebelum Anda mulai menyelidiki. Kemudian jalankan journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1 untuk melihat alamat eksternal mana yang memanggil endpoint tertentu dan kapan pemanggilan itu terjadi. Bandingkan ollama list dengan model yang memang ingin Anda miliki, karena /api/pull tidak menggunakan autentikasi dan model yang tidak Anda pull merupakan penggunaan ruang disk sekaligus bukti akses yang tidak diinginkan. Periksa ruang kosong dengan df -h. Ollama tidak mencatat teks prompt pada level log default, sehingga Anda memiliki catatan tentang siapa yang mengajukan permintaan dan model yang digunakan, tetapi bukan tentang hasil yang dihasilkan.