Open nonifo opened 3 weeks ago
I support the idea
Here’s an example configuration demonstrating the functionality I'm looking for. This setup uses Nginx’s stream module to forward SPICE traffic based on SNI (Server Name Indication), allowing Nginx to direct requests for specific domains to a designated backend server. Additionally, it includes an HTTP proxy configuration for handling other HTTP-based requests.
# Forward SPICE traffic based on SNI
map $ssl_preread_server_name $upstream {
example.domain.com 192.168.1.100:61000; # Destination for SPICE traffic
default 127.0.0.1:444; # Fallback server if no match
}
server {
listen 61000 ssl; # Listen on port 61000 with SSL for SPICE
proxy_pass $upstream;
ssl_preread on; # Enable SNI to identify the correct backend
# Use the same SSL certificate and key as the main server
ssl_certificate /etc/letsencrypt/live/npm-1/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/npm-1/privkey.pem;
}
# HTTP/S proxy for other HTTP-based requests
server {
listen 3128;
proxy_pass 192.168.1.100:3128; # HTTP proxy for port 3128
}
In this example:
The map block forwards requests based on the domain specified in the SNI header. If the domain matches example.domain.com, the request is forwarded to 192.168.1.100 on port 61000. A fallback server at 127.0.0.1:444 handles any unmatched requests. The second server block forwards HTTP-based requests received on port 3128 to 192.168.1.100:3128.
Here’s another example configuration for SNI-based SSH forwarding using Nginx’s stream module. In this setup, Nginx listens on the default SSH port 22 and forwards incoming SSH traffic to different internal SSH servers based on the requested domain name (SNI).
# SSH Forwarding configuration based on SNI
map $ssl_preread_server_name $upstream_ssh {
ssh1.example.com 192.168.1.101:22; # Forward SSH traffic for ssh1.example.com
ssh2.example.com 192.168.1.102:22; # Forward SSH traffic for ssh2.example.com
default 192.168.1.100:22; # Default SSH server if no SNI match
}
server {
listen 22 ssl; # Listen on port 22 with SSL for SNI-based routing
proxy_pass $upstream_ssh; # Forward to SSH server based on SNI map
ssl_preread on; # Enable SNI inspection
# SSL certificate and key (generic for SNI inspection)
ssl_certificate /etc/letsencrypt/live/placeholder/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/placeholder/privkey.pem;
}
General Nginx stream Configuration Template This template includes SSL-based SNI routing for traffic that requires domain-based routing (e.g., HTTPS, SPICE), as well as simple port-based forwarding for other protocols (e.g., SSH without SSL).
# General-purpose Nginx stream configuration for multi-protocol traffic
# Define upstream servers based on SNI for SSL-based services
map $ssl_preread_server_name $upstream {
example1.com 192.168.1.101:443; # HTTPS or other SSL traffic for example1.com
example2.com 192.168.1.102:61000; # SPICE or custom SSL service for example2.com
default 192.168.1.100:444; # Default server if no SNI match
}
# SSL-based traffic (e.g., HTTPS, SPICE) with SNI-based routing
server {
listen 443 ssl; # Standard HTTPS port
listen 61000 ssl; # Custom SSL port for specific services
proxy_pass $upstream; # Route based on SNI
ssl_preread on; # Enable SNI inspection
# Generic SSL certificate (only used for SNI inspection)
ssl_certificate /etc/letsencrypt/live/placeholder/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/placeholder/privkey.pem;
}
# Port-based routing for non-SSL protocols (SSH, non-SNI HTTP, etc.)
# SSH Server 1
server {
listen 2222; # External port for SSH server 1
proxy_pass 192.168.1.101:22; # Internal SSH server 1
}
# SSH Server 2
server {
listen 2223; # External port for SSH server 2
proxy_pass 192.168.1.102:22; # Internal SSH server 2
}
# HTTP server (non-SSL)
server {
listen 8080; # External port for HTTP traffic
proxy_pass 192.168.1.103:80; # Internal HTTP server
}
# Custom TCP service
server {
listen 3000; # External port for custom service
proxy_pass 192.168.1.104:3000; # Internal custom service
}
as a workaround, you can put anything you want included inside stream {}
block into /data/nginx/custom/stream.conf
Description: Currently, Nginx Proxy Manager allows for simple TCP/UDP stream forwarding but lacks advanced routing capabilities based on the requested domain name (SNI). Enabling SNI-based routing for streams would allow users to direct traffic to specific backend servers based on the hostname provided by the client during the TLS handshake. This feature would mirror the SNI-based routing commonly used in HTTP proxies, but extend its benefits to TCP and UDP streams, such as SSH and other non-HTTP protocols that require secure, domain-specific routing.
Use Cases:
Multi-Server SSH Access: Organizations with multiple servers that need to be accessible over SSH (e.g., server1.example.com, server2.example.com) can route SSH connections to the correct backend server using only the hostname in the request, without needing separate ports for each server. This would simplify access and allow DNS-based routing to specific servers.
Load Balancing Across TCP/UDP Applications: Services using custom TCP/UDP protocols could benefit from SNI-based routing, providing flexibility and load distribution across multiple servers for protocols that aren’t HTTP-based.
Simplified Network Configuration: By using SNI-based routing, administrators can reduce the need for complex port mapping schemes and assign services based on domains rather than ports, making configurations more readable and scalable.
Advantages:
Suggested Implementation: Implement SNI-based routing within the "Streams" section of Nginx Proxy Manager to allow administrators to set up stream proxies that route based on the SNI hostname. This would likely require expanding the current stream configuration options and allowing users to specify hostnames directly for each stream backend.