# Proxy Arkasında Çalıştırma { #behind-a-proxy }
Birçok durumda, FastAPI uygulamanızın önünde Traefik veya Nginx gibi bir **proxy** kullanırsınız.
Bu proxy'ler HTTPS sertifikalarını ve diğer bazı işleri üstlenebilir.
## Proxy Forwarded Header'ları { #proxy-forwarded-headers }
Uygulamanızın önündeki bir **proxy**, request'leri **server**'ınıza göndermeden önce genelde bazı header'ları dinamik olarak ayarlar. Böylece server, request'in proxy tarafından **forward** edildiğini; domain dahil orijinal (public) URL'yi, HTTPS kullanıldığını vb. bilgileri anlayabilir.
**Server** programı (örneğin **FastAPI CLI** üzerinden **Uvicorn**) bu header'ları yorumlayabilir ve ardından bu bilgiyi uygulamanıza aktarabilir.
Ancak güvenlik nedeniyle, server güvenilir bir proxy arkasında olduğunu bilmediği için bu header'ları yorumlamaz.
/// note | Teknik Detaylar
Proxy header'ları şunlardır:
* X-Forwarded-For
* X-Forwarded-Proto
* X-Forwarded-Host
///
### Proxy Forwarded Header'larını Etkinleştirme { #enable-proxy-forwarded-headers }
FastAPI CLI'yi `--forwarded-allow-ips` *CLI Option*'ı ile başlatıp, bu forwarded header'ları okumada güvenilecek IP adreslerini verebilirsiniz.
Bunu `--forwarded-allow-ips="*"` olarak ayarlarsanız, gelen tüm IP'lere güvenir.
**Server**'ınız güvenilir bir **proxy** arkasındaysa ve onunla sadece proxy konuşuyorsa, bu ayar server'ın o **proxy**'nin IP'si her neyse onu kabul etmesini sağlar.
```console
$ fastapi run --forwarded-allow-ips="*"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
### HTTPS ile Redirect'ler { #redirects-with-https }
Örneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim:
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
Client `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir.
Ancak *CLI Option* `--forwarded-allow-ips` ayarlanmadan önce, `http://localhost:8000/items/`'a redirect edebilir.
Oysa uygulamanız `https://mysuperapp.com` üzerinde host ediliyor olabilir ve redirect'in `https://mysuperapp.com/items/` olması gerekir.
Artık `--proxy-headers` ayarını yaparak FastAPI'nin doğru adrese redirect edebilmesini sağlarsınız. 😎
```
https://mysuperapp.com/items/
```
/// tip | İpucu
HTTPS hakkında daha fazla bilgi için [HTTPS Hakkında](../deployment/https.md){.internal-link target=_blank} rehberine bakın.
///
### Proxy Forwarded Header'ları Nasıl Çalışır { #how-proxy-forwarded-headers-work }
**Proxy**'nin, client ile **application server** arasında forwarded header'ları nasıl eklediğini gösteren görsel bir temsil:
```mermaid
sequenceDiagram
participant Client
participant Proxy as Proxy/Load Balancer
participant Server as FastAPI Server
Client->>Proxy: HTTPS Request
Host: mysuperapp.com
Path: /items
Note over Proxy: Proxy adds forwarded headers
Proxy->>Server: HTTP Request
X-Forwarded-For: [client IP]
X-Forwarded-Proto: https
X-Forwarded-Host: mysuperapp.com
Path: /items
Note over Server: Server interprets headers
(if --forwarded-allow-ips is set)
Server->>Proxy: HTTP Response
with correct HTTPS URLs
Proxy->>Client: HTTPS Response
```
**Proxy**, orijinal client request'ini araya girerek (intercept) alır ve request'i **application server**'a iletmeden önce özel *forwarded* header'ları (`X-Forwarded-*`) ekler.
Bu header'lar, aksi halde kaybolacak olan orijinal request bilgilerini korur:
* **X-Forwarded-For**: Orijinal client'ın IP adresi
* **X-Forwarded-Proto**: Orijinal protokol (`https`)
* **X-Forwarded-Host**: Orijinal host (`mysuperapp.com`)
**FastAPI CLI** `--forwarded-allow-ips` ile yapılandırıldığında bu header'lara güvenir ve örneğin redirect'lerde doğru URL'leri üretmek için bunları kullanır.
## Path Prefix'i Kırpılan (Stripped) Bir Proxy { #proxy-with-a-stripped-path-prefix }
Uygulamanıza bir path prefix ekleyen bir proxy'niz olabilir.
Bu durumlarda uygulamanızı yapılandırmak için `root_path` kullanabilirsiniz.
`root_path`, FastAPI'nin (Starlette üzerinden) üzerine kurulduğu ASGI spesifikasyonunun sağladığı bir mekanizmadır.
`root_path` bu özel senaryoları yönetmek için kullanılır.
Ayrıca sub-application mount ederken de içeride kullanılır.
Path prefix'i kırpılan bir proxy kullanmak, şu anlama gelir: Kodunuzda `/app` altında bir path tanımlarsınız; ancak üstte bir katman (proxy) ekleyip **FastAPI** uygulamanızı `/api/v1` gibi bir path'in altına koyarsınız.
Bu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir.
Kodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile.
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
Proxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **"kırpar"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez.
Buraya kadar her şey normal çalışır.
Ancak entegre doküman arayüzünü (frontend) açtığınızda, OpenAPI şemasını `/api/v1/openapi.json` yerine `/openapi.json` üzerinden almayı bekler.
Dolayısıyla tarayıcıda çalışan frontend `/openapi.json`'a erişmeye çalışır ve OpenAPI şemasını alamaz.
Çünkü uygulamamız proxy arkasında `/api/v1` path prefix'i ile çalışmaktadır; frontend'in OpenAPI şemasını `/api/v1/openapi.json` üzerinden çekmesi gerekir.
```mermaid
graph LR
browser("Browser")
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
server["Server on http://127.0.0.1:8000/app"]
browser --> proxy
proxy --> server
```
/// tip | İpucu
`0.0.0.0` IP'si, genelde programın ilgili makine/server üzerindeki tüm kullanılabilir IP'lerde dinlediği anlamına gelir.
///
Docs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulunduğunu belirtmek için OpenAPI şemasına da ihtiyacı olur. Örneğin:
```JSON hl_lines="4-8"
{
"openapi": "3.1.0",
// Burada daha fazla şey var
"servers": [
{
"url": "/api/v1"
}
],
"paths": {
// Burada daha fazla şey var
}
}
```
Bu örnekte "Proxy", **Traefik** gibi bir şey olabilir. Server da FastAPI uygulamanızı çalıştıran (Uvicorn'lu) FastAPI CLI olabilir.
### `root_path` Sağlama { #providing-the-root-path }
Bunu yapmak için `--root-path` komut satırı seçeneğini şöyle kullanabilirsiniz:
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Hypercorn kullanıyorsanız, onda da `--root-path` seçeneği vardır.
/// note | Teknik Detaylar
ASGI spesifikasyonu bu kullanım senaryosu için bir `root_path` tanımlar.
`--root-path` komut satırı seçeneği de bu `root_path`'i sağlar.
///
### Mevcut `root_path`'i Kontrol Etme { #checking-the-current-root-path }
Uygulamanızın her request için kullandığı mevcut `root_path` değerini alabilirsiniz; bu değer ASGI spesifikasyonunun bir parçası olan `scope` dict'inin içindedir.
Burada sadece göstermek için bunu mesaja dahil ediyoruz.
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
Ardından Uvicorn'u şu şekilde başlatırsanız:
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Response şöyle bir şey olur:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
### FastAPI Uygulamasında `root_path` Ayarlama { #setting-the-root-path-in-the-fastapi-app }
Alternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz:
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir.
### `root_path` Hakkında { #about-root-path }
Şunu unutmayın: Server (Uvicorn) bu `root_path`'i, uygulamaya iletmek dışında başka bir amaçla kullanmaz.
Ancak tarayıcınızla http://127.0.0.1:8000/app adresine giderseniz normal response'u görürsünüz:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
Yani `http://127.0.0.1:8000/api/v1/app` üzerinden erişilmeyi beklemez.
Uvicorn, proxy'nin Uvicorn'a `http://127.0.0.1:8000/app` üzerinden erişmesini bekler; bunun üstüne ekstra `/api/v1` prefix'ini eklemek proxy'nin sorumluluğudur.
## Stripped Path Prefix Kullanan Proxy'ler Hakkında { #about-proxies-with-a-stripped-path-prefix }
Stripped path prefix kullanan bir proxy, yapılandırma yöntemlerinden yalnızca biridir.
Birçok durumda varsayılan davranış, proxy'nin stripped path prefix kullanmaması olacaktır.
Böyle bir durumda (stripped path prefix olmadan), proxy `https://myawesomeapp.com` gibi bir yerde dinler; tarayıcı `https://myawesomeapp.com/api/v1/app`'e giderse ve sizin server'ınız (ör. Uvicorn) `http://127.0.0.1:8000` üzerinde dinliyorsa, proxy (stripped path prefix olmadan) Uvicorn'a aynı path ile erişir: `http://127.0.0.1:8000/api/v1/app`.
## Traefik ile Local Olarak Test Etme { #testing-locally-with-traefik }
Traefik kullanarak, stripped path prefix'li deneyi local'de kolayca çalıştırabilirsiniz.
Traefik'i indirin; tek bir binary'dir, sıkıştırılmış dosyayı çıkarıp doğrudan terminalden çalıştırabilirsiniz.
Ardından `traefik.toml` adında bir dosya oluşturup şunu yazın:
```TOML hl_lines="3"
[entryPoints]
[entryPoints.http]
address = ":9999"
[providers]
[providers.file]
filename = "routes.toml"
```
Bu, Traefik'e 9999 portunda dinlemesini ve `routes.toml` adlı başka bir dosyayı kullanmasını söyler.
/// tip | İpucu
Standart HTTP portu 80 yerine 9999 portunu kullanıyoruz; böylece admin (`sudo`) yetkileriyle çalıştırmanız gerekmez.
///
Şimdi diğer dosyayı, `routes.toml`'u oluşturun:
```TOML hl_lines="5 12 20"
[http]
[http.middlewares]
[http.middlewares.api-stripprefix.stripPrefix]
prefixes = ["/api/v1"]
[http.routers]
[http.routers.app-http]
entryPoints = ["http"]
service = "app"
rule = "PathPrefix(`/api/v1`)"
middlewares = ["api-stripprefix"]
[http.services]
[http.services.app]
[http.services.app.loadBalancer]
[[http.services.app.loadBalancer.servers]]
url = "http://127.0.0.1:8000"
```
Bu dosya, Traefik'i `/api/v1` path prefix'ini kullanacak şekilde yapılandırır.
Ardından Traefik, request'leri `http://127.0.0.1:8000` üzerinde çalışan Uvicorn'unuza yönlendirir.
Şimdi Traefik'i başlatın:
```console
$ ./traefik --configFile=traefik.toml
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
```
Ve şimdi uygulamanızı `--root-path` seçeneğiyle başlatın:
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
### Response'ları Kontrol Edin { #check-the-responses }
Şimdi Uvicorn'un portundaki URL'ye giderseniz: http://127.0.0.1:8000/app, normal response'u görürsünüz:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
/// tip | İpucu
`http://127.0.0.1:8000/app` üzerinden erişiyor olsanız bile, `root_path` değerinin `--root-path` seçeneğinden alınıp `/api/v1` olarak gösterildiğine dikkat edin.
///
Şimdi de Traefik'in portundaki URL'yi, path prefix ile birlikte açın: http://127.0.0.1:9999/api/v1/app.
Aynı response'u alırız:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
ama bu sefer proxy'nin sağladığı prefix path olan `/api/v1` ile gelen URL'de.
Elbette buradaki fikir, herkesin uygulamaya proxy üzerinden erişmesidir; dolayısıyla `/api/v1` path prefix'li sürüm "doğru" olandır.
Uvicorn'un doğrudan sunduğu, path prefix olmayan sürüm (`http://127.0.0.1:8000/app`) ise sadece _proxy_'nin (Traefik) erişmesi için kullanılmalıdır.
Bu da Proxy'nin (Traefik) path prefix'i nasıl kullandığını ve server'ın (Uvicorn) `--root-path` seçeneğinden gelen `root_path`'i nasıl kullandığını gösterir.
### Docs UI'yi Kontrol Edin { #check-the-docs-ui }
Şimdi işin eğlenceli kısmı. ✨
Uygulamaya erişmenin "resmi" yolu, tanımladığımız path prefix ile proxy üzerinden erişmektir. Bu yüzden beklendiği gibi, Uvicorn'un doğrudan servis ettiği docs UI'yi URL'de path prefix olmadan açarsanız çalışmaz; çünkü proxy üzerinden erişileceğini varsayar.
Şuradan kontrol edebilirsiniz: http://127.0.0.1:8000/docs:
Ancak docs UI'yi proxy üzerinden, `9999` portuyla, `/api/v1/docs` altında "resmi" URL'den açarsak doğru çalışır! 🎉
Şuradan kontrol edebilirsiniz: http://127.0.0.1:9999/api/v1/docs:
Tam istediğimiz gibi. ✔️
Bunun nedeni, FastAPI'nin OpenAPI içinde varsayılan `server`'ı, `root_path` tarafından verilen URL ile oluşturmak için bu `root_path`'i kullanmasıdır.
## Ek `server`'lar { #additional-servers }
/// warning | Uyarı
Bu daha ileri seviye bir kullanım senaryosudur. İsterseniz atlayabilirsiniz.
///
Varsayılan olarak **FastAPI**, OpenAPI şemasında `root_path` için bir `server` oluşturur.
Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs UI'nin hem staging hem de production ortamıyla etkileşime girmesini istiyorsanız.
Özel bir `servers` listesi verirseniz ve bir `root_path` varsa (çünkü API'niz proxy arkasındadır), **FastAPI** bu `root_path` ile bir "server"ı listenin başına ekler.
Örneğin:
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
Şöyle bir OpenAPI şeması üretir:
```JSON hl_lines="5-7"
{
"openapi": "3.1.0",
// Burada daha fazla şey var
"servers": [
{
"url": "/api/v1"
},
{
"url": "https://stag.example.com",
"description": "Staging environment"
},
{
"url": "https://prod.example.com",
"description": "Production environment"
}
],
"paths": {
// Burada daha fazla şey var
}
}
```
/// tip | İpucu
`url` değeri `/api/v1` olan, `root_path`'ten alınmış otomatik üretilen server'a dikkat edin.
///
Docs UI'de, http://127.0.0.1:9999/api/v1/docs adresinde şöyle görünür:
/// tip | İpucu
Docs UI, seçtiğiniz server ile etkileşime girer.
///
/// note | Teknik Detaylar
OpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir.
`servers` parametresini belirtmezseniz ve `root_path` `/` ile aynıysa, üretilen OpenAPI şemasında `servers` özelliği varsayılan olarak tamamen çıkarılır; bu da `url` değeri `/` olan tek bir server ile eşdeğerdir.
///
### `root_path`'ten Otomatik `server` Eklenmesini Kapatma { #disable-automatic-server-from-root-path }
**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz:
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
Böylece OpenAPI şemasına dahil etmez.
## Bir Sub-Application Mount Etme { #mounting-a-sub-application }
Bir sub-application'ı ( [Sub Applications - Mounts](sub-applications.md){.internal-link target=_blank} bölümünde anlatıldığı gibi) mount etmeniz gerekiyorsa ve aynı zamanda `root_path` ile bir proxy kullanıyorsanız, bunu beklendiği gibi normal şekilde yapabilirsiniz.
FastAPI içeride `root_path`'i akıllıca kullanır; dolayısıyla doğrudan çalışır. ✨