Config

Portlar

Proxy eklemeden önce dinlenecek bir port bağlamanız gerekir. Bunu "Portlar" bölümünden yapabilirsiniz.

r3v3rs3 altı port türünü destekler:

Server Name'ler

HTTPS, QUIC üzerinden HTTP ve TLS üzerinden TCP portlarında "Server Name'ler" alanı bulunur. r3v3rs3, server sertifikasını client'ın SNI (Server Name Indication) değerine göre seçer. Client SNI göndermediğinde r3v3rs3, bütün server name'leri taşıyan geçerli bir server sertifikası seçer. Liste boşsa ilk geçerli server sertifikasını seçer.

[my-port]
listen = "/ip4/0.0.0.0/tcp/443/https"
tls_termination = { server_names = ["example.com", "*.example.com"] }

TLS client authentication

HTTPS, QUIC üzerinden HTTP ve TLS üzerinden TCP portları client'ın sertifikasını doğrulayabilir (mutual TLS). Modu "Client Authentication" alanından seçin:

ModDavranış
KapalıPort client sertifikası istemez. Varsayılan mod budur.
İsteğe bağlıPort sertifika ister, fakat sertifikasız client'ları da kabul eder. Client'ın gönderdiği sertifika geçerli olmalıdır.
ZorunluClient geçerli bir sertifika göndermezse TLS handshake başarısız olur.

İsteğe bağlı ve Zorunlu modlarda "Client CA Sertifikaları" listesinden bir veya daha fazla root sertifika seçin. Client sertifikası bunlardan biriyle imzalanmış olmalıdır. Sistemin root sertifikaları kullanılmaz. r3v3rs3, root sertifika seçilmemiş veya root olmayan bir sertifika seçilmiş port config'ini reddeder. Bir portun kullandığı root sertifika silinemez.

Client authentication config'i geçersiz hale gelirse (örneğin root sertifika config dizininden silinirse) port bütün bağlantıları kapatır ve port listesi "TLS Hatası" gösterir.

HTTPS ve QUIC üzerinden HTTP portlarında header kuralları, doğrulanan sertifikayı {client_cert_subject} ve {client_cert_fingerprint} değişkenleriyle upstream sunucuya gönderebilir. "Header kuralları" bölümüne bakın.

[my-port]
listen = "/ip4/0.0.0.0/tcp/443/https"
tls_termination = { server_names = ["example.com"], client_auth = "required", client_ca_certs = ["a1b2c3d"] }

PROXY protocol

r3v3rs3 önündeki bir load balancer, client adresini PROXY protocol header'ı (versiyon 1 veya 2) ile gönderebilir. TCP, TLS üzerinden TCP, HTTP ve HTTPS portları bu header'ı okuyabilir. UDP ve QUIC üzerinden HTTP portları okuyamaz.

"PROXY Protocol Kabul Et" seçeneğini açın. Load balancer'ların IP adreslerini veya CIDR bloklarını "Güvenilen Load Balancer'lar" alanına yazın:

r3v3rs3 header'ı TLS handshake'ten önce okur. Header'daki adres bağlantının client adresi olur. IP filtreleri, rate limit'ler, client IP hash, Forwarded ve X-Forwarded-For header'ları ve access log bu adresi kullanır. Access log peer adresini de peer alanına yazar.

PROXY protocol header'ı ile başlayan bir ACME HTTP-01 challenge request'i challenge yanıtını almaz. Böyle bir load balancer'ın sunduğu sertifika için DNS-01 challenge kullanın.

[my-port]
listen = "/ip4/0.0.0.0/tcp/443/https"
tls_termination = { server_names = ["example.com"] }
proxy_protocol = { trusted = ["10.0.0.0/8"], accept = "v2", timeout = "5s" }

accept değeri any (varsayılan), v1 veya v2 olur.

Portu sıfırlama

Port config'ini değiştirdiğinizde açık bağlantılar etkilenmez; bu bağlantılar eski config ile çalışmaya devam eder. Açık bağlantıları kapatmak için portu sıfırlayın.

Proxy'ler

r3v3rs3 üç proxy türünü destekler:

Bir proxy'ye birden fazla port bağlayabilirsiniz. Ancak HTTP / HTTPS proxy'sine TCP veya TLS üzerinden TCP portu bağlanamaz. TCP / TLS üzerinden TCP proxy'sine de HTTP veya HTTPS portu bağlanamaz.

Routing

Bir portu birden fazla HTTP / HTTPS proxy'si kullanıyorsa r3v3rs3, porttaki bütün proxy'lerin bütün route'larını karşılaştırır. Request'i en özel route'a gönderir. Proxy'lerin ve route'ların sırası sonucu değiştirmez.

  1. Önce request'in host'u proxy'leri seçer. Host ile aynı olan virtual host (app.example.com veya bir IP adresi), wildcard'dan (*.example.com) önce gelir. Wildcard, regex pattern'den önce gelir. Regex pattern, virtual host'u olmayan proxy'den önce gelir. Virtual host'u olmayan proxy her host'u kabul eder.
  2. Host eşleşmesi aynı olan route'lar arasında path'i en uzun olan route kazanır. Path tam segment'lerle eşleşir. Bu yüzden /api, /api ve /api/users ile eşleşir, /apiv2 ile eşleşmez.
  3. İki route'un host eşleşmesi ve path'i aynıysa önce gelen route kazanır.

Örneğin aşağıdaki route'larda GET /api/users request'i http://api:8080/ sunucusuna, GET /about request'i http://web:3000/ sunucusuna gider. app.example.com için gelen request, path'i /api olsa da my-app proxy'sine gider.

[my-default]
protocol = "http"
routes = [
  { path = "/", servers = [{ url = "http://web:3000/" }] },
  { path = "/api", servers = [{ url = "http://api:8080/" }] },
]

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
routes = [{ path = "/", servers = [{ url = "http://app:9000/" }] }]

DNS SRV sunucuları

http+srv veya https+srv şemalı bir sunucu URL'i, sunucularını host adının DNS SRV kayıtlarından alır. r3v3rs3 adı çözer ve route, her SRV hedefi için bir sunucu alır: +srv önündeki şema, hedefin host:port değeri ve URL'in path'i. Consul, Kubernetes headless service'leri ve diğer service registry'ler bu kayıtları yayınlar. URL'de port yazılmaz, portları SRV kayıtları verir.

[my-api]
protocol = "http"
routes = [{ path = "/", servers = [{ url = "http+srv://_http._tcp.api.service.consul/v1" }] }]

_http._tcp.api.service.consul. 30 IN SRV 0 5 8080 api-1.node.consul. ve ... 0 1 8080 api-2.node.consul. kayıtlarıyla route, request'leri http://api-1.node.consul:8080/v1 ve http://api-2.node.consul:8080/v1 sunucularına 5 ve 1 weight değerleriyle gönderir.

Path Rewrite

r3v3rs3 varsayılan olarak route path'ini request path'inden kaldırır ve kalan kısmı sunucu URL'sinin path'ine ekler. Örneğin path = "/api" değerli bir route ve http://api:8080/v1/ sunucusu için GET /api/users request'i http://api:8080/v1/users adresine gider. Route'un rewrite tablosu path'i şu sırayla değiştirir:

  1. strip_prefix = false route path'ini korur. Bu durumda aynı request http://api:8080/v1/api/users adresine gider.
  2. regex path'teki ilk eşleşmeyi replacement değeriyle değiştirir. Path / ile başlar. ${1} veya ${name} bir capture group ekler. Eşleşme yoksa path değişmez.
  3. add_prefix path'in başına /v2 gibi bir path ekler.

r3v3rs3 query string'i korur. Kimlik doğrulama ve cache, client request'inin path'ini kullanır. r3v3rs3 geçersiz regex'i reddeder. / ile başlamayan veya ? ya da # içeren add_prefix değerini de reddeder.

Aşağıdaki route'larda GET /api/users request'i http://api:8080/v2/users adresine, GET /items/42 request'i http://shop:9000/item/42 adresine gider.

[my-shop]
protocol = "http"
routes = [
  { path = "/api", servers = [{ url = "http://api:8080/" }], rewrite = { add_prefix = "/v2" } },
  { path = "/items", servers = [{ url = "http://shop:9000/" }], rewrite = { strip_prefix = false, regex = "^/items/([0-9]+)$", replacement = "/item/${1}" } },
]

Redirect Kuralları

HTTP / HTTPS proxy'sinin redirects değeri request'e bir redirect ile yanıt verir. Bu durumda request upstream sunucuya gitmez. Her kuralın regex, target ve status değerleri vardır:

