Here's the setup:
fowarding_proxy -> server_1, server_2
server_1 -> app1.domain.com, app2.domain.com
server_2 -> app3.domain.com, app4.domain.com
Where each server is running a docker daemon with an nginx reverse-proxy based on the jwilder/nginx-proxy + letsencrypt setup.
Both servers sit behind the same router and I need a way to route traffic correctly to each one based on the host name. I've been trying to use the nginx stream module since I don't want the forwarding proxy to handle any ssl termination, but the $ssl_preread_name directive doesn't (seem) to capture the host name on http traffic and I can't do a 301 on server directives in the stream module. What's the best way to approach this?
I've included an example of the config I'm currently working with and I've tried multiple iterations. Open to any suggestions.
(Also, as an aside, nothing logs to access.log)
Forward_proxy nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
stream {
# bare bones content, still nothing written to the log.
log_format main '[$time_local] $remote_addr'
access_log /var/log/nginx/access.log main;
map $ssl_preread_server_name $name {
app1.domain.com server1;
app2.domain.com server1;
app3.domain.com server2;
app4.domain.com server2;
}
upstream server1 {
server server1:80;
}
upstream server2 {
server server1:80;
}
upstream server1_ssl {
server server1:443;
}
upstream server2_ssl {
server server1:443;
}
server {
listen 80;
proxy_pass $name;
ssl_preread on;
}
server {
listen 443;
proxy_pass "${name}_ssl";
ssl_preread on;
}
}
Came up with a solution, happy to hear of better ones.
Instead of a single forwarding-proxy, I created two new nginx containers: One for HTTP traffic and the other for HTTPS traffic and put them both in a single docker-compose file for easier management.
HTTP-forwarding-proxy
http {
map $host $name {
default server1;
app3.strangedreamsinc.com server2;
app4.strangedreamsinc.com server2;
}
upstream server1 {
server server1_ip:8080;
}
upstream server2 {
server server2:8080;
}
server {
listen 80 default_server;
server_name _;
location / {
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_pass http://$name;
}
}
}
HTTPS-forwarding-proxy
stream {
map $ssl_preread_server_name $name {
default server1;
app1.strangedreamsinc.com server1;
app2.strangedreamsinc.com server1;
}
upstream server1 {
server server1_ip:8443;
}
upstream server2 {
server server2_ip:8443;
}
server {
listen 443;
proxy_pass $name;
ssl_preread on;
}
}
I'm not convinced there isn't a better way and there's probably something I'm overlooking, but this allows me to transparently route traffic to the correct reverse-proxy and still supports the letsencrypt protocols to apply SSL to my servers.
Related
I would like to handle 2 servernames, say "web1.example.com" and "web2.example.com" on the same port (443) in the same nginx config where the first should be a local http server, and the second needs to be forwarded to an external upstream without terminating the SSL connection.
How do I configure this?
Details:
I can use nginx to look at the first SSL message (CLientHello) and use it to proxy/forward the entire connection without terminating SSL. This can even look at the SNI and choose a different upstream based on the servername in it. This uses the ngx_stream_ssl_preread_module with proxy_pass and ssl_preread on. The config is something like this:
stream {
upstream web1 {
server 10.0.0.1:443;
}
upstream web2 {
server 10.0.0.2:443;
}
map $ssl_preread_server_name $upstream {
web1.example.com web1;
web1-alias.example.com web1;
web2.example.com web2;
}
server {
listen 443;
resolver 1.1.1.1;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass $upstream;
ssl_preread on;
}
}
This is configured in the stream config section of nginx.
But I can also configure a local http server in the http config section of nginx.
So what if I want web1 ("web1.example.com" in the example) to use such a "local nginx http server", and not an external "upstream server"? ("web2" should still be forwarded as before.) So I want to configure "web1.example.com" in the http config section of nginx, and "forward" to it in the stream config section of nginx.
To be clear, I want "web1.example.com" to be configured like this:
http {
server {
listen 443 ssl;
server_name web1.example.com web1-alias.example.com;
ssl_certificate ...
location ...
...
}
}
This all works find if I do either stream or http listening on the same port. But how do I do both on the same port?
How can I "call" the http config section from the streams config section? Can proxy_pass refer to a local nginx http server somehow?
I don't think you can use both on the same port, but maybe something like this would work?
stream {
upstream web1 {
server 127.0.0.1:8443;
}
upstream web2 {
server 10.0.0.2:443;
}
map $ssl_preread_server_name $upstream {
web1.example.com web1;
web1-alias.example.com web1;
web2.example.com web2;
}
server {
listen 443;
resolver 1.1.1.1;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass $upstream;
ssl_preread on;
}
}
http {
server {
listen 8443 ssl;
server_name web1.example.com web1-alias.example.com;
ssl_certificate ...
location ...
...
}
}
Is it possible?
I want know how would be work this config.
Is it Ok or not and why?
upstream one_proxy {
ip_hash;
server unix:/var/run/websocket-proxy.20000.sock max_fails=0;
server unix:/var/run/websocket-proxy.20001.sock max_fails=0;
}
upstream two_proxy {
ip_hash;
server 1.2.3.4:1234;
}
server {
server_name domain_name;
listen 0.0.0.0:80;
access_log off;
location / {
proxy_pass http://one_proxy;
}
}
server {
listen 127.0.0.1:20003;
access_log off;
location / {
proxy_pass http://two_proxy;
}
}
Definitely config not complete but I think it look like good.
I didn't find examples with two reverse proxy on one nginx and I doubt.
If you have experience share it please )
Don't you know nginx -t -c conf/your-custom-nginx.conf command could test the configuration
I have a nginx instance in AWS that has upstream Application layer.
There are two requirements for nginx
- keepalive
- use resolver to dynamically resolve the upstream
I am able to make either of them work.
Here is the config for making keepalive work:
upstream "backend" {
server "appserver.example.com:443";
keepalive 250;
}
server {
resolver 10.0.0.2 valid=60s;
server_name _;
location / {
proxy_http_version 1.1;
proxy_pass https://backend;
}
}
Here is the config for DNS resolver to work:
server {
resolver 10.0.0.2 valid=60s;
server_name _;
set $backend appserver.example.com:443;
location / {
proxy_http_version 1.1;
proxy_pass https://$backend;
}
}
How can I get both DNS resolver and keepalive to work without using a third-party plugin in open source NGinx
According to this Nginx wiki page
there seems to be the jdomain Plugin
http {
resolver 8.8.8.8;
resolver_timeout 10s;
upstream backend {
jdomain www.baidu.com;
# keepalive 10;
}
server {
listen 8080;
location / {
proxy_pass http://backend;
}
}
}
I have some problem about nginx with http and https bypass, In upstream block
upstream block:
upstream bypass{
server 192.168.99.1:80; #http
server 192.168.99.2:443 backup; #https
}
When http 80 have a problem (server down, etc), I want to redirect to https 443,
This block does not work for me.
location block:
location / {
proxy_pass https://bypass;
proxy_redirect off;
}
How can I resolve this?
This works well: Create server config section for each backend on different port and forward to both ports internally without ssl.
In this example, you can see how the first server acts as main server with cached content (available via https) and if cache content is not available, use the second server (via http).
(using nginx 1.19.6, just for reference)
upstream backends {
server 127.0.0.1:8082;
server 127.0.0.1:8081 backup;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# ssl certs etc here
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout http_404 http_403;
}
access_log /var/log/nginx/access.log upstreamlog;
}
server {
listen 8081;
location / {
add_header X-Cache MISS;
proxy_pass http://server1;
proxy_set_header Host server1;
}
}
server {
listen 8082;
location / {
add_header X-Cache HIT;
proxy_pass https://server2;
proxy_set_header Host server2;
}
}
Taking a shot in the dark. Assuming you were having issues mixing HTTP and HTTPS in the upstream, you could try this in the location block:
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass;
proxy_redirect off;
}
}
And if that didn't work, split the bypass upstream block into bypass1 and bypass2 and reference them accordingly in their corresponding location blocks:
upstream bypass1{
server 192.168.99.1:80; #http
}
upstream bypass2{
server 192.168.99.2:443; #https
}
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass1;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass2;
proxy_redirect off;
}
}
A third option would be reference them both on port 80, and ensure the second upstream server redirects HTTP requests to HTTPS.
I have 2 servers on my network:
one linux machine (192.168.0.2) with a website listening on port 8181 for service1.domain.com
one windows machine (192.168.0.3) with a website listening on port 8080 for service2.domain.com
I want to set up an nginx reverse proxy so that I can route requests like so:
service1.domain.com --> 192.168.0.2:8181 with host header service1.domain.com
service2.domain.com --> 192.168.0.3:8080 with host header service2.domain.com
I have tried with the following config:
### General Server Settings ###
worker_processes 1;
events {
worker_connections 1024;
}
### Reverse Proxy Listener Definition ###
http {
server {
listen 80;
server_name service1.domain.com;
location / {
proxy_pass http://192.168.0.2:8181;
proxy_set_header host service1.domain.com;
}
}
server {
listen 80;
server_name service2.domain.com;
location / {
proxy_pass http://192.168.0.3:8080;
proxy_set_header host service2.domain.com;
}
}
}
But that doesn't seem to work?
Is there anything blindingly obvious that I might be doing wrong here?
this works fine for me:
http {
server {
listen 80;
server_name service1.domain.com;
location / {
proxy_pass http://192.168.0.2:8181;
proxy_set_header host service1.domain.com
}
}
server {
listen 80;
server_name service2.domain.com;
location / {
proxy_pass http://192.168.0.3:8080;
proxy_set_header host service2.domain.com;
}
}
}
have a try?