Ollama Güvenliği: API Erişimini Kısıtlama ve Şifreleme
Yerel yapay zeka modellerini çalıştırmak harika bir özgürlük hissi veriyor; bulut servislerine bağımlı olmadan, verileriniz elinizde kalarak LLM kullanabiliyorsunuz. Ama “yerel” kelimesi sizi yanıltmasın. Ollama varsayılan kurulumda oldukça açık bir şekilde geliyor ve yanlış yapılandırılmış bir kurulum, ağınızdaki herkesin modellerinize erişmesine, hatta sunucunuzu kötüye kullanmasına neden olabilir. Bu yazıda Ollama’yı production ortamına yakın bir güvenlik seviyesine taşımak için yapmanız gerekenleri, gerçek senaryolar üzerinden anlatacağım.
Ollama’nın Varsayılan Güvenlik Durumu
Ollama’yı curl -fsSL https://ollama.com/install.sh | sh komutuyla kurduğunuzda, servis 127.0.0.1:11434 adresinde dinlemeye başlar. Localhost’a bağlı olduğu için ilk bakışta güvenli görünür. Ancak pratikte şu sorunlarla karşılaşırsınız:
- Localhost’ta çalışan başka bir servis veya container Ollama API’sine kısıtlamasız erişebilir
- Eğer uzak erişim için
OLLAMA_HOST=0.0.0.0ayarlarsanız tüm ağa açılır - Varsayılan kurulumda kimlik doğrulama yoktur
- HTTPS desteği kutuda gelmez
- Rate limiting mekanizması yoktur
Özellikle şunu hayal edin: Bir geliştirme sunucusunda Ollama kuruyorsunuz, uygulamanızın erişmesi için 0.0.0.0 yapıyorsunuz ve firewall kuralını geçici olarak açıyorsunuz. “Geçici” dediğiniz şey kalıcı oluyor, ve birkaç hafta sonra sunucunuz başkalarının model inference işlemleri için kullanılıyor. GPU’nuz yanıyor, bant genişliğiniz tükeniyor.
Mevcut durumu kontrol etmekle başlayalım:
# Ollama'nın hangi adreste dinlediğini kontrol et
ss -tlnp | grep 11434
# Servis durumunu ve environment değişkenlerini gör
systemctl status ollama
systemctl cat ollama
# Mevcut API erişimini test et
curl http://localhost:11434/api/tags
curl http://localhost:11434/api/version
Ağ Erişimini Kısıtlamak: İlk Savunma Hattı
Systemd Servis Yapılandırması
Ollama systemd ile çalışıyorsa, servis dosyasını override ederek network binding’i kontrol altına alabilirsiniz:
# Override dizini oluştur
sudo mkdir -p /etc/systemd/system/ollama.service.d/
# Override dosyasını oluştur
sudo tee /etc/systemd/system/ollama.service.d/override.conf << 'EOF'
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
Environment="OLLAMA_ORIGINS=http://localhost:3000,http://127.0.0.1:3000"
Environment="OLLAMA_MAX_LOADED_MODELS=2"
Environment="OLLAMA_NUM_PARALLEL=4"
EOF
# Systemd'yi yeniden yükle ve servisi yeniden başlat
sudo systemctl daemon-reload
sudo systemctl restart ollama
# Değişikliklerin uygulandığını doğrula
systemctl show ollama --property=Environment
OLLAMA_ORIGINS değişkeni çok kritik. Bu ayar olmadan CORS başlıkları her kaynağa izin verir. Sadece gerçekten erişmesi gereken origin’leri buraya ekleyin.
UFW ile Firewall Kuralları
Eğer Ollama’yı belirli IP’lere açmak zorundaysanız, UFW ile sıkı kurallar tanımlayın:
# Varsayılan olarak gelen trafiği reddet
sudo ufw default deny incoming
# Ollama portuna sadece belirli IP'den erişime izin ver
sudo ufw allow from 192.168.1.50 to any port 11434 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 11434 proto tcp
# Genel internetten erişimi kesinlikle engelle
sudo ufw deny 11434
# Kuralları aktifleştir
sudo ufw enable
sudo ufw status verbose
IPTables ile Daha Granüler Kontrol
Kurumsal ortamlarda UFW yerine doğrudan iptables tercih edilebilir:
# Sadece belirli subnet'ten Ollama'ya erişime izin ver
sudo iptables -A INPUT -p tcp --dport 11434 -s 10.0.1.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 11434 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 11434 -j DROP
# Kuralları kalıcı hale getir (Debian/Ubuntu)
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
# Mevcut kuralları kontrol et
sudo iptables -L INPUT -n -v --line-numbers
Nginx Reverse Proxy ile Authentication ve HTTPS
Ollama’nın kendi kimlik doğrulama sistemi olmadığı için önüne bir reverse proxy koymak en temiz çözüm. Nginx burada hem TLS sonlandırma hem de basic auth yapabilir.
SSL Sertifikası Hazırlığı
# Self-signed sertifika oluştur (iç ağ için)
sudo mkdir -p /etc/nginx/ssl/ollama
sudo openssl req -x509 -nodes -days 365 -newkey rsa:4096
-keyout /etc/nginx/ssl/ollama/private.key
-out /etc/nginx/ssl/ollama/certificate.crt
-subj "/C=TR/ST=Istanbul/L=Istanbul/O=MyCompany/CN=ollama.internal"
-addext "subjectAltName=DNS:ollama.internal,IP:192.168.1.100"
# Sertifika izinlerini ayarla
sudo chmod 600 /etc/nginx/ssl/ollama/private.key
sudo chmod 644 /etc/nginx/ssl/ollama/certificate.crt
# Let's Encrypt kullanıyorsanız (public domain için)
# sudo certbot certonly --nginx -d ollama.yourdomain.com
Nginx Yapılandırması
# /etc/nginx/sites-available/ollama adlı dosya oluşturun
upstream ollama_backend {
server 127.0.0.1:11434;
keepalive 32;
}
# HTTP'yi HTTPS'e yönlendir
server {
listen 80;
server_name ollama.internal;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name ollama.internal;
ssl_certificate /etc/nginx/ssl/ollama/certificate.crt;
ssl_certificate_key /etc/nginx/ssl/ollama/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# Güvenlik header'ları
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# Basic Authentication
auth_basic "Ollama API";
auth_basic_user_file /etc/nginx/.ollama_htpasswd;
# Rate limiting
limit_req_zone $binary_remote_addr zone=ollama_limit:10m rate=10r/m;
limit_req zone=ollama_limit burst=20 nodelay;
# Log ayarları
access_log /var/log/nginx/ollama_access.log;
error_log /var/log/nginx/ollama_error.log warn;
location / {
proxy_pass http://ollama_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Streaming için timeout ayarları
proxy_read_timeout 300s;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
# Büyük model yanıtları için buffer ayarları
proxy_buffering off;
proxy_cache off;
}
# Model yükleme/silme endpoint'lerini sadece belirli IP'lere aç
location ~ ^/api/(pull|push|delete|copy|create) {
allow 192.168.1.0/24;
allow 127.0.0.1;
deny all;
proxy_pass http://ollama_backend;
proxy_read_timeout 600s;
}
}
# htpasswd dosyası oluştur
sudo apt install apache2-utils -y
sudo htpasswd -c /etc/nginx/.ollama_htpasswd apiuser
# Ek kullanıcı eklemek için -c olmadan kullanın
sudo htpasswd /etc/nginx/.ollama_htpasswd devuser
# Nginx yapılandırmasını aktifleştir
sudo ln -s /etc/nginx/sites-available/ollama /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Bu yapılandırmayla /api/pull, /api/delete gibi yönetim endpoint’leri sadece yerel ağdan erişilebilir olur. Birisi dışarıdan modellerinizi silmeye veya yeni model çekmeye çalışamaz.
API Token Tabanlı Kimlik Doğrulama
Basic auth iyi bir başlangıç ama production ortamlarında token bazlı auth daha yönetilebilir. Nginx’te Lua veya basit bir auth middleware ile bunu yapabilirsiniz. Daha pratik bir yaklaşım olarak küçük bir proxy uygulaması yazmak:
# Python ile basit bir auth proxy
cat > /opt/ollama-proxy/auth_proxy.py << 'EOF'
#!/usr/bin/env python3
import os
import hashlib
import hmac
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.request
import urllib.error
import json
VALID_TOKENS = {
"app-service-token": "myapp",
"dev-team-token": "devteam",
"readonly-token": "monitoring"
}
READONLY_PATHS = ["/api/tags", "/api/version", "/api/show"]
OLLAMA_BACKEND = "http://127.0.0.1:11434"
class OllamaAuthProxy(BaseHTTPRequestHandler):
def do_request(self, method):
auth_header = self.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
self.send_error(401, "Unauthorized: Bearer token required")
return
token = auth_header[7:]
if token not in VALID_TOKENS:
self.send_error(403, "Forbidden: Invalid token")
return
# Readonly token kontrolü
if VALID_TOKENS[token] == "monitoring":
if self.path not in READONLY_PATHS:
self.send_error(403, "Forbidden: Read-only access")
return
# İsteği Ollama'ya ilet
target_url = OLLAMA_BACKEND + self.path
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length) if content_length > 0 else None
req = urllib.request.Request(target_url, data=body, method=method)
try:
with urllib.request.urlopen(req, timeout=300) as resp:
self.send_response(resp.status)
for key, value in resp.headers.items():
self.send_header(key, value)
self.end_headers()
self.wfile.write(resp.read())
except urllib.error.URLError as e:
self.send_error(502, f"Backend error: {str(e)}")
def do_GET(self): self.do_request("GET")
def do_POST(self): self.do_request("POST")
def do_DELETE(self): self.do_request("DELETE")
def log_message(self, format, *args):
token = self.headers.get("Authorization", "unknown")[-10:]
print(f"[{self.client_address[0]}] token=...{token} {format % args}")
if __name__ == "__main__":
server = HTTPServer(("127.0.0.1", 11435), OllamaAuthProxy)
print("Ollama Auth Proxy çalışıyor: 127.0.0.1:11435")
server.serve_forever()
EOF
chmod +x /opt/ollama-proxy/auth_proxy.py
# Systemd servisi oluştur
sudo tee /etc/systemd/system/ollama-proxy.service << 'EOF'
[Unit]
Description=Ollama Authentication Proxy
After=ollama.service
Requires=ollama.service
[Service]
Type=simple
User=ollama
ExecStart=/usr/bin/python3 /opt/ollama-proxy/auth_proxy.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now ollama-proxy
Audit Logging ve Monitoring
Kimin ne sorduğunu bilmek, güvenlik açısından kritik. Nginx access log’ları başlangıç için yeterli ama daha detaylı bir izleme için şu yaklaşımı kullanabilirsiniz:
# Ollama erişimlerini izlemek için log analiz scripti
cat > /usr/local/bin/ollama-audit.sh << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/nginx/ollama_access.log"
ALERT_THRESHOLD=100 # dakikada 100'den fazla istek
echo "=== Ollama API Erişim Raporu ==="
echo "Son 1 saatteki erişimler:"
echo ""
# IP bazlı istek sayısı
echo "--- IP Bazlı İstek Dağılımı ---"
awk '{print $1}' "$LOG_FILE" |
grep -v "^#" |
sort | uniq -c | sort -rn | head -20
echo ""
echo "--- Endpoint Kullanımı ---"
awk '{print $7}' "$LOG_FILE" |
sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Başarısız Kimlik Doğrulama ---"
grep " 401 | 403 " "$LOG_FILE" |
awk '{print $1, $9}' |
sort | uniq -c | sort -rn
echo ""
echo "--- Yüksek Hacimli İstekler (Son 5 dk) ---"
RECENT=$(date -d "5 minutes ago" "+%d/%b/%Y:%H:%M")
grep "$RECENT" "$LOG_FILE" |
awk '{print $1}' |
sort | uniq -c |
awk -v threshold="$ALERT_THRESHOLD" '$1 > threshold {print "UYARI: " $2 " - " $1 " istek"}'
EOF
chmod +x /usr/local/bin/ollama-audit.sh
# Günlük rapor için cron
echo "0 9 * * * root /usr/local/bin/ollama-audit.sh >> /var/log/ollama-audit.log 2>&1" |
sudo tee /etc/cron.d/ollama-audit
Fail2Ban ile Brute Force Koruması
# Ollama için Fail2Ban filtresi oluştur
sudo tee /etc/fail2ban/filter.d/ollama.conf << 'EOF'
[Definition]
failregex = ^<HOST> .* "(GET|POST|DELETE) /api/.* HTTP/.*" (401|403) .*$
ignoreregex =
EOF
# Fail2Ban jail yapılandırması
sudo tee /etc/fail2ban/jail.d/ollama.conf << 'EOF'
[ollama]
enabled = true
port = 443,80
filter = ollama
logpath = /var/log/nginx/ollama_access.log
maxretry = 5
findtime = 300
bantime = 3600
action = iptables-multiport[name=ollama, port="80,443", protocol=tcp]
EOF
sudo systemctl restart fail2ban
# Fail2Ban durumunu kontrol et
sudo fail2ban-client status ollama
Container Ortamında Ollama Güvenliği
Docker veya Podman ile çalışıyorsanız, ağ izolasyonu için şu yapıyı kullanın:
# Özel bir Docker network oluştur
docker network create --driver bridge
--subnet=172.20.0.0/24
--ip-range=172.20.0.0/24
ollama-net
# Ollama'yı izole network'te çalıştır
docker run -d
--name ollama
--network ollama-net
--ip 172.20.0.10
-p 127.0.0.1:11434:11434
-v ollama_data:/root/.ollama
--gpus all
--restart unless-stopped
--read-only
--tmpfs /tmp:rw,size=2g
-e OLLAMA_HOST=0.0.0.0:11434
-e OLLAMA_ORIGINS=http://172.20.0.0/24
ollama/ollama
# Nginx proxy container'ı aynı network'e bağla
docker run -d
--name ollama-proxy
--network ollama-net
-p 443:443
-p 80:80
-v /etc/nginx/ollama.conf:/etc/nginx/conf.d/default.conf:ro
-v /etc/nginx/ssl:/etc/nginx/ssl:ro
-v /etc/nginx/.ollama_htpasswd:/etc/nginx/.htpasswd:ro
--restart unless-stopped
nginx:alpine
Bu yapılandırmada Ollama container’ı sadece 127.0.0.1:11434 üzerinden host’a, ve internal network üzerinden Nginx container’ına erişilebilir durumda. Dışarıya doğrudan port açılmıyor.
Güvenlik Kontrollerini Otomatikleştirme
Tüm bu önlemleri aldıktan sonra, yapılandırmanın bozulup bozulmadığını düzenli kontrol eden bir script işinizi kolaylaştırır:
#!/bin/bash
# /usr/local/bin/ollama-security-check.sh
ERRORS=0
WARNINGS=0
check() {
local desc="$1"
local cmd="$2"
local expected="$3"
result=$(eval "$cmd" 2>/dev/null)
if echo "$result" | grep -q "$expected"; then
echo "✓ $desc"
else
echo "✗ HATA: $desc"
ERRORS=$((ERRORS + 1))
fi
}
warn() {
local desc="$1"
local cmd="$2"
local pattern="$3"
result=$(eval "$cmd" 2>/dev/null)
if echo "$result" | grep -q "$pattern"; then
echo "! UYARI: $desc"
WARNINGS=$((WARNINGS + 1))
else
echo "✓ $desc"
fi
}
echo "=== Ollama Güvenlik Kontrol Listesi ==="
echo ""
check "Ollama sadece localhost'ta dinliyor"
"ss -tlnp | grep 11434" "127.0.0.1"
check "Nginx servisi çalışıyor"
"systemctl is-active nginx" "active"
check "Fail2Ban çalışıyor"
"systemctl is-active fail2ban" "active"
check "SSL sertifikası geçerli"
"openssl x509 -checkend 2592000 -noout -in /etc/nginx/ssl/ollama/certificate.crt" "will not expire"
warn "Doğrudan 11434 portuna dış erişim var"
"curl -s --max-time 3 http://$(curl -s ifconfig.me):11434/api/version" "version"
check "Htpasswd dosyası mevcut"
"test -f /etc/nginx/.ollama_htpasswd && echo exists" "exists"
check "Auth olmadan API erişimi reddediliyor"
"curl -s -o /dev/null -w '%{http_code}' https://localhost/api/tags -k" "401"
echo ""
echo "Sonuç: $ERRORS hata, $WARNINGS uyarı"
[ $ERRORS -gt 0 ] && exit 1 || exit 0
chmod +x /usr/local/bin/ollama-security-check.sh
# Haftalık otomatik kontrol
echo "0 8 * * 1 root /usr/local/bin/ollama-security-check.sh | mail -s 'Ollama Güvenlik Raporu' [email protected]" |
sudo tee /etc/cron.d/ollama-security
Pratik Güvenlik Kontrol Listesi
Bir Ollama kurulumunu production’a almadan önce şu maddeleri kontrol edin:
- Ağ binding:
OLLAMA_HOSTsadece gerekli adresi dinlemeli - Firewall: 11434 portu doğrudan internete açık olmamalı
- Reverse proxy: Nginx veya Caddy önde olmalı, TLS zorunlu
- Authentication: Basic auth veya token auth aktif olmalı
- CORS:
OLLAMA_ORIGINSsadece gereken origin’leri içermeli - Rate limiting: API abuse’a karşı Nginx level’da limit tanımlı olmalı
- Fail2Ban: Auth hataları için aktif kural olmalı
- Logging: Erişim logları düzenli incelenmeli
- Endpoint kısıtlaması: Yönetim endpoint’leri (
/api/pull,/api/delete) IP ile kısıtlanmalı - Sertifika: SSL sertifika son kullanma tarihleri takip edilmeli
- Güncellemeler: Ollama versiyonu güncel tutulmalı
Sonuç
Ollama’yı güvenli çalıştırmak, kurulumdan sonra unutulan bir detay değil; başından beri düşünülmesi gereken bir mimari karar. Varsayılan kurulumda kendi bilgisayarınızda kullanmak için yeterli güvenlik var ama herhangi bir sunucu veya çok kullanıcılı ortamda bu yazıdaki adımların tamamına ihtiyacınız var.
En önemli üç önlem şunlar: Ollama’yı asla doğrudan internete açmayın, önüne mutlaka authentication koyun ve erişim loglarını takip edin. GPU kaynaklarınız pahalı; başkasının sizin sunucunuzda model çalıştırmasına fırsat vermeyin.
Ortamınız geliştikçe güvenlik yapılandırmanızı da gözden geçirin. Yeni bir servis eklendiğinde CORS listesini güncelleyin, eski API token’larını rotasyona sokun, sertifika yenileme süreçlerini otomasyona bağlayın. Güvenlik bir kere yapılıp biten bir şey değil, sürekli bakım gerektiren bir alışkanlık.
