Many clients host their PHP application on a subdomain like blog.example.com, but later decide that they want the same site to appear under a subdirectory such as:
And they want:
- NO redirect
- URL must stay example.com/blog
- Content must come from blog.example.com
- All internal links must continue to work
This can only be done using a Reverse Proxy.
On an IIS server, the correct way to do this is using:
- Application Request Routing (ARR)
- URL Rewrite
This combination allows IIS to forward requests internally to the subdomain and rewrite outbound links so the user never sees the subdomain.
✔ Why Point 4 (Inbound Rewrite Only) Is NOT Enough
Many developers try only the following inbound rule:
<rule name="Blog Reverse Proxy" stopProcessing="true">
<match url="^blog/(.*)" />
<action type="Rewrite" url="http://blog.example.com/{R:1}" />
</rule>
This will load the PHP site from the subdomain, but it causes major problems:
- CSS, JS, and images will still load from blog.example.com
- Internal links redirect to blog.example.com
- Forms submit to the subdomain
- Login redirects break (WordPress, Laravel, etc.)
- The illusion of
/blogis lost
This happens because the backend continues to generate absolute URLs.
So inbound only = proxy works, but site breaks.
✔ What You Actually Need
To make the site fully functional under example.com/blog, you need two rules:
1. Inbound Rewrite (Reverse Proxy Request Forwarding)
This forwards all /blog/... requests to the PHP site.
<rule name="Blog Reverse Proxy" stopProcessing="true">
<match url="^blog/(.*)" />
<action type="Rewrite" url="http://blog.example.com/{R:1}" />
<serverVariables>
<set name="HTTP_X_Forwarded_For" value="{REMOTE_ADDR}" />
<set name="HTTP_X_Forwarded_Proto" value="https" />
<set name="HTTP_HOST" value="blog.example.com" />
</serverVariables>
</rule>
2. Outbound Rewrite (Fix HTML Links, Images, CSS, JS)
This replaces URLs inside HTML output so browsers never see the subdomain.
<outboundRules>
<rule name="Fix absolute URLs" preCondition="IsHTML">
<match filterByTags="A, Form, Img, Script, Link"
pattern="http://blog\.example\.com/(.*)" />
<action type="Rewrite" value="/blog/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
Now all links such as:
http://blog.example.com/category
http://blog.example.com/wp-content/themes/style.css
automatically become:
/blog/category
/blog/wp-content/themes/style.css
This keeps users inside /blog forever.
🧩 Final Combined Working web.config
Put this inside the main site (example.com) web.config:
<configuration>
<system.webServer>
<rewrite>
<!-- Inbound reverse proxy rule -->
<rules>
<rule name="Blog Reverse Proxy" stopProcessing="true">
<match url="^blog/(.*)" />
<action type="Rewrite" url="http://blog.example.com/{R:1}" />
<serverVariables>
<set name="HTTP_X_Forwarded_For" value="{REMOTE_ADDR}" />
<set name="HTTP_X_Forwarded_Proto" value="https" />
<set name="HTTP_HOST" value="blog.example.com" />
</serverVariables>
</rule>
</rules>
<!-- Outbound rules to fix internal links -->
<outboundRules>
<rule name="Fix absolute URLs" preCondition="IsHTML">
<match filterByTags="A, Form, Img, Script, Link"
pattern="http://blog\.example\.com/(.*)" />
<action type="Rewrite" value="/blog/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
🎉 Result
After applying both rules:
✔ Visiting example.com/blog will load the PHP site
✔ URL will NOT redirect
✔ All CSS, JS, and images will load correctly
✔ Internal site links stay under /blog
✔ Backend (PHP) keeps running normally on blog.example.com
This is the correct and complete reverse proxy setup for IIS.

Ankit Srivastava is an IT trainer, technology educator, and digital skills mentor with expertise in programming, data analytics, AI, and software development. He has successfully trained thousands of learners, with more than 10,000 student enrollments on Udemy. His practical teaching approach empowers students and professionals to build in-demand technical skills. Colorstech channel where Ankit posts video tutorials has more than 8000 Subscribers.

