Giriş
Ters proxy kullanmak, bir uygulama sunucusunu internete açmak için önerilen yaklaşımdır. İster üretim ortamında bir Node.js uygulaması çalıştırıyor ister Flask gibi temel bir yerleşik web sunucusu kullanıyor olun, bu uygulama sunucuları genellikle bir TCP bağlantı noktası üzerinden localhost‘a bağlanır. Varsayılan olarak bu, uygulamaya erişimi yerel makineyle sınırlar. İnternet erişimini etkinleştirmek için farklı bir bağlanma noktası belirlemek mümkün olsa da, bu uygulama sunucuları ideal olarak üretim ayarlarında bir ters proxy arkasında çalışacak şekilde yapılandırılır. Bu kurulum, uygulama sunucusunu doğrudan internete maruz kalmaktan ayırarak, merkezi güvenlik duvarı koruması sağlayarak ve hizmet reddi saldırıları gibi yaygın tehditler için saldırı yüzeyini azaltarak güvenlik avantajları sunar.
İstemci açısından bakıldığında, ters proxy ile etkileşim kurmak doğrudan uygulama sunucusuyla arayüz oluşturmaktan farksızdır. Süreç işlevsel olarak aynıdır ve istemcilerin herhangi bir ek yapılandırmaya ihtiyacı yoktur. İstemci bir kaynak isteği yapar ve bunu sorunsuz bir şekilde alır.
Bu yazıda, yaygın olarak kullanılan bir web sunucusu ve ters proxy çözümü olan Nginx kullanılarak bir ters proxy’nin nasıl kurulacağı gösterilecektir. Adımlar, Nginx’in kurulmasını, proxy_pass yönergesini kullanarak ters proxy olarak yapılandırılmasını ve istemcinin isteğindeki ilgili başlıkların iletilmesini içerir. Test için kullanılabilir bir uygulama sunucunuz yoksa, isteğe bağlı olarak WSGI sunucusu Gunicorn’u kullanarak bir test uygulaması kurabilirsiniz, onu da anlatacağız.
Ön Koşullar
Bu projemizi başarıyla takip etmek için aşağıdakilere sahip olduğunuzdan emin olun:
- Ubuntu için bir Ubuntu sunucusu.
- Proxy olarak kullanmak istediğiniz uygulama sunucusunun adresi, bu kılavuz boyunca “app_server_address” olarak anılacaktır. Bu, TCP bağlantı noktasına sahip bir IP adresi (örneğin, http://127.0.0.1:8000 gibi Gunicorn varsayılanı) veya bir Unix etki alanı soketi (örneğin, pgAdmin için http://unix:/tmp/pgadmin4.sock) olabilir. Test için bir uygulama sunucunuz yoksa, http://127.0.0.1:8000 adresine bağlı bir Gunicorn uygulaması kurmanızda size yardımcı olacağım.
- Sunucunuzun genel IP’sine yönlendirilmiş bir alan adı. Nginx, bu alan adını kullanarak uygulama sunucunuzu proxy’lemek üzere yapılandırılacaktır.
Adım 1 – Nginx Kurulumu
Terminali açıp apt komutuyla yükleyeceğiz:
sudo apt update
sudo apt install nginx
Kurulumu onaylamak için Y tuşuna basın. Hizmetleri yeniden başlatmanız istenirse, varsayılanları kabul etmek için ENTER tuşuna basın.
Güvenlik duvarınız üzerinden Nginx’e erişime izin vermeniz gerekir. Sunucunuzu ilk sunucu önkoşullarına göre kurduktan sonra, ufw ile aşağıdaki kuralı ekleyin:
sudo ufw allow 'Nginx HTTP'
Şimdi Nginx’in çalıştığını doğrulayabilirsiniz:
systemctl status nginx
Şöyle bir yazı çıkması gerekiyor:

Ardından, alan adınız ve uygulama sunucusu proxy’niz ile özel bir sunucu bloğu ekleyeceksiniz.
Adım 2 – Sunucu Bloğunuzu Yapılandırma
Varsayılan yapılandırmayı doğrudan değiştirmek yerine, herhangi bir ek sunucu bloğu için kişiselleştirilmiş bir yapılandırma dosyası oluşturmanın en iyi uygulamasını benimsemeniz önerilir. nano veya tercih ettiğiniz metin düzenleme aracını kullanarak yeni bir Nginx yapılandırma dosyasının oluşturulmasını ve açılmasını başlatın.
sudo nano /etc/nginx/sites-available/fastapi-app.conf
Ben önceki blog yazılarımdan olan ‘Gunicorn+Uvicorn kullanarak bir FastAPI uygulaması‘ konusuna reverse proxy uygulayacağım için fastapi-app.conf ismini seçtim. Siz istediğiniz ismi koyabilirsiniz. Açılan ayar dosyamıza şu komutları yapıştırın:
upstream app_server {
server unix:/home/fastapi-user/fastapi-nginx-gunicorn/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name 127.0.0.1:8000;
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/fastapi-user/fastapi-nginx-gunicorn/logs/nginx-access.log;
error_log /home/fastapi-user/fastapi-nginx-gunicorn/logs/nginx-error.log;
location / {
access_log /home/fastapi-user/fastapi-nginx-gunicorn/logs/app-access.log;
error_log /home/fastapi-user/fastapi-nginx-gunicorn/logs/app-error.log;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
}
}
}
Kaydedin ve çıkın, nano ile bunu CTRL+O(Kaydetme) ve ardından CTRL+X(Çıkış) tuşlarına basarak yapabilirsiniz.
Bu konfigürasyon dosyası, bir FastAPI uygulamasının Nginx web sunucusu üzerinden nasıl yönetileceğini tanımlar. İlk olarak, upstream
bloğu, Nginx’in yönlendirmeleri nereye yapacağını belirtir ve bu durumda bir Gunicorn sunucusuna işaret eder. Bu Gunicorn sunucusu, FastAPI uygulamasını çalıştıran bir arka uç sunucudur.
Ana server
bloğu, Nginx’in gelen bağlantıları nasıl dinleyeceğini ve yönlendireceğini belirtir. Bu durumda, 80 numaralı portu dinler ve gelen bağlantıları belirtilen host ve port kombinasyonuna göre işler.
Diğer ayarlar bölümü, genel Nginx yapılandırma ayarlarını içerir, örneğin, keepalive süresi ve maksimum istemci gövde boyutu gibi. Ayrıca, erişim ve hata logları belirli bir dizine yönlendirilir, bu da sistem yönetimi ve hata ayıklama için önemlidir.
Son olarak, location/
bloğu, belirli bir URL yoluna yapılan istekleri ele alır. Bu blok, Nginx’in bu istekleri Gunicorn sunucusuna yönlendirmesini sağlar. Bu, Nginx’in ön uç sunucu olarak görev yaparak, Gunicorn üzerinde çalışan FastAPI uygulamasına gelen istekleri yönlendirip, sonuçları geri döndürmesini sağlar. Bu konfigürasyon, bir web uygulamasının Nginx ile nasıl entegre edileceğini ve hizmet verileceğini belirleyen önemli bir yapıyı temsil eder.
Ters proxy’ler söz konusu olduğunda amaç, istemci hakkında ve bazen de ters proxy sunucusunun kendisi hakkında ilgili ayrıntıları iletmektir. Proxy sunucusunun ters proxy sunucusu hakkında bilgi edinmek istediği durumlar olsa da, konunun özü genellikle ilk istemcinin talebindeki temel bilgiler etrafında döner. Nginx, bu başlıkların iletimini kolaylaştırmak ve bilgilerin beklenen yerlerde mevcut olmasını sağlamak için proxy_set_header yönergesini kullanır.
Varsayılan olarak, Nginx bir ters vekil rolünü üstlendiğinde, iki başlığı değiştirir, tüm boş başlıkları kaldırır ve ardından isteği iletir. Değişikliğe tabi olan iki başlık Host ve Connection başlıklarıdır. Çok sayıda HTTP başlığı mevcut olsa da, daha fazla bilgi için her birinin amaçlarını detaylandıran kapsamlı bir listeye başvurulabilir. Ancak, ters proxy’ler için ilgili olanlar daha sonra açıklanacaktır.
proxy_params betiği belirli başlıkları iletir ve ilişkili verileri değişkenlerde kapsüller. İşte proxy_params tarafından iletilen başlıklar ve bunların verilerini barındıran değişkenler:
- Ana bilgisayar: Bu başlıkta, web sitesi etki alanı ve bağlantı noktasını kapsayan, istemci tarafından talep edilen orijinal ana bilgisayar yer alır. Nginx bu bilgiyi $http_host değişkeninde saklar.
- X-Forwarded-For: Bu başlık, orijinal isteği başlatan istemcinin IP adresini içerir. Ayrıca, birincil IP orijinal istemcinin IP adresi olmak üzere, isteği yönlendiren ters proxy sunucularının IP adreslerinin bir listesini içeren bir IP adresleri listesi de barındırabilir. Nginx bunu $proxy_add_x_forwarded_for değişkeninde tutar.
- X-Real-IP: Bu başlık sürekli olarak uzak istemciye atfedilebilen tekil bir IP adresi içerir. Bu, potansiyel olarak bir dizi adres içerebilen X-Forwarded-For ile tezat oluşturur. X-Forwarded-For yoksa, X-Real-IP onun değerini alır.
- X-Forwarded-Proto: Bu başlık, HTTP veya HTTPS olsun, bağlantı için ilk istemci tarafından kullanılan protokolü kapsüller. Nginx bu bilgiyi $scheme değişkeninde saklar.
Ardından, bu yapılandırma dosyasından Nginx’in başlangıçta okuduğu sites-enabled dizinine bir bağlantı oluşturarak bu yapılandırma dosyasını etkinleştirin:
sudo ln -s /etc/nginx/sites-available/fastapi-app.conf /etc/nginx/sites-enabled/
Artık yapılandırma dosyanızı sözdizimi hatalarına karşı test edebilirsiniz:
sudo nginx -t
Herhangi bir sorun çıkmadıysa, değişikliklerinizi uygulamak için Nginx’i yeniden başlatın:
sudo systemctl restart nginx
Nginx, uygulama sunucunuz için bir ters proxy olarak ayarlanmıştır. Uygulama sunucunuz çalışır durumdaysa, ona yerel bir tarayıcı üzerinden erişebilirsiniz. İstediğiniz uygulama sunucusunu henüz başlatmadıysanız, devam edin ve şimdi başlatın. Bu durumda, bu eğitimin geri kalanını atlayabilirsiniz.
Bununla birlikte, aklınızda belirli bir uygulama sunucusu yoksa veya şu anda çalışmıyorsa, Gunicorn kullanarak bir test uygulaması ve sunucusu yapılandırma konusunda size rehberlik edeceğimiz bir sonraki adıma geçin.
Adım 3(İsteğe Bağlı) – Ters Proxy’nizi Gunicorn ile Test Etme
Önceki
Önceki blog yazılarımdan olan ‘Gunicorn+Uvicorn kullanarak bir FastAPI uygulaması‘ konusuna değinmiştik ve orda nasıl böyle bir uygulama yapacağımızı anlarmıştık. Burda değiştirmemiz gereken bir kaç bir şey var. Öncelikle terminalden ‘cd home/fastapi-user/fastapi-nginx-gunicorn‘ dosya konumumuza gelelim ve ardından şu komutumuzu yazarak main dosyamızı açalım:
nano main.py
Ardından şu komutları dosyanın içerisine yapıştıralım.
import logging
from typing import List, Optional
from fastapi import FastAPI, HTTPException
from uuid import UUID
from model import User, Role, Gender, UserUpdateRequest
app = FastAPI()
db: List[User] = [
User(
id="09d2bedb-6c52-4ba5-9f5a-02fe3f36a81c",
first_name="James",
last_name="Bond",
gender=Gender.male,
roles=[Role.student]
),
User(
id="ebb4a58d-003e-4d56-958c-f899ec56b1b3",
first_name="James2",
last_name="Bond2",
gender=Gender.female,
roles=[Role.admin, Role.user]
)
]
# Log dosyası için yapılandırma
logging.basicConfig(filename='app.log', level=logging.INFO)
@app.on_event("startup")
async def startup_event():
logging.info("Uygulama başlatıldı.")
@app.on_event("shutdown")
async def shutdown_event():
logging.info("Uygulama kapatıldı.")
@app.middleware("http")
async def log_requests(request, call_next):
logging.info(f"Istek: {request.method} - {request.url}")
response = await call_next(request)
logging.info(f"Yanıt: {response.status_code}")
return response
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/api/users")
async def fetch_users():
return db
@app.post("/api/users")
async def create_user(user: User):
db.append(user)
return {"id": user.id}
@app.delete("/api/users/{user_id}")
async def delete_user(user_id: UUID):
for user in db:
if user.id == user_id:
db.remove(user)
return
raise HTTPException(
status_code=404,
detail=f"user with id: {user_id} does not exist"
)
@app.put("/api/users/{user_id}")
async def update_user(user_update: UserUpdateRequest, user_id: UUID):
for user in db:
if user.id == user_id:
if user_update.first_name is not None:
user.first_name = user_update.first_name
if user_update.last_name is not None:
user.last_name = user_update.last_name
if user_update.roles is not None:
user.roles = user_update.roles
return
raise HTTPException(
status_code=404,
detail=f"user with id: {user_id} does not exist"
)
Bu kodların açıklamısını bu yazıda yaparak kafanızı şişirmeyeceğim, önceki yazımızdan bakabilirsiniz. Tek farkımız artık bir app.log adlı bir log tutan dosyamız var. Bakalım Ters Proxy’li Nginx+Gunicorn+Uvicorn uygulamamız doğru çalışmış mı?

Evet görünen o ki uygulamamız doğru bir şekilde çalışıyor. Hepinize iyi çalışmalar diliyorum.
+ There are no comments
Add yours