Eşleşen ilk kural yanıt verir. r3v3rs3; client IP filtresini, rate limit'i ve upgrade_insecure HTTPS redirect'ini kurallardan önce, kimlik doğrulamayı kurallardan sonra uygular. Geçerli bir header değeri oluşturmayan target eşleşme sayılmaz ve r3v3rs3 bir uyarı log'u yazar. r3v3rs3 başka bir status değerini reddeder. Boş olan veya kontrol karakteri içeren target değerini de reddeder.

WebUI'da her satıra bir kuralı status regex target biçiminde yazın. Orada regex ve target boşluk içeremez. Regex içinde \s, target içinde %20 kullanın.

[my-site]
protocol = "http"
vhosts = ["example.com", "www.example.com"]
redirects = [
  { regex = "^www\\.example\\.com/(.*)$", target = "https://example.com/${1}", status = 301 },
  { regex = "^example\\.com/blog/([0-9]+)$", target = "/posts/${1}" },
]
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:3000/" }] }]

Sabit Response'lar

HTTP / HTTPS proxy'sindeki bir route, request'i servers değerine göndermek yerine response ile her request'e kendisi yanıt verebilir. Bir route'ta servers veya response değerlerinden yalnız biri bulunur. Redirect host veya 404 host için sabit response kullanın.

r3v3rs3; client IP filtresini, rate limit'i, upgrade_insecure HTTPS redirect'ini, redirect kurallarını ve kimlik doğrulamayı sabit response'tan önce uygular. r3v3rs3 hem servers hem response içeren route'u reddeder. Geçersiz target, status veya body değerini de reddeder.

WebUI'da her route için route tipini seçin. Yeni proxy sayfası "Redirect host" ve "404 host" şablonlarını sunar. Servis keşfi label'ları aynı alanları ayarlar, örneğin r3v3rs3.http.old.routes.0.response.type=redirect ve r3v3rs3.http.old.routes.0.response.target=https://example.com. response içeren route, container port'undan varsayılan server almaz.

[old-domain]
protocol = "http"
vhosts = ["old.example.com"]
routes = [{ path = "/", response = { type = "redirect", target = "https://example.com", status = 301 } }]

[catch-all]
protocol = "http"
routes = [{ path = "/", response = { type = "status", status = 404, body = "Not found" } }]

UDP Session'ları

UDP proxy her client adresi için ayrı bir session açar. Her session'ın upstream sunucuya giden kendi socket'i vardır. Bu yüzden upstream sunucu her client'ı farklı bir kaynak porttan görür. r3v3rs3 upstream sunucunun yanıtlarını dinlediği porttan client'a geri gönderir.

İki yönde de session_idle_timeout süresince (varsayılan 60s) paket geçmezse session kapanır. Upstream socket hata verdiğinde veya portun upstream sunucuları ya da idle timeout değeri değiştiğinde de session kapanır. Client'ın sonraki paketi yeni bir session açar. Bir port en fazla 10.000 session tutar. Bu sınıra ulaşılınca r3v3rs3 yeni client'ların paketlerini düşürür.

Upstream Timeout'ları

r3v3rs3 upstream sunucuyu sınırlı bir süre bekler. Timeout değerlerini 500ms, 10s veya 1m gibi yazın.

Timeout dolduğunda HTTP client'ı 504 Gateway Timeout alır, TCP client bağlantısı kapanır. r3v3rs3 sıfır olan connect timeout ve session idle timeout değerlerini reddeder.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
timeouts = { connect = "5s", request = "30s" }
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] },
  { path = "/reports", servers = [{ url = "http://127.0.0.1:9001/" }], timeouts = { connect = "5s", request = "5m" } },
]

[my-database]
protocol = "tcp"
upstream_servers = [{ addr = "/ip4/127.0.0.1/tcp/5432" }]
connect_timeout = "3s"

Request Body Boyutu

HTTP / HTTPS proxy'sinde max_body_size değeri request body'sini byte cinsinden sınırlar. Varsayılan değer 0'dır. 0 limiti kapatır. Bir route, proxy değeri yerine kendi max_body_size değerini kullanabilir. Route'taki 0 değeri o route için limiti kapatır.

r3v3rs3 Content-Length header'ını authentication'dan önce kontrol eder. Bu yüzden limitten büyük bir request 413 Payload Too Large alır ve upstream sunucuya ulaşmaz. Content-Length taşımayan body, örneğin chunked body, r3v3rs3 onu upstream sunucuya gönderirken sayılır. Body upstream sunucu yanıt vermeden limiti geçerse r3v3rs3 upstream request'ini durdurur ve client 413 alır. Upstream sunucu böyle bir body'nin başını alabilir. Limit HTTP/1.1, HTTP/2 ve HTTP/3 request'lerine uygulanır.

[uploads]
protocol = "http"
vhosts = ["files.example.com"]
max_body_size = 1048576
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] },
  { path = "/upload", servers = [{ url = "http://127.0.0.1:9000/" }], max_body_size = 104857600 },
]

Trafik Mirroring

Route'un mirror değeri route request'lerinin bir kopyasını başka sunuculara gönderir. Örneğin yeni bir sürümü gerçek trafikle denemek için kullanılır. r3v3rs3 mirror sunucuların response'larını atar. Kopyayı retry etmez, health check'e ve circuit breaker'a saymaz ve kopyayı beklemez. Bu yüzden client, route sunucusunun response'unu önceki gibi alır.

r3v3rs3 kopyayı request body'sinin tamamını okuduktan sonra gönderir. Hata veren veya client'ın tamamlamadığı body için kopya gönderilmez. Cache'ten gelen response, WebSocket gibi upgrade request'leri ve route'ta 64 kopya gönderilirken gelen request kopyalanmaz. Kopya, header kuralları uygulandıktan sonraki method ve header'ları taşır. Bu yüzden kimlik doğrulamanın kaldırmadığı cookie gibi credential'ları da taşır. Bu verilere güvendiğiniz bir mirror sunucu kullanın. r3v3rs3 1 ile 100 dışındaki percent değerini reddeder.

[my-api]
protocol = "http"
vhosts = ["api.example.com"]
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:9000/" }], mirror = { servers = [{ url = "http://127.0.0.1:9100/" }], percent = 10 } },
]

Load Balancing ve Health Check

Birden fazla upstream sunucusu olan proxy veya HTTP route, trafiği load_balancing değerine göre dağıtır:

Her sunucunun 0 ile 65535 arasında bir weight değeri vardır (varsayılan 1). round_robin her sunucuyu weight değeri kadar kullanır. nginx'in smooth weighted round robin yöntemindeki gibi, bir sunucunun sıraları döngüye yayılır. Örneğin 3 ve 1 weight değerlerinde her dört request'in üçü ilk sunucuya gider. random sunucuyu weight değeriyle orantılı bir olasılıkla seçer. client_ip_hash her sunucuya, weight değeriyle orantılı sayıda client adresi verir. first weight değerini dikkate almaz. weight = 0 olan sunucu, diğer bütün sunucular sağlıksız olsa da yeni trafik almaz. Bu yüzden bir sunucuyu silmeden servis dışına alabilirsiniz. Sunucunun açık TCP bağlantıları ve UDP session'ları devam eder. Her proxy'nin veya HTTP route'unun en az bir sunucusunun weight değeri 0'dan büyük olmalıdır.

HTTP proxy her request için, TCP proxy her bağlantı için, UDP proxy her client session'ı için bir sunucu seçer. Her HTTP route'unun sunucuları ayrı bir gruptur.

TCP proxy seçilen sunucuya bağlanamazsa veya connect timeout dolarsa r3v3rs3 bir kez sıradaki sunucuyu dener.

HTTP proxy, başarısız request'i retry policy'sine göre sıradaki sunucuya yeniden gönderir. retry.attempts (varsayılan 2), bir request'in ilk deneme dahil en fazla kaç kez gönderileceğini belirler ve 1 ile 10 arasında olmalıdır. attempts = 1 retry'ı kapatır. retry.retry_on (varsayılan ["connect"]) retry başlatan hataları listeler:

timeout, http_502, http_503 ve http_504 yalnız RFC 9110'daki idempotent method'ları retry eder: GET, HEAD, OPTIONS, TRACE, PUT ve DELETE. Request timeout her denemeye ayrı uygulanır. Retry, policy sırasındaki sıradaki sunucuya gider ve circuit'i açık sunucuyu atlar. Son denemeden sonra client son response'u veya hatayı alır.

Body'si olan request yalnız body uzunluğu biliniyorsa (örneğin Content-Length ile) ve retry.replay_body_limit (varsayılan 0) byte değerini aşmıyorsa retry edilir. r3v3rs3 bu body'yi memory'de tutar. Değer 0 ise yalnız body'si olmayan request'ler retry edilir. WebSocket gibi upgrade request'leri retry edilmez. Bir route kendi retry ayarıyla proxy'nin retry policy'sini değiştirebilir.

