ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

ทำ Reverse Proxy บน IIS ด้วย ARR และ URL Rewrite
Home ทำ Reverse Proxy บน IIS ด้วย ARR และ URL Rewrite

ทำ Reverse Proxy บน IIS ด้วย ARR และ URL Rewrite

องค์กรจำนวนมากมี IIS เป็นเว็บเซิร์ฟเวอร์หลักอยู่แล้ว แต่ทีมพัฒนาเขียนแอปใหม่ด้วย Node.js หรือรันใน Container ซึ่งฟังพอร์ตของตัวเอง การให้ IIS ทำหน้าที่รับคำขอจากภายนอกแล้วส่งต่อไปยังแอปเหล่านั้นทำให้ใช้โดเมนและใบรับรอง SSL ร่วมกันได้โดยไม่ต้องเปิดพอร์ตเพิ่ม

คู่มือนี้ติดตั้งสองส่วนที่ต้องใช้คู่กันคือ Application Request Routing และ URL Rewrite แล้วตั้งค่าให้ครบรวมถึงการส่ง IP จริงของผู้ใช้ซึ่งมักถูกลืม

สิ่งที่ต้องเตรียม

  • Windows Server ที่ติดตั้ง IIS แล้ว
  • แอปหลังบ้านที่ทำงานอยู่ เช่น Node.js ที่ฟังพอร์ต 3000 บน localhost
  • สิทธิ์ Administrator
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
Get-Website

ขั้นตอนที่ 1: ติดตั้งส่วนขยาย

ติดตั้งผ่าน Web Platform Installer หรือดาวน์โหลดตัวติดตั้งโดยตรงจากเว็บไซต์ของ Microsoft ทั้งสองตัวนี้

  • URL Rewrite ตัวเขียนกฎเปลี่ยนเส้นทาง
  • Application Request Routing ตัวที่ทำให้ส่งต่อคำขอข้ามเครื่องได้

ลำดับสำคัญ ต้องติดตั้ง URL Rewrite ก่อน ARR เสมอ ไม่เช่นนั้นจะใช้ร่วมกันไม่ได้

ตรวจว่าติดตั้งแล้ว

Get-WebGlobalModule | Where-Object Name -like "*Rewrite*"
Get-WebGlobalModule | Where-Object Name -like "*RequestRouter*"

ขั้นตอนที่ 2: เปิดโหมด Proxy

ขั้นตอนนี้เป็นสวิตช์หลักที่ถ้าไม่เปิดแล้วทุกอย่างจะไม่ทำงาน ในหน้าจอ IIS Manager คลิกที่ชื่อเซิร์ฟเวอร์ระดับบนสุด เปิด Application Request Routing Cache แล้วกด Server Proxy Settings ทางขวา ติ๊ก Enable proxy

หรือสั่งด้วยคำสั่ง

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
  -Filter "system.webServer/proxy" -Name "enabled" -Value "True"

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
  -Filter "system.webServer/proxy" -Name "preserveHostHeader" -Value "True"

Get-WebConfiguration -Filter "system.webServer/proxy" -PSPath 'MACHINE/WEBROOT/APPHOST'

preserveHostHeader ทำให้แอปหลังบ้านเห็นชื่อโดเมนจริงที่ผู้ใช้เรียก ไม่ใช่ localhost ซึ่งสำคัญมากกับแอปที่สร้างลิงก์จากชื่อโฮสต์

ขั้นตอนที่ 3: เขียนกฎส่งต่อ

แก้ไฟล์ web.config ของเว็บไซต์นั้น

notepad C:\inetpub\wwwroot\web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Proxy to Node app" stopProcessing="true">
          <match url="^api/(.*)" />
          <action type="Rewrite" url="http://127.0.0.1:3000/{R:1}" />
          <serverVariables>
            <set name="HTTP_X_FORWARDED_PROTO" value="https" />
          </serverVariables>
        </rule>
      </rules>

      <outboundRules>
        <!-- แก้ลิงก์ที่แอปหลังบ้านส่งกลับมาให้ชี้ถูกที่ -->
        <rule name="Fix redirect location" preCondition="IsRedirection">
          <match serverVariable="RESPONSE_Location" pattern="^http://127.0.0.1:3000/(.*)" />
          <action type="Rewrite" value="https://{HTTP_HOST}/api/{R:1}" />
        </rule>
        <preConditions>
          <preCondition name="IsRedirection">
            <add input="{RESPONSE_STATUS}" pattern="3\d\d" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

ขั้นตอนที่ 4: อนุญาตให้ตั้งตัวแปรของเซิร์ฟเวอร์

