FastAPI ile yazdığınız bir API'yi yerelde fastapi dev ile çalıştırmak kolaydır; canlı bir VPS'te ise sürecin açılışta başlaması, çöktüğünde yeniden kalkması, birden fazla çekirdeği kullanması ve HTTPS arkasında doğru URL'ler üretmesi gerekir. FastAPI belgeleri bunları "deployment concepts" başlığında toplar: HTTPS, başlangıçta çalışma, yeniden başlatma, çoğaltma (worker sayısı), bellek ve başlangıç öncesi adımlar.

Bu rehberde Docker kullanmadan Ubuntu 24.04 üzerinde Uvicorn worker'ları, systemd servisi ve önde Nginx ile bu kavramların her birini karşılıyoruz. Proxy başlıklarına güven (--proxy-headers ve --forwarded-allow-ips) ile API'yi bir alt yolda yayınlamak için root_path ayarını da ayrıca ele alıyoruz. Örneklerde uygulama main.py içindeki app nesnesi, kullanıcı api, alan adı api.ornek.com olarak geçiyor.

Sürüm notları

Sürüm notları

Yazının kontrol edildiği tarihte PyPI'daki güncel sürümler FastAPI 0.162, Uvicorn 0.54 ve Gunicorn 26.2'dir; üçü de Python 3.10 veya üstünü ister, bu yüzden Ubuntu 24.04'ün Python 3.12 sürümü yeterlidir. FastAPI ve Uvicorn hâlâ 0.x sürüm numarasıyla yayımlandığı için requirements.txt dosyanızda sürümleri sabitleyin ve güncellemeden önce sürüm notlarını okuyun. Uvicorn belgeleri artık uvicorn.dev adresinde yayımlanıyor.

1. Kullanıcı, dizin ve sanal ortam

bash
sudo apt update
sudo apt install -y python3-venv nginx git
sudo useradd --system --create-home --home-dir /srv/api --shell /bin/bash api
sudo -iu api
git clone https://github.com/KULLANICI/api-projem.git app
python3 -m venv venv
venv/bin/pip install --upgrade pip
venv/bin/pip install -r app/requirements.txt
exit

requirements.txt dosyanızda fastapi[standard] varsa Uvicorn da gelir: FastAPI belgelerine göre standard grubu uvicorn[standard] paketini içerir ve bu paket uvloop gibi performans bağımlılıklarını kurar. FastAPI belgeleri artık örneklerde uv aracını kullanıyor; pip tercih edenler için öneri, paketi bir sanal ortamın içine kurmaktır, yukarıda yaptığımız da budur.

Gizli değerleri koddan ayırmak için bir ortam dosyası oluşturun:

bash
sudo mkdir -p /etc/api
sudo nano /etc/api/api.env
sudo chown root:api /etc/api/api.env
sudo chmod 640 /etc/api/api.env
ini
FASTAPI_ENV=production
DATABASE_URL=postgresql://api:GUCLU_BIR_SIFRE@127.0.0.1:5432/api

FastAPI CLI belgelerine göre fastapi dev komutu FASTAPI_ENV değişkenini development yapar, fastapi run ise bu değişkene dokunmaz. Uygulamanızın canlı ortamı tanıması gerekiyorsa değeri bu şekilde kendiniz verin.

2. Uvicorn'u elle deneyin

Servis yazmadan önce uygulamanın açıldığını doğrulayın. Uvicorn'un varsayılan adresi zaten 127.0.0.1:8000'dir, yine de açıkça yazmak okunabilirliği artırır:

bash
sudo -iu api
cd app
set -a; . /etc/api/api.env; set +a
../venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
# ikinci bir SSH oturumunda:
curl -I http://127.0.0.1:8000/docs

3. Kaç worker?

3. Kaç worker? Uvicorn worker'ları, FastAPI CLI, Gunicorn + uvicorn-worker, Gunicorn yerel ASGI worker

FastAPI belgeleri birden çok çekirdeği kullanmak için --workers seçeneğini gösterir: hem fastapi run --workers 4 hem de uvicorn main:app --workers 4 aynı işi yapar. Uvicorn'un kendi süreç yöneticisi çöken worker'ları otomatik olarak yeniden başlatır ve takılan worker'ı sonlandırır.

Uvicorn için resmî bir formül yoktur. Belirleyici olan iki şey vardır: çekirdek sayısı (nproc) ve bellek (free -h). FastAPI belgelerindeki örnek önemlidir: uygulamanız açılışta 1 GB'lık bir model yüklüyorsa 4 worker en az 4 GB RAM tüketir. Async ağırlıklı, hafif bir API için çekirdek sayısı kadar worker ile başlayıp ölçerek ayarlamak makul bir yaklaşımdır. Gunicorn'un (2 x çekirdek) + 1 formülü Gunicorn'un senkron worker modeli için verilmiş bir başlangıç değeridir; doğrudan Uvicorn'a taşımayın.

