Sunday, January 31, 2016

IIS - Exposing localhost to the world for free

There are many ways to expose your localhost, such as the free option localtunnel.me and the paid option ngrok.com.

Localtunnel gives you a random URL that only lives as long as your connection is held open, which can be a pain when you have to reconfigure external services to call your app every now and then.

Ngrok allows you to reserve a fixed subdomain, but starts at $60/year and $21/month (minimum 3 users for monthly, yuck!).

So, what is a dirt cheap coder to do? We roll our own of course.

Assumptions:
  1. You already have IIS Manager installed, if not you know what to do. It's free!
  2. You are behind a fixed IP or at least it doesn't change too often.
  3. You already own a mydomain.com and can point app.mydomain.com to your IP. I highly recommend cloudflare.com for managing your DNS records. It's free and awesome.
  4. Your local app is running on localhost:8000

IIS as Reverse Proxy

There are many tutorials on this, so I'll list the main points.
  1. Add a website and point it to some empty folder with the proper permission.

    If your website's application pool is named app.mydomain.com then you want to add read/list/execute permissions to the Windows user IIS AppPool\app.mydomain.com.
     
  2. Go to URL Rewrite of your website, then add a Reverse Proxy rule. Fill in localhost:8000 and choose to rewrite the HTTP links.

     
  3. Profit! No? You are probably seeing an IIS error about not being able to forward gzip'ed responses from the local server. Find the web.config of your reverse proxy website folder (no not your app's web.config) and add the bold sections below. This will strip the Accept-Encoding header on incoming, and add it back on outgoing so the local server does not think the caller accepts gzip'ed HTTP. Sweet.

    The original stackoverflow post on reverse proxy and gzip.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="ReverseProxyInboundRule1" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="http://localhost:8000/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
                        <set name="HTTP_ACCEPT_ENCODING" value="" />
                    </serverVariables>
                </rule>
            </rules>
            <outboundRules>
                <rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
                    <match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:8000/(.*)" />
                    <action type="Rewrite" value="http{R:1}://app.mydomain.com/{R:2}" />
                </rule>
                <rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
                  <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
                  <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
                </rule>
                <preConditions>
                    <preCondition name="ResponseIsHtml1">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                    </preCondition>
                    <preCondition name="NeedsRestoringAcceptEncoding">
                      <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>


Now, either point your domain to your IP or simply edit your local hosts file to point it to 127.0.0.1, and access app.mydomain.com from your browser and watch your local server present its glory stuff.

No comments:

Post a Comment