Nginx as a Reverse Proxy

I'm wanting to use nginx on device as a reverse proxy, so that the device points to the internal LAN resource based on the URL/URI.

I've got Luci w/ nginx installed. Ideally, I'd like it to serve port 80/443 on br-lan and have the reverse proxy on the wan interface to act as the forwarding agent from outside->in.

I found https://serverfault.com/questions/886582/single-server-nginx-as-a-reverse-proxy-multiple-domains-websites which describes the format, but I'm not sure how to apply it to the OpenWrt package using the /etc/nginx/conf.d

Any assistance would be greatly appreciated!

Where does it go wrong? I'm going to give a couple of shots in the dark here in case it helps.

1- Is the issue that you can't listen on 80/443 as the ports are taken by luci? If so, make sure you only bind to the interface/IP address that you want to serve content on. so Luci would listen on your lan IP and nginx on your wan IP

2- Is the issue with your nginx config? If so, are you able to serve the default nginx page to the outside world? once you have that you can change your server{} section to do a location redirect to your internal luci (using the IP address it's now bound to from the change in 1 above)

3- If you can serve a simple page from nginx but that's only accessible locally, check your firewall settings.

1 Like

I'm running the stock nginx configuration that loads default with the luci package.

config main global
        option uci_enable 'true'

config server '_lan'
        list listen '443 ssl default_server'
        list listen '[::]:443 ssl default_server'
        option server_name '_lan'
        list include 'restrict_locally'
        list include 'conf.d/*.locations'
        option uci_manage_ssl 'self-signed'
        option ssl_certificate '/etc/nginx/conf.d/_lan.crt'
        option ssl_certificate_key '/etc/nginx/conf.d/_lan.key'
        option ssl_session_cache 'shared:SSL:32k'
        option ssl_session_timeout '64m'
        option access_log 'off; # logd openwrt'

config server '_redirect2ssl'
        list listen '80'
        list listen '[::]:80'
        option server_name '_redirect2ssl'
        option return '302 https://$host$request_uri'

The issue is that I'm simply don't know nginx :slight_smile:
I've looked up documentation and they reference front-end and back-end sections, which don't seem to fit in this format? or am I just being especially dense with it?

2 Likes

I see, I haven't used nginx on openwrt yet so wasn't aware that the luci-nginx package does the heavy lifting that I mentioned in my first post. (I've now read the nginx section here)

Sorry, I still don't really understand what you are missing or what is failing for you...

If you want a specific domain to also work and point to your luci, you can add a server section in UCI or a new .conf file in /etc/nginx/conf.d (see here).

You can think of an nginx "server" as a section that handles a specific subset of the whole picture (eg. the _redirect2ssl server listens on port 80 and sends a 302 to redirect all traffic to https - the next client request will hit the _lan server on 443 and server whatever is configured there - currently luci)

The idea with backend / frontend is that you typically run the web services locally on ports that are not accessible from the outside world (eg. 4000 in your stackoveflow post), these are called backend. And then you use a "server" in nginx to listen on a publicly accessible port (eg. 443), these are called frontend. So in your setup, luci is the "backend" and the two servers in your nginx are the "frontend".

I think I have it figured out :slight_smile: I just need to get a wildcard Acme SSL Cert that covers what the proxy handles to use on the WAN-facing server defines

This is what I ended up with:

/etc/config/nginx

config main global
        option uci_enable 'true'

config server '_lan'
        list listen '192.168.1.1:443 ssl default_server'
        list listen '[fd42:bcc8:69d1:4::1]:443 ssl default_server'
        option server_name '_lan'
        list include 'restrict_locally'
        list include 'conf.d/luci.locations'
        option uci_manage_ssl 'self-signed'
        option ssl_certificate '/etc/nginx/conf.d/_lan.crt'
        option ssl_certificate_key '/etc/nginx/conf.d/_lan.key'
        option ssl_session_cache 'shared:SSL:32k'
        option ssl_session_timeout '64m'
        option access_log 'off; # logd openwrt'

config server 'bitwarden'
        list listen '192.168.200.143:443 ssl'
        option server_name 'bitwarden.example.com'
        list include 'conf.d/bitwarden.locations'
        option uci_manage_ssl 'self-signed'
        option ssl_certificate '/etc/nginx/conf.d/_lan.crt'
        option ssl_certificate_key '/etc/nginx/conf.d/_lan.key'
        option ssl_session_cache 'shared:SSL:32k'
        option ssl_session_timeout '64m'

config server '_redirect2ssl'
        list listen '80'
        list listen '[::]:80'
        option server_name '_redirect2ssl'
        option return '302 https://$host$request_uri'

/etc/nginx/conf.d/bitwarden.locations

location / {
        proxy_pass              https://bitwarden.example.com:443;
}

Now, will the device's DNS prefer the internal connected IP for bitwarden.example.com even though the Public DNS sent it to the WAN port in the first place? or will it just loop?

I can't test this myself because until I get this working, I can't uncouple my public DNS from the hosting provider to move it local. I'd rather have it working before killing it :smiley:

I'm currently using "bitwarden.example.com" on the LAN side, but "bitwarden.example.cc" on the public side, so I need to know how the router will handle a request coming in for bitwarden.example.com where that URL have both a public and a private (on device) DNS entry.

Edit: Also, is there a $remote_addr type thing I can put in there for the WAN IP?

1 Like

I've got a new issue you might be willing to help me with :slight_smile:

BitWarden generates it's own TLS certs via Acme through LE. If I Port Forward (80/443) via the Firewall to the machine, there are no issues. If I use nginx to reverse-proxy, it breaks the certs. I'm assuming the Openwrt device is playing MITM and causing issues.

Any suggestions on how to solve this?

I expect you're going to have to bring the certificate to your nginx as well and/or possibly manage to tell the connection where to get it from the host that has it.

Something like: https://serverfault.com/questions/341023/nginx-as-reverse-proxy-with-upstream-ssl

Yeah, I tried that and still run into the MITM issues..

I also have been trying this https://stackoverflow.com/questions/34741571/nginx-tcp-forwarding-based-on-hostname/40135151#40135151

My uci.conf.template:

root@openwrt:/etc/nginx# cat uci.conf.template
# Consider using UCI or creating files in /etc/nginx/conf.d/ for configuration.
# Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false
# For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx

worker_processes auto;

user root;

events {}

stream {
    map_hash_bucket_size 64;
    map $ssl_preread_server_name $name {
        bitwarden.tech911.cc bitwarden;
        # vpn2.app.com vpn2_backend;
        # https.app.com https_backend;
        default https_default_backend;
    }

    upstream bitwarden {
        server 192.168.1.193:443;
    }

    upstream https_default_backend {
        server 127.0.0.1:443;
    }

    server {
        listen 192.168.200.143:443;
        proxy_pass $name;
        ssl_preread on;
    }
}

http {
        access_log off;
        log_format openwrt
                '$request_method $scheme://$host$request_uri => $status'
                ' (${body_bytes_sent}B in ${request_time}s) <- $http_referer';

        include mime.types;
        default_type application/octet-stream;
        sendfile on;

        client_max_body_size 128M;
        large_client_header_buffers 2 1k;

        gzip on;
        gzip_vary on;
        gzip_proxied any;

        root /www;

        #UCI_HTTP_CONFIG
        include conf.d/*.conf;
}

But I end up losing the luci site, probably because stream is taking ALL the traffic, not jsut the http.

well, we've reached the limits of how much I can think of without doing a similar setup. I'd track the requests browser and server side to see where things are going, but I'm out of ideas. Good luck!

1 Like

Hello there Grommish..
Any updates on the topic?
I am also is trying to set up reverse proxy with nginx.
Thx!

Any update? I'm trying to do the same thing, but I can't expose the nginx ports