YöntemKomut örneğiNot
Uvicorn worker'larıuvicorn main:app --workers 4FastAPI belgelerinin gösterdiği yol; bu rehberde kullanılıyor
FastAPI CLIfastapi run --workers 4 --host 127.0.0.1Arka planda Uvicorn çalıştırır
Gunicorn + uvicorn-workergunicorn main:app -w 4 -k uvicorn_worker.UvicornWorkerUvicorn belgeleri eski uvicorn.workers modülünün kullanımdan kalktığını, ayrı uvicorn-worker paketinin kullanılmasını söyler
Gunicorn yerel ASGI workergunicorn main:app --worker-class asgiGunicorn 24.0'da beta olarak geldi, 25.1.0 ile kararlı ilan edildi

4. systemd servisi

ini
# /etc/systemd/system/api.service
[Unit]
Description=FastAPI uygulaması (Uvicorn)
After=network.target

[Service]
User=api
Group=api
WorkingDirectory=/srv/api/app
EnvironmentFile=/etc/api/api.env
ExecStart=/srv/api/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2 --proxy-headers --forwarded-allow-ips 127.0.0.1
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl enable --now api.service
systemctl status api.service
journalctl -u api.service -f
  • --proxy-headers: Uvicorn belgelerine göre varsayılan olarak açıktır, ancak yalnızca --forwarded-allow-ips listesindeki adreslerden gelen X-Forwarded-For ve X-Forwarded-Proto başlıklarına güvenir. Açıkça yazmak, servis dosyasını okuyan kişiye niyeti gösterir.
  • --forwarded-allow-ips: Varsayılan değer 127.0.0.1 ve ::1'dir. Nginx aynı sunucudaysa bu yeterlidir. * değeri her kaynağa güvenir; belgeler bunu yalnızca tüm proxy'lerin başlıkları temizleyip yeniden yazdığından emin olduğunuzda kullanmanızı söyler.
  • ExecReload ve HUP: Uvicorn belgelerine göre --workers ile çalışırken ana sürece gönderilen SIGHUP, worker'ları birer birer ve istek düşürmeden yeniden başlatır; yeni worker'lar diskteki yeni kodu yükler.
  • --reload: Yalnızca geliştirme içindir ve --workers ile birlikte kullanılamaz.

systemd birimlerinin genel yapısı için systemd servis dosyası rehberi yazımıza bakabilirsiniz.

5. Nginx reverse proxy ve WebSocket

Aşağıdaki yapılandırma, Uvicorn belgelerindeki Nginx örneğinin TCP üzerinden bağlanan sürümüdür. WebSocket bağlantıları için gereken map bloğu nginx belgelerinden alınmıştır; proxy_http_version 1.1 satırı WebSocket yükseltmesi için gereklidir.

nginx
# /etc/nginx/sites-available/api
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

