Ein Upstream-Proxy ist ein Proxy-Server, an den ein anderer Proxy-Server Client-Anfragen weiterleitet, wodurch eine Kette entsteht, in der der erste Proxy als Client für den Upstream-Proxy fungiert.
Was ist ein Upstream-Proxy?
Wenn ein Client eine Anfrage an einen Proxy-Server sendet, ruft dieser Proxy-Server die angeforderte Ressource typischerweise direkt vom Ursprungsserver im Internet ab. In vielen Architekturen kontaktiert der erste Proxy-Server den Ursprung jedoch nicht direkt. Stattdessen leitet er die Anfrage an einen anderen Proxy-Server weiter, der als Upstream-Proxy bekannt ist. Dieser zweite Proxy bearbeitet die Anfrage dann, indem er sie aus seinem Cache erfüllt, an einen weiteren Upstream-Proxy weiterleitet oder vom Ursprungsserver abruft.
Die Hauptzwecke der Nutzung eines Upstream-Proxys sind:
- Mehrschichtige Sicherheit: Hinzufügen einer zusätzlichen Ebene für Sicherheit und Zugriffskontrolle.
- Spezialisierte Funktionen: Delegieren spezifischer Aufgaben wie Inhaltsfilterung, Antiviren-Scans oder erweitertes Caching an einen dedizierten Proxy.
- Netzwerksegmentierung: Überbrückung verschiedener Netzwerksegmente oder Bereitstellung eines kontrollierten Zugriffs auf externe Netzwerke.
- Anonymität und Datenschutz: Verschleierung der IP-Adresse des ursprünglichen Clients durch mehrere Hops.
- Umgehung von Beschränkungen: Weiterleitung des Datenverkehrs über verschiedene geografische Standorte oder Netzwerke, um Geoblocks oder Netzwerkbeschränkungen zu umgehen.
- Lastverteilung: Verteilung von Anfragen auf mehrere Upstream-Proxys oder Ursprungsserver.
Der Fluss einer Anfrage mit einem Upstream-Proxy ist: Client -> Proxy A -> Upstream-Proxy B -> Ursprungsserver. In diesem Szenario ist Proxy A so konfiguriert, dass er Proxy B als seinen Upstream verwendet.
Kaskadierende Proxys erklärt
Kaskadierende Proxys, auch bekannt als Proxy-Ketten, beziehen sich auf eine Architektur, bei der mehrere Proxy-Server in einer Sequenz angeordnet sind, wobei jeder Proxy Anfragen an den nächsten in der Kette weiterleitet, bis der letzte Proxy den Ursprungsserver kontaktiert. Dies schafft einen Multi-Hop-Pfad für Client-Anfragen.
Vorteile kaskadierender Proxys
- Verbesserte Sicherheit: Jeder Proxy kann seine eigenen Sicherheitsrichtlinien, Authentifizierungen und Zugriffskontrollen durchsetzen.
- Modulare Architektur: Verschiedene Proxys können sich auf unterschiedliche Funktionen spezialisieren (z. B. einer für Caching, ein anderer für WAF, ein weiterer für die Ausgangskontrolle).
- Komplexe Weiterleitung: Ermöglicht komplexe Weiterleitungslogik, die bestimmte Arten von Datenverkehr durch verschiedene Ketten oder geografische Standorte leitet.
- Erhöhte Anonymität: Mehr Hops erschweren die Rückverfolgung des ursprünglichen Clients.
- Redundanz-Umgehung: Bietet alternative Pfade, falls ein Proxy in der Kette ausfällt oder blockiert wird.
Nachteile kaskadierender Proxys
- Erhöhte Latenz: Jeder zusätzliche Proxy-Hop führt zu Verarbeitungsverzögerungen und Netzwerklatenz.
- Komplexität: Konfiguration und Verwaltung werden komplizierter, insbesondere bei der Fehlersuche und -behebung.
- Einzelne Fehlerpunkte: Wenn keine Redundanz vorgesehen ist, kann der Ausfall eines Proxys in der Kette den Dienst unterbrechen.
- Herausforderungen bei der Fehlersuche: Das Verfolgen des Pfades einer Anfrage und das Identifizieren von Problemen kann über mehrere Server hinweg schwierig sein.
- Header-Verwaltung: Die korrekte Handhabung von Headern wie
X-Forwarded-ForundViaist entscheidend für die Protokollierung und die Kenntnis des Ursprungsservers.
Konfiguration eines Upstream-Proxys
Konfigurationsbeispiele für gängige Proxy-Server, die zeigen, wie ein Proxy eingerichtet wird, um Anfragen an einen Upstream weiterzuleiten.
Nginx (als Reverse-Proxy für einen Upstream)
Nginx fungiert typischerweise als Reverse-Proxy. Um eine Nginx-Instanz so zu konfigurieren, dass sie Anfragen an einen Upstream-Proxy weiterleitet, definieren Sie die Adresse des Upstream-Proxys in der proxy_pass-Direktive innerhalb eines location-Blocks.
# Nginx Configuration (e.g., proxy.example.com)
# This Nginx instance acts as Proxy A, forwarding to Upstream Proxy B.
http {
upstream upstream_proxy_b {
# Address of your upstream proxy (Proxy B)
server 192.168.1.100:3128; # Example: IP and port of Proxy B
# Optional: Add multiple servers for load balancing/failover if Proxy B has multiple instances
# server 192.168.1.101:3128;
}
server {
listen 80;
server_name proxy.example.com;
location / {
# Pass requests to the defined upstream_proxy_b
proxy_pass http://upstream_proxy_b;
# Recommended headers for proxy chains
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "1.1 $hostname"; # Add current proxy to Via header
}
}
}
Squid (als Forward-Proxy für einen Upstream)
Squid wird häufig als Forward-Proxy verwendet. Um Squid für die Verwendung eines Upstream-Proxys zu konfigurieren, verwenden Sie die cache_peer-Direktive.
# Squid Configuration (e.g., proxy-a.conf)
# This Squid instance acts as Proxy A, forwarding to Upstream Proxy B.
# Define the upstream proxy (Proxy B)
# Syntax: cache_peer hostname type http_port icp_port [options]
# type: parent or sibling (parent is more common for upstream)
# http_port: HTTP port of the upstream proxy
# icp_port: ICP port (usually 0 if not used or unknown)
cache_peer 192.168.1.100 parent 3128 0 no-query default_parent
# Example for multiple upstream proxies (Proxy B and Proxy C)
# cache_peer 192.168.1.101 parent 3128 0 no-query round-robin
# cache_peer 192.168.1.102 parent 3128 0 no-query
# Access control to allow clients to use this proxy
acl localnet src 192.168.0.0/24 # Example: your client network
http_access allow localnet
http_access deny all
# Specify the port Squid listens on for client requests
http_port 3129 # Proxy A listens on 3129
# Optional: Add Via header
via off # Squid adds Via headers by default; 'off' means Squid won't add its own 'Via' header,
# but it will forward existing ones. To ensure it *adds* its own, remove this line or set it to 'on'.
# For cascading, usually 'via on' or default behavior is preferred.
In dieser Squid-Konfiguration lauscht proxy-a auf Port 3129 und leitet alle Anfragen an 192.168.1.100:3128 (Proxy B) weiter, aufgrund der Option default_parent.
Konfiguration kaskadierender Proxys
Um kaskadierende Proxys einzurichten, konfigurieren Sie jeden Proxy in der Kette so, dass er auf den nächsten zeigt.
Szenario: Client -> Proxy A -> Proxy B -> Internet
Dieses Szenario umfasst zwei Proxys in einer Kette.
Proxy A Konfiguration (Front-End-Proxy)
Proxy A ist der erste Kontaktpunkt für Clients und leitet Anfragen an Proxy B weiter.
Nginx als Proxy A:
(Siehe das Nginx-Beispiel unter "Konfiguration eines Upstream-Proxys" oben. Der upstream_proxy_b-Block und die proxy_pass http://upstream_proxy_b;-Direktive konfigurieren Nginx, um Anfragen an Proxy B zu senden.)
Squid als Proxy A:
(Siehe das Squid-Beispiel unter "Konfiguration eines Upstream-Proxys" oben. Die cache_peer 192.168.1.100 parent 3128 0 no-query default_parent-Direktive konfiguriert Squid, um Anfragen an Proxy B zu senden.)
Proxy B Konfiguration (Intermediate/Upstream-Proxy)
Proxy B empfängt Anfragen von Proxy A und leitet sie dann an das Internet weiter (oder an einen weiteren Upstream-Proxy, wenn die Kette länger ist).
Nginx als Proxy B:
Wenn Proxy B ebenfalls eine Nginx-Instanz ist, würde er typischerweise als Standard-Reverse-Proxy konfiguriert, der an den Ursprungsserver weiterleitet. Wenn er ausschließlich als Ausgangspunkt oder weiterer Proxy fungiert, wäre seine Konfiguration ähnlich der von Proxy A, aber sein proxy_pass-Ziel wäre der nächste Proxy oder der tatsächliche Ursprung.
# Nginx Configuration for Proxy B (192.168.1.100)
# This Nginx instance receives requests from Proxy A and forwards to the internet.
http {
server {
listen 3128; # Proxy B listens on 3128 for requests from Proxy A
server_name proxy-b.example.com; # Or simply listen on IP
location / {
# Here, Proxy B could forward directly to the origin based on the client's original request
# Or, it could forward to *another* upstream if the chain continues.
# For simplicity, assuming it forwards to the internet based on the original request.
# Nginx as a forward proxy is more complex and usually involves dynamic resolution.
# A more common scenario is Nginx acting as a reverse proxy for a known set of origins,
# or for a single "next hop" proxy.
# Example: If Proxy B forwards to a specific known origin
# proxy_pass http://www.example.com;
# If Proxy B is to act as a general forward proxy for arbitrary domains (less common for Nginx)
# This requires dynamic resolution and is often handled by specialized forward proxies like Squid.
# For Nginx to function as a general forward proxy, it often involves custom Lua scripting or modules.
# A simpler Nginx Proxy B might just pass to *another* fixed upstream.
# For a true "internet" forward, Squid is usually preferred.
# If Proxy B is just the egress point and doesn't know the final origin (like Squid)
# This is where Nginx's capabilities as a *general purpose* forward proxy are limited.
# If Proxy B is an Nginx, it's more likely to be a reverse proxy for specific services
# or a next hop in a defined chain where the next hop is also fixed.
# For the purpose of cascading, if Nginx is Proxy B, it would typically be configured
# to pass to a *known* next hop or a known origin.
# For a "general internet" egress, Squid is more appropriate.
# Let's assume Proxy B is forwarding to a known *final* upstream, e.g., an anonymizing proxy
# or a specific egress gateway.
proxy_pass http://final_egress_proxy:8080; # Example: forwarding to a final egress proxy
# Or, if it's the last hop before origin and Nginx is configured for dynamic upstream resolution:
# proxy_pass $scheme://$host$request_uri; # Requires custom setup for dynamic forward proxy
# For simplicity, let's assume Proxy B is a Squid proxy for general internet access.
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "1.1 $hostname";
}
}
}
Squid als Proxy B:
Proxy B empfängt Anfragen von Proxy A und ist so konfiguriert, dass er entweder direkt aus dem Internet abruft oder an einen weiteren Upstream weiterleitet. Wenn er der letzte Proxy vor dem Internet ist, benötigt er keine cache_peer-Direktive, die auf einen anderen Proxy zeigt (es sei denn, es handelt sich um spezifische Domänen oder Failover).
# Squid Configuration for Proxy B (192.168.1.100)
# This Squid instance receives requests from Proxy A and fetches from the internet.
# Proxy B listens on 3128 for requests from Proxy A
http_port 3128
# Optional: If Proxy B also has its own upstream (e.g., an ISP proxy or another specific proxy)
# cache_peer upstream.isp.com parent 8080 0 no-query default_parent
# Access control to allow Proxy A (and other authorized clients) to connect
acl proxy_a_network src 192.168.1.0/24 # Example: network where Proxy A resides
http_access allow proxy_a_network
http_access deny all
# Configure caching, logging, etc. as needed for Proxy B
Erweiterte Kaskadierung: Bedingte Upstreams
Für komplexere Weiterleitungen möchten Sie möglicherweise Anfragen für bestimmte Domänen oder Pfade an verschiedene Upstream-Proxys senden.
Nginx Bedingte Upstreams:
http {
# Upstream group for general traffic
upstream general_upstream {
server 192.168.1.100:3128; # Proxy B
}
# Upstream group for specific sensitive traffic
upstream secure_upstream {
server 192.168.2.200:4444; # Secure Proxy C
}
server {
listen 80;
server_name proxy.example.com;
location /secure/ {
# Requests to /secure/ go to Secure Proxy C
proxy_pass http://secure_upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
# All other requests go to Proxy B
proxy_pass http://general_upstream;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Squid Bedingte Upstreams:
# Define multiple cache_peers
cache_peer 192.168.1.100 parent 3128 0 no-query name=general_proxy
cache_peer 192.168.2.200 parent 4444 0 no-query name=secure_proxy
# ACLs to identify specific traffic
acl secure_domains dstdomain .secure.example.com
acl secure_urls url_regex ^https://secure\.
# Direct requests based on ACLs
cache_peer_access secure_proxy allow secure_domains
cache_peer_access secure_proxy allow secure_urls
cache_peer_access general_proxy allow all
# Ensure traffic not matching an explicit peer access rule goes direct or to default_parent
# if no default_parent is set, requests may fail or go direct based on 'never_direct'/'always_direct'
# It's usually better to have a default_parent or a final 'cache_peer_access' to catch all.
Wichtige Überlegungen für kaskadierende Proxys
Latenz und Leistung
Jeder Proxy in der Kette fügt Verarbeitungszeit und Netzwerklatenz hinzu. Die Minimierung der Anzahl der Hops und die Gewährleistung leistungsstarker Proxys und Netzwerkverbindungen sind entscheidend. Überwachen Sie die End-to-End-Latenz, um Engpässe zu identifizieren.
Sicherheit und Authentifizierung
- Inter-Proxy-Authentifizierung: Implementieren Sie Authentifizierung (z. B. IP-Whitelisting, Shared Secrets, Client-Zertifikate) zwischen Proxys, um unbefugten Zugriff auf Zwischen-Proxys zu verhindern.
- SSL/TLS-Terminierung: Entscheiden Sie, wo die SSL/TLS-Terminierung stattfindet. Wenn Proxys den Datenverkehr entschlüsseln, stellen Sie eine ordnungsgemäße Zertifikatsverwaltung und Neuverschlüsselung für nachfolgende Hops sicher.
- Zugriffskontrolle: Konfigurieren Sie strenge Zugriffskontrolllisten (ACLs) auf jedem Proxy, um den Datenverkehr nur von autorisierten Upstream-/Downstream-Proxys oder Clients zuzulassen.
Fehlersuche und -behebung
Das Verfolgen von Anfragen durch mehrere Proxys kann komplex sein.
* X-Forwarded-For-Header: Dieser Header verfolgt die ursprüngliche Client-IP-Adresse und nachfolgende Proxy-IPs in der Kette. Stellen Sie sicher, dass er bei jedem Hop korrekt angehängt wird ($proxy_add_x_forwarded_for in Nginx).
* Via-Header: Der Via-Header gibt die Zwischen-Proxys an, über die die Anfrage geleitet wurde. Jeder Proxy sollte seinen Bezeichner zu diesem Header hinzufügen.
* Protokollierung: Zentralisierte Protokollierung und Korrelations-IDs sind unerlässlich, um Anfragen über die gesamte Proxy-Kette hinweg zu verfolgen.
Lastverteilung und Failover
Um Hochverfügbarkeit zu gewährleisten und den Datenverkehr zu verteilen, konfigurieren Sie die Lastverteilung für Upstream-Proxys.
* Nginx: Verwenden Sie den upstream-Block mit mehreren server-Direktiven und Optionen wie least_conn, round_robin, backup, down.
nginx
upstream proxy_b_cluster {
server 192.168.1.100:3128 weight=5; # Primary Proxy B
server 192.168.1.101:3128 backup; # Backup Proxy B
server 192.168.1.102:3128; # Another Primary Proxy B
least_conn; # Use least connections method
}
# Then proxy_pass http://proxy_b_cluster;
* Squid: Verwenden Sie mehrere cache_peer-Direktiven mit Optionen wie round-robin, weighted-round-robin, failover und no-query.
squid
cache_peer 192.168.1.100 parent 3128 0 no-query weight=10
cache_peer 192.168.1.101 parent 3128 0 no-query weight=5
cache_peer 192.168.1.102 parent 3128 0 no-query round-robin
Header-Verwaltung
Eine sorgfältige Verwaltung der HTTP-Header ist entscheidend. Neben X-Forwarded-For und Via sollten Sie Proxy-Authorization für die Authentifizierung bei Upstream-Proxys in Betracht ziehen und sicherstellen, dass andere relevante Header gemäß der Richtlinie weitergeleitet oder entfernt werden.
Vergleich: Einzelner Upstream vs. Kaskadierende Upstreams
| Feature / Aspekt | Einzelner Upstream-Proxy | Kaskadierende Upstream-Proxys |
|---|---|---|
| Komplexität | Gering; einfachere Konfiguration und Verwaltung. | Hoch; komplizierte Konfiguration, Verwaltung und Fehlersuche über mehrere Server hinweg. |
| Latenz | Minimaler Overhead; ein zusätzlicher Netzwerkhop. | Erhöhter Overhead; mehrere Netzwerkhops und Verarbeitungsverzögerungen pro Proxy. |
| Flexibilität | Beschränkt auf die Fähigkeiten eines einzelnen Proxys. | Hoch; ermöglicht spezialisierte Funktionen in jeder Phase und komplexe Weiterleitung. |
| Sicherheitsebenen | Eine einzige Ebene für Sicherheit und Zugriffskontrolle. | Mehrschichtige Sicherheit; jeder Proxy kann unterschiedliche Richtlinien durchsetzen. |
| Anonymität | Bietet grundlegende Anonymität vom Ursprung. | Verbesserte Anonymität; schwieriger, den ursprünglichen Client über mehrere Hops zu verfolgen. |
| Fehlersuche | Relativ unkompliziert. | Herausfordernd; erfordert sorgfältige Header-Verwaltung (X-Forwarded-For, Via) und Protokollierung. |
| Ausfallauswirkungen | Ausfall des einzelnen Upstreams stoppt den gesamten Datenverkehr. | Ausfall eines Proxys in der Kette kann den Dienst unterbrechen, wenn kein Failover konfiguriert ist. |
| Anwendungsfälle | Grundlegende Inhaltsfilterung, Caching, einfache Zugriffskontrolle. | Erweiterte Sicherheit, Compliance, Geo-Routing, spezialisierte Dienste, Anforderungen an hohe Anonymität. |