การใช้ serverVariables ต้องประกาศอนุญาตก่อน ไม่เช่นนั้นจะได้ข้อผิดพลาด 500.50

Add-WebConfiguration -Filter "/system.webServer/rewrite/allowedServerVariables" `
  -PSPath "MACHINE/WEBROOT/APPHOST" -Value @{name="HTTP_X_FORWARDED_PROTO"}

Add-WebConfiguration -Filter "/system.webServer/rewrite/allowedServerVariables" `
  -PSPath "MACHINE/WEBROOT/APPHOST" -Value @{name="HTTP_X_FORWARDED_HOST"}

Get-WebConfiguration -Filter "/system.webServer/rewrite/allowedServerVariables" `
  -PSPath "MACHINE/WEBROOT/APPHOST"

ขั้นตอนที่ 5: ส่ง IP จริงของผู้ใช้

ARR ส่ง header X-Forwarded-For ให้อยู่แล้ว แต่ต้องเปิดใน Server Proxy Settings ในช่อง Custom Headers

ฝั่งแอปต้องอ่าน header นี้แทนการอ่าน IP ต้นทางโดยตรง เพราะถ้าไม่ทำ Log ของแอปจะบันทึกเป็น 127.0.0.1 ทุกรายการ ทำให้ระบบจำกัดอัตราและระบบตรวจสอบใช้งานไม่ได้

// ตัวอย่างใน Express
app.set('trust proxy', true)

ระวังเรื่องความปลอดภัย ให้เชื่อ header นี้เฉพาะเมื่อคำขอมาจาก Proxy ที่คุณควบคุมเท่านั้น

ขั้นตอนที่ 6: ตั้งหลายปลายทางและกระจายโหลด

สร้าง Server Farm ในหน้าจอ IIS Manager คลิกขวาที่ Server Farms เลือก Create Server Farm เพิ่มเซิร์ฟเวอร์หลายเครื่องเข้าไป ระบบจะสร้างกฎ URL Rewrite ให้อัตโนมัติ

ตั้งการตรวจสุขภาพเพื่อให้หยุดส่งคำขอไปยังเครื่องที่ล่ม โดยเลือก Health Test แล้วระบุ URL ที่ใช้ทดสอบ ช่วงเวลา และจำนวนครั้งที่ยอมให้ล้มเหลว

ขั้นตอนที่ 7: ทดสอบ

Invoke-WebRequest -Uri "https://example.com/api/health" -UseBasicParsing |
  Select-Object StatusCode, Content

# ดูเวลาตอบสนอง
Measure-Command { Invoke-WebRequest "https://example.com/api/health" -UseBasicParsing }

# ตรวจว่าแอปหลังบ้านตอบเองได้
Invoke-WebRequest -Uri "http://127.0.0.1:3000/health" -UseBasicParsing

เปิด Failed Request Tracing เมื่อต้องไล่ปัญหาเชิงลึก ซึ่งจะบอกว่ากฎไหนทำงานและผลเป็นอย่างไรทีละขั้น

Install-WindowsFeature -Name Web-Http-Tracing

ปัญหาที่พบบ่อย

ขึ้นข้อผิดพลาด 502.3

IIS ติดต่อแอปหลังบ้านไม่ได้ ตรวจว่าแอปทำงานอยู่จริงด้วย Test-NetConnection 127.0.0.1 -Port 3000 และตรวจว่าเวลารอตอบไม่สั้นเกินไปในการตั้งค่า Proxy Timeout

ขึ้นข้อผิดพลาด 500.50

ใช้ serverVariables ที่ยังไม่ได้ประกาศอนุญาต ทำตามขั้นตอนที่ 4

หน้าเว็บโหลดได้แต่ CSS และรูปหาย

แอปหลังบ้านสร้างลิงก์แบบพาธเต็มที่ชี้กลับไปยังพอร์ตเดิม แก้ด้วย outbound rule ตามขั้นตอนที่ 3 หรือตั้งค่า base path ในแอปให้ถูกต้อง

แอปเห็น IP ผู้ใช้เป็น 127.0.0.1 ทุกคน

แอปยังไม่ได้อ่าน X-Forwarded-For ตั้งค่าตามขั้นตอนที่ 5 และตรวจว่า header ถูกส่งจริงด้วยการพิมพ์ header ทั้งหมดออกมาดูที่ฝั่งแอป

WebSocket ใช้ไม่ได้

ต้องติดตั้งฟีเจอร์ WebSocket ของ IIS เพิ่มด้วย Install-WindowsFeature Web-WebSockets แล้วรีสตาร์ต IIS

ต้องการวางโครงสร้างเว็บให้รองรับทั้งระบบเดิมและระบบใหม่ ติดต่อ THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security