Created
May 11, 2024 20:40
-
-
Save casebeer/5c4ead8e23613a091c7b6fe8dfe90c05 to your computer and use it in GitHub Desktop.
Nginx reverse proxy config for Ruckus Unleashed controller w/ backend failover support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Reverse proxy config for Ruckus Unleashed controllers | |
# | |
# Requirements: | |
# | |
# - DNS entries for all unleashed<IPv4 last octet of controllers>.example.com | |
# - DNS entry for unleashed.example.com | |
# - (DNS entries to point to Nginx reverse proxy) | |
# - Wildcard TLS cert on reverse proxy (or SAN cert covering all above mentioned names) | |
# | |
# Problem: | |
# | |
# Unleashed controllers elect one controller to be the primary. All other controllers | |
# will 302 redirect to that primary. However, Nginx open source edition cannot detect | |
# this 302 as a "backend down" signal, so we instead map those redirects to backend-specific | |
# frontend hostnames, then use those hostnames on the reverse proxy to determine the | |
# correct Unleashed controller to hit. | |
# | |
# We could probably also set a cookie with the correct backend to hit and avoid needing | |
# DNS and certificates for multiple hostnames, but this is fairly simple assuming internal | |
# DNS and wildcard ACME certs already configured on the Nginx reverse proxy. | |
# | |
# hostname-only (via search domain) to FQDN redirect | |
server { | |
server_name "~^unleashed\d{0,3}$" ; | |
listen 80; | |
listen [::]:80; # ipv6only=on; | |
return 302 https://unleashed.example.com$request_uri; | |
} | |
# Map frontend (i.e. reverse proxy) hostname to specific backend IP address | |
# Required because Unleashed controllers elect a primary amongst themselves, | |
# then any non-primaries simply 302 redirect to the primary. Ideally, we'd | |
# have the reverse proxy do a health check and fail any backends issuing these | |
# "I'm not primary" 302s, but that's an Nginx Plus subscription-only feature. | |
map $host $backend_ip { | |
hostnames; | |
"~*^unleashed(?<octet>\d{1,3})\.?.*$" 192.168.0.$octet; | |
default 192.168.0.123; # default Unleashed primary controller | |
} | |
server { | |
server_name "~^unleashed\d{0,3}.example.com$"; | |
if ($https = "") { | |
return 302 https://$server_name$request_uri; | |
} | |
# docker DNS resolver | |
resolver 127.0.0.11 valid=30s; | |
# need separate v4 and v6 listens to avoid `bind() to [::]:80 failed (98: Address already in use)` | |
listen 80; | |
listen [::]:80; # ipv6only=on; | |
listen 443 ssl; | |
listen [::]:443 ssl; # ipv6only=on; # if your nginx version is >= 1.9.5 you can also add the "http2" flag here | |
access_log /dev/stdout combined_host; #client_certs; | |
## TLS config | |
#add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; | |
ssl_certificate /certs/*.example.com_ecc/fullchain.cer; | |
ssl_certificate_key /certs/*.example.com_ecc/*.example.com.key; | |
ssl_protocols TLSv1.3 TLSv1.2; | |
ssl_ecdh_curve X25519:prime256v1:secp384r1; | |
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384::ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; | |
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 X-Forwarded-Proto $scheme; | |
proxy_set_header X-Forwarded-Protocol $scheme; | |
proxy_set_header X-Forwarded-Host $http_host; | |
location / { | |
# backend IP is determined by frontend hostname via map section above | |
proxy_pass https://$backend_ip; | |
# override the Host header going to backend | |
# Unleashed will respond to any Host we provide, and by spoofing Host to the proxy (not | |
# backend) FQDN, we'll get Redirect locations etc. set properly by the backend | |
proxy_set_header Host $host; | |
proxy_ssl_server_name off; | |
# Intercept "I'm not the Unleashed Primary" redirects | |
# These are always to the bare host of the primary, with no path. Handle by | |
# changing frontend domain to backend-specific hostname. | |
proxy_redirect "~^https://192.168.0.(?<octet>\d{0,3})" https://unleashed$octet.example.com; | |
# normal backend redirect handle as normal | |
# Any redirects with a path, even just `/` are "normal" redirects. | |
proxy_redirect "~^https://192.168.0.\d{0,3}/" https://$host; | |
proxy_ssl_trusted_certificate /certs/unleashed-backend.example.com_SELFSIGNED_cert.pem; | |
proxy_ssl_verify off; # verify off since still WIP to get trustable self-signed certs on Unleashed controllers | |
proxy_ssl_verify_depth 3; | |
proxy_ssl_session_reuse on; | |
proxy_ssl_protocols TLSv1.1 TLSv1.2; | |
proxy_ssl_ciphers HIGH:!aNULL:!MD5; | |
proxy_buffering off; | |
proxy_http_version 1.1; | |
proxy_set_header Upgrade $http_upgrade; | |
proxy_set_header Connection "upgrade"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment