Transparent dynamic reverse proxy with nginx

A while back I wrote about using Apache as a dynamic reverse proxy. Anyone who has done even minimal research into web servers knows that Apache is the swiss army knife. It trys to be everything for everyone, and like a swiss army knife may not be as good as a more refined too at least as far as efficiency is concerned.

Here is the situation. You have a single pinhole into your private network. You have a single ip at your gateway. You want to serve multiple websites on your lan that may be running on multiple physical servers. Rather than opening up multiple ports and pinholling to all the different spots you want to serve, or getting more external ips and doing 1to1 NAT you can use a reverse proxy to be your single entrance point. The reverse proxy will fetch the content from the backend server and serve it up.

nginx is a HTTP server and mail proxy server. One of its features basic HTTP features is accelerated reverse proxying.

nginx should be available through your package manager so just aptitude (or whatever your package manager is yum, emerge, pacman) install it.

The config file paths shown are Debian specific but the config itself should work on any distro.

Edit /etc/nginx/sites-available/default and make it look like this

server {
     listen  :80;
     server_name  _;
     access_log  /var/log/nginx/proxy.access.log;

     location / {
     proxy_pass      http://$host$uri;
     proxy_redirect off;
     proxy_set_header        Host    $host;
     proxy_set_header        X-Real-IP $remote_addr;
     proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

     error_page   500 502 503 504  /50x.html;
     location = /50x.html {
          root   /var/www/nginx-default;

So this config causes nginx to listen on all interfaces/ips. server_name _; matches on anything so essentially this is a catchall now. You can tail proxy.access.log in order to see the requests are they come in and are served.

The location section is where the actual proxying happens. Since this is a dynamic configuration you need to set a resolver where the requested names can be looked up (and overridden for the local lan address). dnsmasq reads is dns configuration right out of /etc/hosts. It’s easy to install and configure so I reccomend using it. We will install and configure it shortly but for now just leave resolver as proxy_pass does the requesting of the page we are proxying. Since this is a transparent dynamic proxy we just have it request the same thing that was requested of the proxy. proxy_redirect should be set to off since we are just passing on the same request. We need to set a few headers for logfiles on the backend servers as well as making sure that Host is set to the requesting host in case your using name based virtual hosts on your backend servers. I have left the error page in the default config (at least on debian its default). This provides a nice error message in case your proxy is working but one of the backend servers is not. It just serves the index.html that is located in /var/www/nginx-default. Feel free to change that path to something else, modify the index.html or omit the error_page and error page location section all together as they aren’t needed for this to work.

Now we need to get that local resolver (dnsmasq) installed so we can take our reverse proxy for a spin. Go ahead and aptitude (or whatever) install dnsmasq.

At least on debian dnsmasq comes out wanting to serve dhcp. You probably do not want this behavior. There is also the question of needing access to these same services by the same name on your LAN. If you need this you might need to do some slight adjusting of your dns. I might reccomend pointing your main dns to this dnsmask proxy or pointing all of your clients at this dnsmasq install since it will look up other requested names other than those in /etc/hosts. For this example I will assume you will be wanting to access these same web services internally with the same names and bypass the proxy. So I will assume you have either changed your primary dns cacher/resolver (think soho router or whatnot) to the address of the proxy server (since its running dnsmasq as well), or set all of your clients to point directly at the proxy server for dns. We need to edit the dnsmasq config to disable dhcp.

Edit /etc/dnsmasq.conf and add no-dhcp-interface=ethx. Do that for every interface on your system so that your not accidentally serving out dhcp to anyone. If somone has a more generic way to disable dhcp in dnsmasq without specifying each interface I would love to know but from reading the man this was the only way I could find. So you may have something like the following in you /etc/dnsmasq.conf.


After making the change you should be ready to add entries to the proxy servers /etc/hosts for dnsmasq to use and then test your reverse proxy.

Lets say you have served off of a machine with the ip and you have served off of Lets also assume that your world routeable ip is You will need to make sure that your authoritative dns (the real one that servs for has A records for both and pointing to Now on the machine running dnsmasq (in this example also your proxy server) add the following entries to /etc/hosts.

Go ahead and restart dnsmasq (from making changes to the config, subsequent changes to /etc/hosts should not require dnsmasq restart to pick up changes) and nginx.

Now tail your proxy.access.log file and start making requests to and from both the inside of your lan as well as outside against your world ip. It should all magically serve up the same content.

This type of config can be useful in many situations. You have a small office and budget that reflects that not being able to afford multiple ips but needing to provide web services behind the firewall. You work in a large corporation where someone else manages the firewall and you would like to bring up more web services without waiting for the other person to make the necessary changes to the firewall.

One of the other benefits this provides is being relatively self documenting  with regard to what web services you host behind the firewall. (you should be able to see all of them in /etc/hosts since you have to override the dns)


  • Jerad Windows XP Google Chrome wrote:

    Heyo Nick, this is the same fellow you helped by pointing me here on a week or so ago.

    I’ve got this sorta-kinda working, but I’ve also caught a snag. It’s redirecting to the correct site at the moment, but it’s breaking my css and functionality on a phpbb forum whenever I access it outside the local network (it works fine inside the local network).

    You can see what I’m talking about at

    any ideas?

    (I also posted this question at linuxquestions under the “software” questions area.

  • med Mac OS X Firefox 3.0.13 wrote:

    great tip, isn’t it possible to add authetication as it can be done with apache ?

    great thanks


  • Hello i’m looking for an experienced System Administrator to set-up Nginx on my VPS account (very trafficked wordpress blog.) since i’m experiencing problems with Apache
    Contact me if you are interested about the small job at

    seffignoz at gmail d o t com

  • Hi, i want to transfer my website in a VPS but don’t have any experiece with this server. sould i choose a vps managed service of unmanaged?? is there any one how ca help me? i can pay you for your time. thank you.

  • Thanks for your very good tutorial.
    Just tell you some problems I got.
    It works perfectly if I replace the directive
    proxy_pass http://$host$uri
    proxy_pass; #(IP of the original web server )
    But if I do so, there’s no dynamic any more.

    if I use
    proxy_pass http://$host$uri
    and add something like
    in the /etc/hosts file
    errors occur.

    I use Ubuntu 10.04 with NginX 0.8.54
    errors got:

    2011/04/05 14:41:21 [alert] 14219#0: worker process 14274 exited on signal 11
    2011/04/05 14:41:22 [alert] 14219#0: worker process 14275 exited on signal 11
    2011/04/05 14:41:25 [alert] 14219#0: worker process 14276 exited on signal 11

  • Thats interesting, looks like possibly a bug in Nginx. It’s been so long since I have used a setup like this. You could try a similar configuration with apache.

  • Hello,
    Your configuration works perfectly except from one thing. That is the trailing slash problem.
    Detail: if url for folder not include the trailing slash “/” it will be redirect to the localhost automatically.
    I found many post about that problem, but no luck.
    Could you please figure it out?

    Example: I have domain : with folder images
    If user enters “”, it works well.
    But if user enter: “”, the site get redirected to his/her IP address automatically. I do not know the reason why and how to fix it.
    If you can do me a favour, thank you very much in advance.

    I try to use rewrite in nginx like
    rewrite ^([^.]*[^/])$ $1/ permanent;
    or use:
    server_name_in_redirect off;

    Nothing works at all.

  • It has been a long time since I have used a configuration like this.

    Try fiddling around with the regex match. Maybe ^(.*)$

  • I have problem with this model.
    My VPS become free proxy for other to access. Do you know how to block query to external host. I mean only the host listed in /etc/hosts file canbe served, others should be ignored.
    I have tried to force dnsmasq to use only local host file; howerver, still not succeeded.

  • duckpond Windows other version Firefox 27.0 wrote:

    I used this approach, but added line for referer:
    proxy_set_header referer “”;

    unfortunately, this line is ignored, now matter what value i supply for the referer, my server always sees the true referer.

Leave a Reply

Your email is never shared.Required fields are marked *

To submit your comment, click the image below where it asks you to...
Clickcha - The One-Click Captcha