Pasif health check her sunucunun art arda aldığı hataları sayar. Hata, kurulamayan bir bağlantı veya response gelmeyen bir request'tir. health_check.max_fails (varsayılan 1) kadar hatadan sonra sunucu health_check.fail_timeout (varsayılan 30s) süresince sağlıksız sayılır. Sağlıksız sunucu yeni trafiği yalnız sağlıklı sunuculardan sonra alır. Bütün sunucular sağlıksızsa r3v3rs3 trafiği aynı sırayla yine onlara gönderir. Başarılı bir deneme hata sayısını sıfırlar. max_fails = 0 kontrolü kapatır. 500 gibi hata status'lu bir HTTP response başarılı sayılır, çünkü sunucu yanıt vermiştir.

Aktif health check, health_check.interval değeri 0s'den büyükse çalışır (varsayılan 0s, kapalı). r3v3rs3 her interval'de her sunucuyu kontrol eder:

health_check.timeout (varsayılan 5s) her kontrolü sınırlar. Kontrolü geçemeyen sunucu, bir kontrol başarılı olana kadar sağlıksız kalır. Bu kural max_fails = 0 olduğunda da geçerlidir. Başarılı bir request bu durumu bitirmez.

Sunucular, weight değerleri, policy ve health check ayarları değişmediği sürece config reload sonrasında sunucuların sağlık durumu korunur.

Status API'si (GET /api/proxies/{id}/status), her upstream sunucusunun sağlık durumunu upstreams alanında listeler: adres, weight, healthy, art arda hata sayısı failures ve last_error. WebUI'daki proxy listesi sağlıklı sunucu sayısını gösterir ve status'leri 10 saniyede bir yeniler. Sayının title'ı sağlıksız sunucuları son hatalarıyla listeler.

DNS SRV sunucuları olan bir HTTP proxy'si her SRV adını srv alanında da listeler: name, son başarılı sorgunun hedefleri targets (host:port), son sorgu başarısızsa error ve son başarılı sorgunun Unix epoch'tan bu yana saniye cinsinden zamanı refreshed_at. WebUI'daki proxy listesi, sorgusu başarısız olan her SRV adı için bir satır gösterir.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
load_balancing = "round_robin"
health_check = { max_fails = 3, fail_timeout = "10s", interval = "10s", timeout = "2s", path = "/health" }
retry = { attempts = 3, retry_on = ["connect", "http_503"], replay_body_limit = 65536 }
routes = [
  { path = "/", servers = [{ url = "http://10.0.0.1:9000/" }, { url = "http://10.0.0.2:9000/", weight = 3 }] },
]

[my-database]
protocol = "tcp"
load_balancing = "first"
upstream_servers = [
  { addr = "/ip4/10.0.0.1/tcp/5432" },
  { addr = "/ip4/10.0.0.2/tcp/5432" },
]

Circuit Breaker

Circuit breaker, HTTP veya TCP proxy'nin hata veren bir upstream sunucusuna giden trafiği bir süre durdurur. Varsayılan olarak kapalıdır. Her HTTP route'undaki her sunucunun kendi circuit'i vardır. UDP proxy'lerde circuit breaker yoktur.

Pasif health check 5xx response'u yine başarılı sayar, çünkü sunucu yanıt vermiştir. Status API'si circuit'i kapalı olmayan sunucu için "circuit": "open" veya "circuit": "half_open" gösterir. WebUI'daki proxy listesi böyle bir sunucuyu sağlıklı saymaz ve sayının title'ında circuit durumunu yazar.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
circuit_breaker = { enabled = true, failure_ratio = 50, min_requests = 20, window = "10s", open_duration = "30s" }
routes = [
  { path = "/", servers = [{ url = "http://10.0.0.1:9000/" }, { url = "http://10.0.0.2:9000/" }] },
]

Sticky Session'lar

sticky, HTTP proxy'nin her client'ını bir cookie ile tek bir upstream sunucusunda tutar. Varsayılan olarak kapalıdır.

TCP veya UDP proxy ve cookie saklamayan client'lar bunun yerine load_balancing = "client_ip_hash" kullanabilir.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
sticky = { enabled = true, name = "app_server", max_age = "1h" }
routes = [
  { path = "/", servers = [{ url = "http://10.0.0.1:9000/" }, { url = "http://10.0.0.2:9000/" }] },
]

Client IP

CDN veya load balancer arkasında r3v3rs3'ün TCP peer'ı ziyaretçi değil, edge sunucusudur. r3v3rs3 gerçek client IP adresini yalnız peer güvenilirse belirler:

Peer güvenilirse r3v3rs3 client IP adresini şu sırayla okur:

  1. Sağlayıcı header'ı: Cloudflare için CF-Connecting-IP, Bunny CDN için X-Real-IP, Amazon CloudFront için CloudFront-Viewer-Address.
  2. X-Forwarded-For içinde güvenilen bir proxy'ye veya bilinen bir CDN edge'ine ait olmayan en sağdaki adres.

r3v3rs3 bulduğu adresi upstream sunucuya X-Real-IP header'ında gönderir. Gelen X-Forwarded-For ve Forwarded zincirlerine dokunmaz. Peer güvenilir değilse r3v3rs3 Forwarded, X-Forwarded-For, X-Real-IP, CF-Connecting-IP, True-Client-IP, CloudFront-Viewer-Address, Fastly-Client-IP ve Incap-Client-IP header'larını siler, çünkü client bu header'lara sahte değer yazabilir.

CDN IP aralıkları binary'ye gömülüdür ve r3v3rs3 bu listeyi her gün yeniden indirir. Son indirilen liste config dizinindeki cdn-ranges.json dosyasına yazılır. İndirme başarısız olursa r3v3rs3 son başarılı listeyi kullanmaya devam eder. Listenin durumunu "Ayarlar" bölümünde görebilir, "Şimdi Yenile" butonuyla listeyi hemen yenileyebilirsiniz.

Akamai edge IP aralıklarını yayınlamaz. Akamai kullanıyorsanız Site Shield aralıklarınızı "Güvenilen Proxy'ler" listesine ekleyin.

IP filtresi

Her HTTP / HTTPS proxy'sinde client'ları IP adresine göre engelleyebilir veya yalnız belirli adreslere izin verebilirsiniz. Filtre, "Client IP" bölümünde belirlenen adrese bakar. Bu yüzden CDN veya güvenilen bir proxy arkasında da doğru çalışır.

Bir adres iki listeye de uyuyorsa engellenir.

Bir route, "Bu Route için Ayrı IP Filtresi Kullan" seçeneğiyle proxy listeleri yerine yalnız kendi listelerini kullanır. Route'un iki listesi de boşsa bu route'a her client erişebilir.

[my-proxy]
protocol = "http"
vhosts = ["example.com"]
ip_filter = { allow = ["192.168.0.0/16"], deny = ["192.168.10.0/24"] }
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:8080/" }] },
  { path = "/public", servers = [{ url = "http://127.0.0.1:8080/public" }], ip_filter = {} },
]

Rate limit

Her HTTP / HTTPS proxy'sinde bir client IP adresinin gönderebileceği request sayısını sınırlayabilirsiniz. r3v3rs3 request'leri "Client IP" bölümünde belirlenen adrese göre sayar.

Limiti aşan client, Retry-After header'ıyla birlikte 429 Too Many Requests alır.

Bir route, "Bu Route için Ayrı Rate Limit Kullan" seçeneğiyle proxy limiti yerine kendi limitini kullanabilir. Bu seçeneği açmayan route'lar her client için ortak bir sayaç kullanır. Route ayarında request değeri 0 ise o route'ta limit uygulanmaz.

r3v3rs3 sayaçları memory'de tutar. Config değiştiğinde sayaçlar korunur; yalnız limitin kendisi değişirse sıfırlanır. Sunucuyu yeniden başlatmak da sayaçları sıfırlar.

[my-proxy]
protocol = "http"
vhosts = ["example.com"]
rate_limit = { requests = 10, per = "second", burst = 20 }
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:8080/" }] },
  { path = "/login", servers = [{ url = "http://127.0.0.1:8080/login" }], rate_limit = { requests = 5, per = "minute" } },
]

Kimlik doğrulama

Her HTTP / HTTPS proxy'sinde "Kimlik Doğrulama" bölümünden kimlik doğrulamayı zorunlu hale getirebilirsiniz. Bir route, "Bu Route için Ayrı Kimlik Doğrulama Kullan" seçeneğiyle proxy ayarı yerine kendi ayarını kullanabilir. O route'u bütün client'lara açmak için "Yok" seçin.