upstream fastapi_app {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    listen [::]:80;
    server_name api.ornek.com;

    client_max_body_size 10m;

    location / {
        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_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_redirect off;
        proxy_pass http://fastapi_app;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/api /etc/nginx/sites-enabled/api
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d api.ornek.com
sudo ufw allow 'Nginx Full' 
  • map bloğu http bağlamında olmalıdır; Ubuntu'da sites-enabled dosyaları http bloğunun içine dahil edildiği için yukarıdaki konum doğrudur. Aynı map başka bir site dosyasında da tanımlıysa nginx -t çakışma hatası verir; bu durumda tek bir yerde tanımlayın.
  • Server-Sent Events veya akış (streaming) yanıtları kullanıyorsanız Uvicorn örneğindeki gibi proxy_buffering off; ekleyin. Normal JSON API'lerde tamponlama açık kalabilir.
  • Uvicorn belgeleri, Nginx ile arasında UNIX soketi kullanmayı da önerir (--uds). Bu durumda istemci adresi soket üzerinden gelmediği için güvenilir kaynak tanımı farklılaşır; tek sunucuda 127.0.0.1 üzerinden TCP en az sürprizli seçenektir.

Sitenizin önünde Cloudflare gibi bir proxy daha varsa Nginx'in gördüğü adres ziyaretçinin değil proxy'nin adresi olur; gerçek IP'yi doğru almak için Cloudflare arkasında gerçek ziyaretçi IP'si yazımıza bakın.

6. Alt yolda yayın: root_path

API'yi kendi alt alan adında değil de ana sitenin altında, örneğin https://ornek.com/api/ adresinde yayınlamak istiyorsanız iki tarafı birlikte ayarlamanız gerekir. Nginx önekini sıyırarak isteği uygulamaya iletir; Uvicorn da uygulamaya hangi önekin arkasında çalıştığını --root-path ile bildirir. nginx belgelerine göre proxy_pass adresinde bir URI (sondaki /) varsa, isteğin location ile eşleşen kısmı bu URI ile değiştirilir.

nginx
location /api/ {
    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_pass http://fastapi_app/;
}
ini
ExecStart=/srv/api/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2 --proxy-headers --forwarded-allow-ips 127.0.0.1 --root-path /api

Bu ayar olmadan uygulamanın kendisi çalışır ama /api/docs sayfası boş kalır, çünkü tarayıcıdaki dokümantasyon arayüzü şemayı /openapi.json adresinden istemeye çalışır. FastAPI belgeleri, FastAPI(root_path=...) parametresinin 0.145.0 sonrası sürümlerde kullanımdan kaldırıldığını ve sunucu tarafındaki --root-path seçeneğinin kullanılmasını söyler.

7. Canlıda dokümantasyon arayüzü

Varsayılan olarak /docs, /redoc ve /openapi.json herkese açıktır. Herkese açık bir API için bu bir sorun olmayabilir; iç kullanıma yönelik bir API'de ise şemayı kapatmak isteyebilirsiniz. FastAPI belgelerine göre openapi_url=None şemayı ve ona dayanan arayüzleri birlikte kapatır:

python
import os
from fastapi import FastAPI

uretim = os.environ.get("FASTAPI_ENV") == "production"
app = FastAPI(openapi_url=None if uretim else "/openapi.json")

8. Güncelleme ve başlangıç öncesi adımlar

FastAPI belgeleri veritabanı göçü gibi işlerin her worker'da değil, uygulama başlamadan önce tek bir kez çalıştırılmasını önerir. Güncelleme akışı bu yüzden şöyle olmalıdır: kodu çekin, bağımlılıkları kurun, göçleri bir kez çalıştırın, sonra servisi yeniden yükleyin.

bash
sudo -iu api
cd app && git pull
../venv/bin/pip install -r requirements.txt
# varsa göç komutunuz (ör. alembic upgrade head) burada bir kez çalışır
exit
sudo systemctl reload api.service

Bu akışı otomatikleştirmek için GitHub Actions ile VPS'e deploy rehberimizdeki sürüm klasörü yapısını kullanabilirsiniz.

9. Sık karşılaşılan hatalar

9. Sık karşılaşılan hatalar: 502 Bad Gateway, 504 Gateway Timeout, Yönlendirmeler http:// ile geliyor, Loglarda tüm istemciler 127.0.0.1
BelirtiMuhtemel nedenÇözüm
502 Bad GatewayServis çalışmıyor veya port eşleşmiyorsystemctl status api.service, upstream portu ile --port değerini karşılaştırın
504 Gateway Timeoutİstek nginx'in proxy okuma süresini aşıyorUzun işi arka plan görevine taşıyın; gerekiyorsa proxy_read_timeout değerini bilinçli olarak artırın
Yönlendirmeler http:// ile geliyorProxy başlıklarına güvenilmiyor--forwarded-allow-ips değerinin Nginx'in bağlandığı adresi içerdiğini kontrol edin
Loglarda tüm istemciler 127.0.0.1X-Forwarded-For okunmuyorAynı kontrol; Nginx'te proxy_set_header X-Forwarded-For satırı
WebSocket bağlanmıyorUpgrade başlıkları iletilmiyorproxy_http_version 1.1, Upgrade ve Connection başlıkları
/api/docs boş sayfaAlt yol bilgisi uygulamada yok--root-path /api
address already in use8000 portunu başka süreç kullanıyorsudo ss -ltnp | grep 8000 ile süreci bulun

Genel 502/504 teşhisi için 502 ve 504 gateway hataları yazımıza bakabilirsiniz.

Sık Sorulan Sorular

Gunicorn kullanmak zorunda mıyım?

Hayır. FastAPI belgeleri doğrudan fastapi run --workers veya uvicorn --workers kullanımını gösterir. Gunicorn'un ayarlarına ve sinyallerine alışkınsanız uvicorn-worker paketiyle ya da Gunicorn'un yerel ASGI worker'ıyla çalıştırabilirsiniz.

Nginx olmadan Uvicorn'a doğrudan sertifika verebilir miyim?

Uvicorn --ssl-keyfile ve --ssl-certfile seçeneklerini destekler, ancak belgeleri Nginx'i ek dayanıklılık, statik dosya sunumu ve yavaş istekleri tamponlama için önerir. Sertifika yenileme de Certbot ve Nginx ile daha zahmetsizdir.

Docker ile çalıştırırsam worker kullanmalı mıyım?

FastAPI belgeleri, Kubernetes gibi kümelerde her konteynerde tek Uvicorn süreci çalıştırmayı, çoğaltmayı küme düzeyinde yapmayı önerir. Tek bir VPS'te tek konteyner kullanıyorsanız worker seçeneği yine işe yarar. Konteyner tarafı için Dockerfile yazma rehberi yazımıza bakın.

Django projem de var; aynı sunucuda olur mu?

Olur; her uygulama kendi kullanıcısı, servisi ve server bloğuyla çalışır. Django tarafını Django, Gunicorn ve Nginx deploy yazımızda anlattık.

Yazılım ve hizmet adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen projeler veya şirketlerle ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Django deploy · GitHub Actions ile VPS deploy · Next.js deploy · Laravel deploy · Reverse proxy nedir · Nginx server block · UFW güvenlik duvarı