Dynamic Nginx Configuration for Internal Proxy

Working around a home network can be challenging at times, especially when it comes to a secular ip address. Doing web and api development, this introduces an even greater problem in the fact that now theres only one entry point. To solve this I considered many options, the main being setting up a VPN, which would solve the problem, but would require additional setup on each client device. Instead I decided to investigate nginx and its reverse proxy ability.

The design is simple, have a singular domain, with a wildcard mask that resolves to individual hosts inside the network. I then wanted to ensure https everywhere from the outside so utilizing Blockchain Debugger guide, I set up a wildcard certificate at edge, and then allowed for non-certified traffic inside my network.

Concept Design

I then utilized Puppet as a configuration management tool to deploy and ensure the nginx service is continually running. This also gave me templated configuration ability. Written in erb, the nginx config is a standard text file with variable input, but the key component is the the proxy_pass statement:

proxy_pass https://$subdomain.<%= @internaldomain %>;

Once this template gets laid down the <%= @internaldomain %> will resolve to my internal domain name. For example, let say my internal dns domain was home.com, and my external domain was example.com. If I attempted to send an http request to foo.example.com, the external dns would resolve to my home, which would then port forward to the nginx server. From there the proxy_pass statement would first derive the hostname foo, and proxy my request to foo.home.com.

server {
listen 80;
server_name *.<%= @domain %>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name <%= @domain %>;
ssl_certificate /etc/letsencrypt/live/<%= @domain %>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<%= @domain %>/privkey.pem;
location / {
resolver 192.168.1.1;
proxy_pass http://admin;
}
}
server {
listen 443 ssl http2;
server_name *.<%= @domain %>;
ssl_certificate /etc/letsencrypt/live/<%= @domain %>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<%= @domain %>/privkey.pem;
if ($host ~* ^(www\.)?([^.]+).<%= @domain %>$) {
set $subdomain $2;
}
location / {
resolver 192.168.1.1;
proxy_pass https://$subdomain.<%= @internaldomain %>;
}
}
view raw nginx.conf.erb hosted with ❤ by GitHub

Overall this design provides many benefits. The first being security, such that as long as the walls on the outside are sturdy, there is only one port in, and all traffic is secure. The second benefit is the ability to now have more domains accessible outside, alleviating the once blocker of external resources not able to get in.