r3v3rs3 kimlik doğrulamayı IP filtresinden, rate limit'ten ve HTTPS redirect'inden sonra yapar. Bu sayede "HTTP'yi Otomatik Olarak HTTPS'e Yönlendir" seçeneği açıksa tarayıcı kimlik bilgilerini şifreli bağlantı üzerinden gönderir.

Basic Auth

Geçerli kullanıcı adı ve parola göndermeyen client'lar WWW-Authenticate: Basic realm="..." header'ıyla birlikte 401 Unauthorized alır. Tarayıcı bunun üzerine giriş penceresini açar.

r3v3rs3 parolaları argon2 hash olarak saklar; düz metin parolayı hiçbir zaman kaydetmez. Admin API hash'i döndürmez. Parolası olan kullanıcı için password_set: true döndürür. Parolayı değiştirmek istemiyorsanız parola alanını boş bırakın. r3v3rs3, request'i upstream sunucuya göndermeden önce Authorization header'ını siler.

Argon2 kasıtlı olarak CPU harcar. r3v3rs3 her kimlik bilgisini bir kez doğrular ve sonucu config değişene kadar memory'de tutar. Parola denemelerini sınırlamak için rate limit kullanın.

proxies.toml dosyasında password_hash yerine password yazabilirsiniz. r3v3rs3 başlarken bu değeri hash'e çevirir.

[my-proxy]
protocol = "http"
vhosts = ["example.com"]
auth = { type = "basic", realm = "Staff", users = [{ username = "alice", password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..." }] }
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:8080/" }] },
  { path = "/health", servers = [{ url = "http://127.0.0.1:8080/health" }], auth = { type = "none" } },
]

Bearer Token

Client, proxy'de tanımlı token'lardan birini Authorization: Bearer <token> header'ıyla göndermelidir. Token göndermeyen client WWW-Authenticate: Bearer realm="r3v3rs3" ile birlikte 401 Unauthorized alır. Yanlış token gönderen client da aynı response'u alır; bu response'ta ayrıca error="invalid_token" bulunur.

r3v3rs3 her token'ın SHA-256 digest'ini saklar; düz metin token'ı hiçbir zaman kaydetmez. Digest'leri sabit sürede karşılaştırır. Admin API digest'i döndürmez. Değeri olan token için token_set: true döndürür. Token'ı değiştirmek istemiyorsanız token alanını boş bırakın. r3v3rs3, request'i upstream sunucuya göndermeden önce Authorization header'ını siler. Bu yüzden bearer kimlik doğrulaması kullanan bir route'ta upstream sunucuya kendi bearer token'ı ulaşmaz.

proxies.toml dosyasında token_hash yerine token yazabilirsiniz. r3v3rs3 başlarken bu değeri digest'e çevirir.

[my-api]
protocol = "http"
vhosts = ["api.example.com"]
auth = { type = "bearer", tokens = [{ name = "ci", token_hash = "<sha-256 hex digest>" }] }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

Forward Auth

r3v3rs3 her request'e izin verilip verilmeyeceğini oauth2-proxy veya Authelia gibi harici bir servise sorar. Bu özellik nginx'teki auth_request gibi çalışır.

r3v3rs3 her client request'inde auth URL'ine bir GET request'i gönderir. Bu request, bağlantı header'ları ve Host dışında client'ın bütün header'larını taşır. Bunlara ek olarak şu header'lar da eklenir:

HeaderDeğer
X-Forwarded-MethodClient request'inin method'u.
X-Forwarded-Protohttp veya https.
X-Forwarded-HostClient request'inin host'u.
X-Forwarded-UriClient request'inin path ve query kısmı.
X-Forwarded-For"Client IP" bölümünde belirlenen client IP adresi.

Auth request'i, upstream request'leriyle aynı root sertifikalarına güvenir. Proxy'nin client sertifikasını da gönderir. Ayrıntılar için "Upstream client sertifikaları" bölümüne bakın.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
auth = { type = "forward", url = "http://127.0.0.1:4180/oauth2/auth", response_headers = ["X-Auth-Request-User"], timeout = "10s" }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

Panel Session

Client'lar, yönetim panelinde kullandığınız r3v3rs3 hesaplarıyla giriş yapar. Kendi kimlik doğrulaması olmayan bir web uygulamasını korumak için bu yöntemi kullanabilirsiniz.

Bu kimlik doğrulamayı kullanan her route, kendi path'inin altında şu endpoint'leri sunar. / route'unun giriş sayfası /.r3v3rs3/auth/login adresindedir. /admin route'unda bu adres /admin/.r3v3rs3/auth/login olur.

EndpointMethodİşlem
.r3v3rs3/auth/loginGETGiriş formunu gösterir.
.r3v3rs3/auth/loginPOSTKullanıcı adını, parolayı ve TOTP kodunu kontrol eder, ardından session cookie'sini ayarlar.
.r3v3rs3/auth/logoutPOSTSession'ı sonlandırır ve session cookie'sini siler.

TOTP kodu yalnız TOTP'si açık hesaplarda istenir. r3v3rs3_session cookie'si HttpOnly ve SameSite=Lax attribute'larını taşır; HTTPS ve HTTP/3 bağlantılarında Secure attribute'u da eklenir. Cookie'nin Domain attribute'u yoktur ve r3v3rs3 bir session'ı yalnız client'ın giriş yaptığı host'ta kabul eder. r3v3rs3, request'i upstream sunucuya göndermeden önce session cookie'sini siler.

Yalnız proxy'yi görebilen hesaplar giriş yapar. Proxy listesi olan bir hesap yalnız listesindeki proxy'leri görür. r3v3rs3 hesabı her request'te kontrol eder. Hesap silinirse, hesap değişirse veya proxy hesabın listesinden çıkarılırsa session sona erer. r3v3rs3 session'ın hesabını kaydetmeye başlamadan önce açılan session'lar geçersizdir. Bu durumda client yeniden giriş yapar.

config.toml dosyasındaki [admin] ayarları bu session'lara da uygulanır:

r3v3rs3 session'ları memory'de tutar. Sunucu yeniden başladığında bütün session'lar sona erer. Uygulamanıza çıkış butonu eklemek için şu formu kullanabilirsiniz:

<form method="post" action="/.r3v3rs3/auth/logout"><button>Sign Out</button></form>
[my-app]
protocol = "http"
vhosts = ["app.example.com"]
auth = { type = "session" }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

Erişim listeleri

Erişim listesi, bir IP filtresini ve bir kimlik doğrulamayı bir adla tutar. Birden fazla proxy ve route aynı erişim listesini kullanabilir. Liste değişince değişiklik yeniden başlatma olmadan hepsine uygulanır.

WebUI'daki "Erişim Listeleri" sayfası listeleri ekler, değiştirir ve siler. HTTP / HTTPS proxy'nin "Erişim Listesi" alanı proxy için bir liste seçer. Route'un "Erişim Listesi" alanı route için bir liste seçer. Yönetim API'sinde ve proxies.toml dosyasında access_list alanı bir proxy'nin veya route'un listesini ayarlar.

Config dizinindeki access_lists.toml dosyası listeleri tutar. Dosya parola hash'lerini ve token digest'lerini taşır. Bu yüzden r3v3rs3 dosyayı 0600 moduyla yazar. Yönetim API'si, proxy kimlik doğrulamasında olduğu gibi hash'leri döndürmez.

# access_lists.toml
[office]
name = "Office"
ip_filter = { allow = ["192.168.0.0/16"] }
auth = { type = "basic", realm = "Office", users = [{ username = "alice", password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..." }] }
# proxies.toml
[my-app]
protocol = "http"
vhosts = ["app.example.com"]
access_list = "office"
routes = [
  { path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] },
  { path = "/health", servers = [{ url = "http://127.0.0.1:9000/health" }], ip_filter = {}, auth = { type = "none" } },
]
Endpointİşlem
GET /api/access_listsErişim listelerini listeler.
POST /api/access_listsBir erişim listesi ekler.
PUT /api/access_lists/{id}Bir erişim listesini değiştirir. Yeni secret'ı olmayan kullanıcı veya token hash'ini korur.
DELETE /api/access_lists/{id}Bir erişim listesini siler.

Her hesap listeleri okur. Listeleri yalnız admin veya proxy listesi olmayan editör değiştirir. Ayrıntılar için Hesaplar sayfasına bakın.

Header kuralları

Proxy'den geçen request ve response'ların header'larını "Header Kuralları" bölümünden değiştirebilirsiniz. Bir route, "Bu Route için Ayrı Header Kuralları Kullan" seçeneğiyle proxy kuralları yerine kendi kurallarını kullanabilir.

Her satıra bir kural yazın:

Kuralİşlem
set Name: valueHeader'ın mevcut değerlerini bu değerle değiştirir.
append Name: valueMevcut değerleri koruyarak bir değer ekler.
remove NameHeader'ı siler.

Boş satırlar ve # ile başlayan satırlar atlanır.

Değerlerde şu değişkenleri kullanabilirsiniz. Süslü parantez yazmak için {{ ve }} kullanın.

DeğişkenDeğer
{client_ip}"Client IP" bölümünde belirlenen client IP adresi.
{host}İstenen host adı.
{scheme}http veya https.
{request_id}Rastgele 32 karakterlik hex ID. Aynı request'in request ve response kuralları aynı ID'yi kullanır.
{route}Eşleşen route'un path'i, örneğin /api.
{client_cert_subject}Doğrulanan client sertifikasının subject değeri, örneğin CN=client.example.com. Client sertifikası yoksa boştur.
{client_cert_fingerprint}Doğrulanan client sertifikasının hex SHA-256 fingerprint'i. Client sertifikası yoksa boştur.

Client aynı adlı bir header'ı kendisi de gönderebilir. Client sertifikası header'ları için append yerine set kullanın. Böylece kural client'ın gönderdiği değeri değiştirir.

Kurallar Connection, Content-Length, Host, Keep-Alive, Proxy-Connection, TE, Trailer, Transfer-Encoding ve Upgrade header'larını değiştiremez, çünkü bu header'lar bağlantıyı ve mesajın framing'ini kontrol eder.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
headers = { request = [{ action = "set", name = "X-Request-Id", value = "{request_id}" }, { action = "remove", name = "X-Debug" }], response = [{ action = "set", name = "X-Frame-Options", value = "DENY" }, { action = "remove", name = "Server" }] }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

Compression

Proxy'den geçen response'ları "Compression" bölümünden sıkıştırabilirsiniz. Bir veya daha fazla encoding seçtiğinizde compression açılır. Hiçbir encoding seçili değilse compression kapalıdır.

EncodingContent-EncodingSeviye
BrotlibrQuality 4
ZstandardzstdLevel 3
GzipgzipLevel 6

r3v3rs3 request'in Accept-Encoding header'ını okur ve client'ın kabul ettiği encoding'lerden q değeri en yüksek olanı seçer. Birden fazla encoding aynı q değerine sahipse algorithms listesindeki sıra geçerli olur. Panelde bu sıra, encoding'leri seçtiğiniz sıradır.

r3v3rs3 bir response'u yalnız şu koşulların hepsi sağlanırsa sıkıştırır:

Bu koşulları sağlayan response'larda r3v3rs3 Vary header'ına Accept-Encoding ekler. Response'u sıkıştırdığında Content-Length ve Accept-Ranges header'larını da siler, strong ETag değerini weak ETag değerine çevirir. Response header kuralları compression'dan önce çalıştığı için bir kural Cache-Control: no-transform ayarlayarak compression'ı engelleyebilir.

AyarVarsayılan
algorithmsBoş. Compression kapalıdır.
min_size1024 byte
mime_typestext/*, application/javascript, application/json, application/manifest+json, application/wasm, application/xml, application/xhtml+xml, application/rss+xml, application/atom+xml, image/svg+xml, font/otf, font/ttf
[my-app]
protocol = "http"
vhosts = ["app.example.com"]
compression = { algorithms = ["br", "zstd", "gzip"], min_size = 1024, mime_types = ["text/*", "application/json"] }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

Cache

Proxy'den geçen response'ları "Cache" bölümünden memory'de saklayabilirsiniz. Cache'teki bir response, upstream sunucuya gidilmeden doğrudan client'a gönderilir. Her proxy'nin ayrı bir cache'i vardır ve proxy'nin bütün route'ları bu cache'i ortak kullanır.

AyarVarsayılanAçıklama
enabledfalseCache'i açar.
max_size67108864 (64 MiB)Saklanan response'lar için byte cinsinden memory limiti. Cache dolunca r3v3rs3 en az kullanılan response'ları siler.
max_entry_size1048576 (1 MiB)Body'si bu değerden büyük response'lar saklanmaz.
default_ttl0sCache-Control: max-age, s-maxage veya Expires içermeyen response'un geçerlilik süresi. Değer 0s ise r3v3rs3 böyle bir response'u yalnız ETag veya Last-Modified header'ı varsa saklar ve her request'te yeniden doğrular.

r3v3rs3 cache'i yalnız Range, Upgrade ve Cache-Control: no-store içermeyen GET ve HEAD request'lerinde kullanır. HEAD request'ine saklanan GET response'u verilir. Client Cache-Control: no-cache veya Pragma: no-cache gönderirse r3v3rs3 cache'e bakmadan request'i upstream sunucuya iletir ve gelen yeni response'u saklar. Cache key, istenen host ile request'in path ve query değerinden oluşur. Bu yüzden load balancing'in seçtiği upstream sunucu key'i değiştirmez.

r3v3rs3 bir response'u yalnız şu koşulların hepsi sağlanırsa saklar:

Geçerlilik süresi için sırasıyla s-maxage, max-age, Expires ve default_ttl değerlerine bakılır. Cache-Control: no-cache bu süreyi sıfır yapar. Saklanan response'un yaşına upstream response'taki Age header'ının değeri de eklenir.

Saklanan response'un süresi dolmuşsa ve response'ta ETag veya Last-Modified header'ı varsa r3v3rs3 If-None-Match veya If-Modified-Since ile koşullu bir request gönderir. Upstream sunucu 304 Not Modified dönerse r3v3rs3 saklanan header'ları günceller ve cache'teki response'u gönderir. Validator'ı olan response, süresi dolduktan sonra da bir saat cache'te kalır. Eşleşen If-None-Match veya If-Modified-Since header'ı gönderen client, cache'ten 304 Not Modified alır.

Her cache key için tek bir response saklanır. Response'un Vary header'ı request header'larını listeliyorsa saklanan response yalnız bu header'larda aynı değerleri gönderen request'lere verilir.

r3v3rs3, cache'i kullanabilecek request'lerdeki Accept-Encoding header'ını siler. Böylece upstream sunucu response'ları encode etmeden gönderir ve "Compression" ayarları response'u her client için ayrıca sıkıştırır. Bu request'lere verilen response'larda X-Cache header'ı bulunur: cache'ten gelen response için HIT, upstream sunucudan gelen response için MISS. Cache'ten gelen response'ta ayrıca Age header'ı vardır.

Bir proxy'nin cache'ini boşaltmak için proxy listesindeki "Temizle" linkine tıklayın veya DELETE /api/proxies/{id}/cache request'i gönderin. Saklanan response'lar, cache ayarları değişene veya sunucu yeniden başlatılana kadar memory'de kalır.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
cache = { enabled = true, max_size = 67108864, max_entry_size = 1048576, default_ttl = "5m" }
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

HTTP/2

r3v3rs3, HTTP ve HTTPS proxy'lerinde hem upstream hem de downstream bağlantılarda HTTP/2 destekler.

Downstream tarafında client destekliyorsa HTTP/2 otomatik olarak seçilir. Çoğu web tarayıcısı HTTP/2'yi yalnız TLS üzerinden kullanır, çünkü sunucunun HTTP/2 desteklediğini ALPN (Application-Layer Protocol Negotiation) ile öğrenir.

Upstream tarafında r3v3rs3, HTTPS sunucularına ALPN ile h2 ve http/1.1 önerir ve sunucunun seçtiği protokolü kullanır. Düz HTTP bağlantısında protokol seçimi yapılamadığı için düz HTTP sunucularına HTTP/1.1 ile bağlanılır. Proxy'nin düz HTTP sunucuları prior knowledge ile HTTP/2 (h2c) kabul ediyorsa h2c = true ayarlayın. WebSocket ve diğer upgrade request'leri her zaman HTTP/1.1 kullanır. Bir portta aynı client sertifikasını ve aynı connect timeout değerini kullanan proxy'ler upstream bağlantılarını ortak kullanır. Bu yüzden tek bir HTTP/2 upstream bağlantısı birçok client'ın request'lerini taşır.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
h2c = true
routes = [{ path = "/", servers = [{ url = "http://127.0.0.1:9000/" }] }]

WebSocket

r3v3rs3, HTTP ve HTTPS proxy'lerinde WebSocket'i (ve HTTP upgrade'i) destekler. Bunun için ayrıca bir ayar yapmanız gerekmez.

HTTP/3

HTTP/3 proxy'lemeyi açmak için "Portlar" bölümünde bir QUIC portu bağlayın ve protokol olarak "QUIC üzerinden HTTP (HTTP/3)" seçin. HTTP/3 yalnız gelen bağlantılarda desteklenir. Upstream bağlantılar HTTP/2 veya HTTP/1.1 kullanır.

WebTransport desteklenmez.

Upstream client sertifikaları

Upstream sunucu client sertifikası isteyebilir (mutual TLS). Sertifikayı HTTP / HTTPS proxy'sinin veya TCP / TLS üzerinden TCP proxy'sinin "Client Sertifikası" alanında seçin. Listede private key'i olan client sertifikaları görünür. Ayrıntılar için "Client sertifikaları" bölümüne bakın.

TCP proxy'sinde TLS bekleyen upstream sunucusu için "TLS ile Bağlan" seçeneğini açın. Bu sunucunun adresi /tls ile biter.

[my-app]
protocol = "http"
vhosts = ["app.example.com"]
client_cert = "a1b2c3d"
routes = [{ path = "/", servers = [{ url = "https://10.0.0.5:8443/" }] }]

[my-database]
protocol = "tcp"
client_cert = "a1b2c3d"
upstream_servers = [{ addr = "/dns/db.internal/tcp/5433/tls" }]

PROXY protocol gönderme

TCP / TLS üzerinden TCP proxy'si client adresini upstream sunuculara gönderebilir. Versiyonu "PROXY Protocol Gönder" alanında seçin. Bundan sonra her upstream bağlantısı bir PROXY protocol header'ı ile başlar. TLS upstream sunucusunda header TLS handshake'ten önce gider.

Bunu yalnız bütün upstream sunucular header'ı okuyorsa açın, çünkü header'ı okumayan sunucu onu veri olarak alır. HTTP / HTTPS proxy'leri PROXY protocol göndermez. Onların yerine Forwarded ve X-Forwarded-For header'larını kullanın.

[my-mail]
protocol = "tcp"
proxy_protocol = "v2"
upstream_servers = [{ addr = "/dns/mail.internal/tcp/25" }]

Sertifikalar

Sunucu sertifikaları

TLS üzerinden TCP ve HTTPS proxy'leri için bir sunucu sertifikası gerekir. Sunucu sertifikasını üç yolla ekleyebilirsiniz:

  1. Self-signed bir sertifika oluşturun.
  2. Bir dosyadan sertifika içe aktarın (yalnız PEM formatı).
  3. Sertifikayı ACME ile otomatik alın.

r3v3rs3, TLS client hello mesajındaki SNI (Server Name Indication) değerine göre uygun sertifikayı otomatik olarak seçer.

Client sertifikaları

TLS sunucusu, client'ı doğrulamak için client sertifikası isteyebilir. "Client Sertifikaları" sekmesinde client sertifikasını iki yolla ekleyebilirsiniz:

  1. Self-signed bir sertifika oluşturun ve sertifika türü olarak "Client Sertifikası" seçin. r3v3rs3 sertifikaya clientAuth extended key usage değerini ekler. Seçilen CA sertifikası sertifikayı imzalar.
  2. Sertifika zincirini ve private key'i dosyadan içe aktarın (yalnız PEM formatı). Client sertifikası için private key gerekir.

Proxy, client sertifikasını upstream sunucularına gönderir. Ayrıntılar için "Upstream client sertifikaları" bölümüne bakın.

Root sertifikaları

Upstream sunucunuz sistemin güvenmediği sertifikalar kullanıyorsa bu sertifikaları root sertifika deposuna eklemeniz gerekir. r3v3rs3, sistemin root sertifikalarına ek olarak bu depodaki root sertifikalarının imzaladığı bütün sertifikalara da otomatik olarak güvenir.

Self-signed bir sertifika oluşturduğunuzda r3v3rs3 bir CA sertifikası da oluşturur ve onu root sertifika deposuna ekler.

Süre uyarıları

Sertifika listesi, "Sertifika Süre Uyarısı" (varsayılan 14days) süresi içinde sona erecek sertifikayı "Süresi dolmak üzere" ile işaretler. Süresi dolmuş sertifikayı "Süresi doldu" ile işaretler.

Bildirimler

r3v3rs3 şu olaylar için bildirim webhook'una bir JSON POST isteği gönderir:

OlayNe zaman
certificate_expiringBir sertifika "Sertifika Süre Uyarısı" süresi içinde sona erer.
certificate_expiredBir sertifikanın süresi dolmuştur.
acme_order_failedBir ACME order başarısız olmuştur. Başarısız her order bir olay gönderir.
testBir admin test bildirimi göndermiştir.
{"event": "certificate_expiring", "time": 1757894400, "node": "proxy-1", "certificate": {"id": "a1b2c3d", "san": ["example.com"], "not_after": 1759104000}}

Webhook'u "Ayarlar" sayfasının "Bildirimler" bölümünde ayarlayın. "Test Bildirimi Gönder" butonu kayıtlı ayarlardaki webhook'a bir test olayı gönderir. POST /api/config/notifications/test aynı işi yapar. Bu endpoint'i yalnız admin hesabı çağırabilir. Webhook ayarlı değilse yanıt 400 notification_webhook_missing olur. Webhook isteği başarısız olursa yanıt 502 notification_failed olur.

[notifications]
cert_expiry_warning = "14days"
webhook = { url = "https://hooks.example.com/r3v3rs3", token = "<token>", timeout = "10s" }

config.toml dosyası token'ı düz metin olarak tutar.

Birden fazla sertifikayı silme

Listedeki checkbox'larla sertifikaları seçin ve "Seçilenleri Sil" butonuna tıklayın. {"ids": [...]} body'si ile gönderilen POST /api/certs/delete isteği en fazla 200 id için aynı işi yapar. Yanıt, istekteki sırayla her id için bir sonuç taşır:

SonuçAnlamı
deletedr3v3rs3 sertifikayı sildi.
in_useBir port, proxy veya discovery provider sertifikayı kullanıyor. Sertifika kalır.
read_onlySertifikayı servis keşfi yönetiyor. Sertifika kalır.
not_foundBu id'ye sahip sertifika yok.
failedStorage sertifikayı silmedi. Sunucu log'u nedeni yazar.

İstekte tekrar eden bir id tek bir sonuç alır.

ACME

r3v3rs3, sertifikaları ACME (Automatic Certificate Management Environment) ile otomatik alabilir. Let's Encrypt, ZeroSSL ve Google Trust Services gibi birçok sertifika otoritesi ACME'yi destekler.

Bir ACME kaydı bir veya daha fazla domain adı içerir. Domain adlarını "Domain Adları" alanına virgülle ayırarak yazın, örneğin example.com, *.example.com. Sertifika her domain adını Subject Alternative Name olarak içerir. r3v3rs3 sertifikayı süresi dolmadan otomatik yeniler. Bir order başarısız olursa r3v3rs3 bir saat sonra yeniden order oluşturur.

Challenge'lar

Sertifika otoritesi, her domain adını sizin yönettiğinizi bir challenge ile doğrular. Challenge'ı "Challenge" alanından seçin.

ChallengeNasıl çalışırGereksinimler
HTTP-01Sertifika otoritesi http://<domain>/.well-known/acme-challenge/<token> adresine istek gönderir ve r3v3rs3 yanıt verir.Her domain adı r3v3rs3'e çözümlenmeli, TCP 80 portu açık ve internetten erişilebilir olmalıdır. Wildcard domain adı kullanılamaz.
TLS-ALPN-01Sertifika otoritesi, domain adının 443 portuna acme-tls/1 ALPN protokolüyle bir TLS bağlantısı açar ve r3v3rs3 bir challenge sertifikasıyla yanıt verir.Her domain adı r3v3rs3'e çözümlenmeli, TCP 443 portu açık ve internetten erişilebilir olmalıdır. Wildcard domain adı kullanılamaz.
DNS-01r3v3rs3, DNS provider'ınızın API'si ile _acme-challenge.<domain> TXT kaydını oluşturur.Aşağıdaki tablodaki DNS provider'larından biri ve zone'u düzenleyebilen bir API credential'ı.

*.example.com gibi bir wildcard domain adı DNS-01 gerektirir. r3v3rs3, HTTP-01 veya TLS-ALPN-01 ile girilen wildcard domain adını reddeder.

TLS-ALPN-01 challenge'ı sürerken her TLS portu ve her HTTPS portu, yalnız acme-tls/1 sunan bir client'a challenge sertifikasıyla yanıt verir. Diğer client'lar portun sertifikasını alır. TLS portu, challenge bağlantısı için upstream sunucusuna bağlanmaz. Hiçbir TCP veya HTTP portu "TLS-ALPN Challenge Adresi" ayarındaki portu kullanmıyorsa r3v3rs3, challenge'lar bitene kadar bu adresi dinler. 443 portundaki TLS'siz bir HTTP portu challenge'a yanıt veremez.

DNS-01

r3v3rs3 her domain adı için şu adımları uygular:

  1. Provider API'si ile domain adının zone'unu bulur. Adı içeren en uzun zone kullanılır.
  2. _acme-challenge.<domain> TXT kaydını 60 saniyelik TTL ile oluşturur. Linode'da TTL, Linode'un kabul ettiği en düşük değer olan 300 saniyedir. Porkbun'a TTL gönderilmez, bu yüzden kayıt hesabın en düşük TTL değerini alır. Gandi'de TTL, Gandi'nin kabul ettiği en düşük değer olan 300 saniyedir. deSEC'te TTL 3600 saniyedir, çünkü deSEC domain'in minimum TTL değerinden düşük bir TTL'i reddeder. Gandi, deSEC, Azure DNS ve Google Cloud DNS bir adın bütün kayıt kümesini yazar. Bu yüzden r3v3rs3 kendi değerlerini mevcut TXT değerlerine ekler ve yalnız kendi değerlerini siler. *.example.com için kayıt adı example.com ile aynıdır: _acme-challenge.example.com. Bu yüzden kayıt iki değer taşır.
  3. TXT değerleri görünene kadar DNS'i 5 saniyede bir sorgular, en fazla 5 dakika bekler. Sorgulanan DNS sunucusunu "DNS Challenge Resolver" ayarı belirler. Ayar boşsa r3v3rs3 sistem resolver'ını kullanır.
  4. Sertifika otoritesine challenge'ların hazır olduğunu bildirir ve doğrulama için en fazla 3 dakika bekler.
  5. TXT kayıtlarını siler. Order başarısız olsa da kayıtları siler.

Sistem resolver'ı cache'teki eski yanıtları döndürebilir. Propagation kontrolü sık başarısız oluyorsa "DNS Challenge Resolver" ayarına 1.1.1.1:53 gibi public bir resolver veya zone'un authoritative name server'ını yazın.

DNS providerCredential'larGereken izinler
CloudflareAPI TokenZone için Zone:Read ve DNS:Edit.
Route 53Access Key ID, Secret Access Keyroute53:ListHostedZones ve route53:ChangeResourceRecordSets. Private hosted zone'lar atlanır.
Azure DNSTenant ID, Client ID, Client Secret, Subscription IDZone'larda DNS Zone Contributor rolü olan bir service principal. r3v3rs3, subscription'daki DNS zone'larını listeler ve resource group'u zone ID'sinden alır.
Google Cloud DNSService Account Key (JSON), Project IDZone'ların projesinde DNS Administrator rolü (roles/dns.admin) olan bir service account'un JSON key dosyası. Project ID boşsa r3v3rs3 key'in projesini kullanır. Private zone'lar atlanır.
deSECAPI TokenHesabın bir token'ı. Policy ile sınırlanmış bir token, _acme-challenge TXT kayıt kümelerine yazma izni vermelidir.
DigitalOceanAPI TokenDomain'leri okuyabilen, domain kayıtlarını oluşturup silebilen bir token.
GandiAPI TokenDomain'leri okuyabilen ve LiveDNS kayıtlarını değiştirebilen bir personal access token.
Hetzner CloudAPI TokenOkuma ve yazma yetkisi olan bir Hetzner Cloud proje token'ı. Zone, Hetzner Cloud DNS'te olmalıdır.
LinodeAPI TokenDomains için okuma ve yazma yetkisi olan bir personal access token.
VultrAPI KeyHesabın API key'i.
PorkbunAPI Key, Secret API KeyPorkbun domain yönetiminde domain için "API Access" açık olmalıdır.
OVHcloudAPI Endpoint, Application Key, Application Secret, Consumer KeyGET /domain/zone, POST /domain/zone/* ve DELETE /domain/zone/* yetkileri olan bir consumer key. Endpoint ovh-eu, ovh-ca, ovh-us, kimsufi-eu, kimsufi-ca, soyoustart-eu veya soyoustart-ca olabilir. r3v3rs3, kayıtları oluşturduktan sonra ve sildikten sonra zone'u refresh eder.
WebhookWebhook URL, Bearer TokenTXT kayıtlarını oluşturan ve silen kendi servisiniz. Aşağıdaki "DNS webhook" bölümüne bakın.
ExecProgram Yolur3v3rs3 host'unda TXT kayıtlarını oluşturan ve silen bir program. Aşağıdaki "DNS exec" bölümüne bakın.
RFC 2136DNS Sunucusu, Zone, TSIG Key Adı, TSIG Algoritması, TSIG SecretDynamic update kabul eden bir DNS sunucusu, örneğin BIND, Knot DNS veya PowerDNS. Aşağıdaki "RFC 2136" bölümüne bakın.

r3v3rs3 bu API'lerin mock sunucularıyla ve Pebble test sertifika otoritesiyle test edilir. Gerçek provider hesaplarıyla test edilmez.

DNS webhook

Webhook provider'ı TXT kayıtlarını bir DNS hosting servisinin API'si yerine kendi servisinize gönderir. r3v3rs3 her challenge adı için webhook URL'ine bu JSON body ile bir POST isteği gönderir:

{"action": "add", "fqdn": "_acme-challenge.example.com", "values": ["<TXT değeri>"]}

Webhook URL'i HTTPS kullanmalıdır. HTTP yalnız loopback adresinde kullanılabilir, örneğin http://127.0.0.1:8080/acme.

DNS exec

Exec provider'ı her TXT değeri için r3v3rs3 host'unda bir program çalıştırır:

<program> add <fqdn> <değer>
<program> remove <fqdn> <değer>

Program, config.toml dosyasının [acme_exec] bölümünde olmalıdır:

[acme_exec]
programs = ["/usr/local/bin/r3v3rs3-dns-hook"]
timeout = "30s"

RFC 2136

RFC 2136 provider'ı, zone'un primary DNS sunucusuna dynamic update gönderir. Her mesaj bir TSIG imzası taşır.

Bir BIND örneği. tsig-keygen -a hmac-sha256 r3v3rs3 komutu yeni bir secret ile key bloğunu yazar:

key "r3v3rs3" {
    algorithm hmac-sha256;
    secret "<base64 secret>";
};

zone "example.com" {
    type primary;
    file "example.com.zone";
    update-policy {
        grant r3v3rs3 name _acme-challenge.example.com. TXT;
    };
};

Her challenge adı için bir grant kuralı ekleyin. *.example.com sertifikası da _acme-challenge.example.com adını kullanır.

Saklanan veriler

r3v3rs3, ACME kayıtlarını config dizinindeki acme.toml dosyasında saklar. Dosya, her ACME hesabının private key'ini ve DNS provider credential'larını düz metin olarak içerir. Unix'te r3v3rs3 dosyayı 0600 izniyle oluşturur ve yazar. Böylece dosyayı yalnız process'in sahibi okuyabilir. Yönetim API'si ve WebUI credential'ları hiçbir zaman döndürmez. ACME listesi yalnız provider adını gösterir, örneğin Let's Encrypt (DNS-01, Cloudflare).

ACME kayıtlarını WebUI'dan oluşturun. r3v3rs3, ACME hesabını kayıt eklendiğinde oluşturur. acme.toml içindeki bir kayıt şöyle görünür:

version = "1.0.1"

[acme1]
provider = "Let's Encrypt"
renewal_days = 60
identifiers = ["example.com", "*.example.com"]
challenge_type = "dns-01"

[acme1.dns_provider]
provider = "cloudflare"
api_token = "<Cloudflare API token>"

[acme1.account]
id = "https://acme-v02.api.letsencrypt.org/acme/acct/123456789"
key_pkcs8 = "<hesabın private key'i>"
directory = "https://acme-v02.api.letsencrypt.org/directory"

dns_provider altındaki provider değeri cloudflare, route53, digitalocean, hetzner, linode, vultr, gandi, desec, porkbun, ovh, azure, google_cloud, webhook, exec veya rfc2136 olabilir. Route 53, api_token yerine access_key_id ve secret_access_key kullanır. Porkbun, api_key ve secret_api_key kullanır. OVHcloud, endpoint, application_key, application_secret ve consumer_key kullanır. Azure DNS, tenant_id, client_id, client_secret ve subscription_id kullanır. Google Cloud DNS, service_account_key ve isteğe bağlı project_id kullanır. Webhook, url ve isteğe bağlı token kullanır. Exec, program kullanır. RFC 2136; server, isteğe bağlı zone, key_name, key_algorithm ve key_secret kullanır. Vultr API key'i api_token alanına yazılır.

Ayarlar

WebUI'daki "Ayarlar" bölümünden, config.toml dosyasında saklanan ve bütün sunucuyu etkileyen seçenekleri değiştirebilirsiniz. Değişiklikler hemen uygulanır ve dosyaya yazılır.

AyarVarsayılanAçıklama
Session Süresi1hYönetim paneli session'ının geçerlilik süresi. En az 5 dakika olabilir.
Maksimum Giriş Denemesi10Her client IP adresi ve kullanıcı adı için izin verilen başarısız giriş sayısı.
Giriş Denemesi Sıfırlama Süresi15mLimite ulaşıldıktan sonraki bekleme süresi.
Arka Plan Görevi Aralığı1hSertifika yenileme ve log temizleme görevlerinin çalışma aralığı.
HTTP Challenge Adresi0.0.0.0:80ACME HTTP challenge'larının dinlendiği adres.
TLS-ALPN Challenge Adresi0.0.0.0:443Hiçbir port bu portu kullanmıyorsa ACME TLS-ALPN-01 challenge'larının dinlendiği adres.
DNS Challenge Resolverboşr3v3rs3'ün DNS-01 challenge'ının TXT kayıtları görünene kadar sorguladığı DNS sunucusu, örneğin 1.1.1.1:53. Boş bırakılırsa sistem resolver'ı kullanılır.
Upstream DNS Resolverboşhttp+srv ve https+srv sunucu URL'lerinin SRV sorgularını yanıtlayan DNS sunucusu, örneğin Consul için 127.0.0.1:8600. Boş bırakılırsa sistem resolver'ı kullanılır. Ayrıntılar için DNS SRV sunucuları bölümüne bakın.
Veritabanı Log Saklama Süresi3monthsLog'ların log veritabanında ne kadar tutulacağı.
Audit Log Saklama Süresi1yearAudit log'daki bir kaydın ne kadar tutulacağı. Ayrıntılar için Audit log bölümüne bakın.
Sertifika Süre Uyarısı14daysSertifika listesi bu süre içinde sona erecek sertifikayı işaretler. Webhook bu sertifika için bildirim alır. Ayrıntılar için Bildirimler bölümüne bakın.
Webhook URLboşBildirim webhook'u. Boşsa bildirim gönderilmez.
Webhook TokenboşWebhook isteklerinin bearer token'ı. Admin API bu değeri döndürmez.
Webhook Timeout10sTek bir webhook isteğinin en uzun süresi.

Süreleri 30s, 15m, 1h veya 7days gibi okunabilir bir biçimde yazın.

Config dosyaları

r3v3rs3 config'ini $XDG_CONFIG_HOME/r3v3rs3 veya $HOME/.config/r3v3rs3 dizinindeki TOML dosyalarında saklar.

Varsayılan konumu R3V3RS3_CONFIG_DIR environment variable'ı veya --config-dir komut satırı seçeneğiyle değiştirebilirsiniz.

Bu dosyaları elle de düzenleyebilirsiniz. Ancak r3v3rs3 config dosyalarındaki değişiklikleri kendiliğinden algılamaz. Değişikliklerin geçerli olması için dosyayı düzenledikten sonra sunucuyu yeniden başlatın.

Cluster'daki bir node yalnız config.toml dosyasını okur. State'in geri kalanı etcd veya Consul'dadır. Ayrıntılar için Cluster sayfasına bakın.

WebUI

r3v3rs3 bir WebUI ile birlikte gelir. WebUI varsayılan olarak localhost:46492 adresinde çalışır. Portu R3V3RS3_WEBUI environment variable'ı veya --webui komut satırı seçeneğiyle değiştirebilirsiniz. WebUI'ı kapatmak için R3V3RS3_NO_WEBUI=1 environment variable'ını ayarlayın veya --no-webui komut satırı seçeneğini kullanın.

WebUI dilini navbar'daki bayrak menüsünden seçebilirsiniz: İngilizce veya Türkçe. Tema menüsünde Sistem, Açık ve Koyu seçenekleri bulunur. WebUI bu seçimleri r3v3rs3_lang ve r3v3rs3_theme cookie'lerinde saklar. Bu cookie'ler yoksa WebUI İngilizce ve sistem temasıyla açılır.

r3v3rs3'ün hata sayfaları ve Panel Session giriş sayfası da bu cookie'lere bakar. Ancak tarayıcı bu cookie'leri yalnız WebUI'ın host'una gönderir. Bu yüzden başka bir host'taki proxy'nin sayfaları İngilizce ve sistem temasıyla açılır.

Yönetim API'si

WebUI, /api altındaki yönetim API'sini kullanır. r3v3rs3 bu API'nin OpenAPI dokümanını sunucu kodundan üretir. Bu yüzden doküman, çalışan sürümün route'larını listeler.

İki adres de session ister. Önce WebUI'a giriş yapın, sonra adresleri aynı tarayıcıda açın. WebUI footer'ındaki API linki de Swagger UI'ı açar.

Bir script, POST /api/login ile giriş yapar ve cevaptaki token cookie'sini sonraki request'lerle gönderir:

$ curl -c cookies.txt -H 'Content-Type: application/json' \
    -d '{"username":"admin","method":"password","password":"passw0rd","insecure":true}' \
    http://localhost:46492/api/login
$ curl -b cookies.txt http://localhost:46492/api/ports

"insecure": true değeri cookie'den Secure özelliğini kaldırır. Yönetim paneli düz HTTP kullanıyorsa bu değeri gönderin.

Audit log

r3v3rs3, bir hesabın WebUI veya yönetim API'si ile yaptığı değişiklikleri kaydeder: portlar, proxy'ler, erişim listeleri, sertifikalar, ACME kayıtları, ayarlar, CDN IP aralığı yenilemeleri ve hesaplar. Yönetim paneline her giriş, her başarısız giriş denemesi ve her çıkış da kaydedilir. r3v3rs3'ün kendi yaptığı değişiklikler kaydedilmez. Sertifika yenileme ve keşfedilen proxy'ler buna örnektir.

Her kayıtta zaman, hesap, client IP adresi, işlem, değişen kaynağın id'si ve kısa bir özet bulunur. Özet isimleri, adresleri ve rolleri içerir. Parola, token veya key içermez.

Tek sunucu audit log'u log dizinindeki log.db dosyasının audit_log tablosunda tutar. Cluster audit log'u cluster store'da şifreli tutar. Böylece her node bütün node'ların kayıtlarını okur. Cluster'daki bir kayıt, onu yazan node'un adını da içerir.

Bir kaydın ne kadar tutulacağını "Audit Log Saklama Süresi" ayarı belirler. Varsayılan değer 1year olur. Cluster bir günün kayıtlarını birlikte siler. Silme, o gün saklama süresini geçtikten sonra yapılır.

Audit log'a yazma başarısız olursa değişiklik geri alınmaz. r3v3rs3 hatayı log'a yazar.

WebUI'daki Audit Log sayfası kayıtları en yeni kayıttan başlayarak listeler. Bu sayfayı yalnız admin hesabı açar. Sayfa kayıtları hesaba, kaynağa ve döneme göre filtreler. Sayfada en fazla 500 kayıt görünür.

GET /api/audit aynı kayıtları döner. Bu endpoint'i yalnız admin hesabı çağırabilir. Query parametrelerinin hepsi isteğe bağlıdır:

ParametreAçıklama
sinceUnix milisaniye cinsinden en erken zaman. Varsayılan değer, until değerinden 31 gün öncesidir.
untilUnix milisaniye cinsinden en geç zaman. Varsayılan değer şu andır.
usernameKayıtların ait olduğu hesap.
resource_idDeğişen kaynağın id'si veya değişen kullanıcı adı.
limitYanıttaki en fazla kayıt sayısı. Varsayılan değer 100, en yüksek değer 500 olur.

Cluster, until değerinden en fazla 31 gün geriye okur. Bu yüzden daha uzun bir dönem daha eski kayıtları döndürmez.

Log

r3v3rs3 varsayılan olarak log'ları standart çıktıya yazar. Bunu R3V3RS3_LOG, R3V3RS3_ACCESS_LOG environment variable'larıyla veya --log, --access-log komut satırı seçenekleriyle değiştirebilirsiniz.

$ r3v3rs3 start --log /var/log/r3v3rs3.log --access-log /var/log/r3v3rs3-access.log

Log seviyesini değiştirmek için R3V3RS3_LOG_LEVEL, R3V3RS3_ACCESS_LOG_LEVEL environment variable'larını veya --log-level, --access-log-level komut satırı seçeneklerini kullanın.