2 คะแนน โดย GN⁺ 2026-04-30 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • FastCGI เป็นโปรโตคอลพร็อกซีสำหรับส่งคำขอผ่านซ็อกเก็ตไปยัง แบ็กเอนด์ที่รันระยะยาว ได้ โดยแทบไม่ต้องเปลี่ยนโครงสร้าง HTTP handler เดิม
  • รีเวิร์สพร็อกซี HTTP/1.1 มีแนวโน้มที่การตีความขอบเขตข้อความจะคลาดเคลื่อนกันตามแต่ละ implementation ทำให้ยังคงเกิดปัญหาความปลอดภัยร้ายแรงอย่าง desync และ request smuggling ได้ต่อเนื่อง
  • FastCGI ให้ message framing ที่ชัดเจนมาตั้งแต่ปี 1996 และแยกส่วนระหว่างเฮดเดอร์จากไคลเอนต์กับข้อมูลที่เชื่อถือได้ซึ่งพร็อกซีเพิ่มเข้ามาอย่างเป็นโครงสร้าง
  • net/http/fcgi ของ Go จะเติม REMOTE_ADDR ลงใน Request.RemoteAddr และสะท้อนสถานะ HTTPS ไปยัง Request.TLS ทำให้การ ส่งต่อข้อมูลที่เชื่อถือได้ ทำได้โดยไม่ต้องมี middleware แยก
  • แม้จะมีข้อจำกัดอย่างไม่รองรับ WebSockets, ecosystem เครื่องมือที่อ่อนกว่า, และ throughput ต่ำกว่า ในบาง workload แต่หากไม่ต้องใช้ WebSockets และประสิทธิภาพเพียงพอ ก็ยังดูเป็นตัวเลือกที่ใช้งานได้จริง

บทบาทและวิธีนำ FastCGI ไปใช้

  • FastCGI ไม่ได้ใช้แค่กับรูปแบบที่รันโปรเซสแยกตามไฟล์เท่านั้น แต่ยังใช้เป็นโปรโตคอลระหว่างพร็อกซีกับแบ็กเอนด์ที่ รันเป็นเดมอนระยะยาว ผ่าน TCP หรือ UNIX socket ได้ด้วย
  • ใน Go สามารถนำมาใช้ได้โดย import แพ็กเกจ net/http/fcgi แล้วเปลี่ยน http.Serve เป็น fcgi.Serve
    • handler เดิมยังคงใช้ http.ResponseWriter และ http.Request เหมือนเดิม
    • โครงสร้างส่วนที่เหลือของแอปพลิเคชันก็ยังคงเดิม
  • พร็อกซีหลักอย่าง Apache, Caddy, nginx, และ HAProxy รองรับแบ็กเอนด์แบบ FastCGI และการตั้งค่าก็ค่อนข้างเรียบง่าย

ปัญหาการพาร์สเมื่อใช้ HTTP เป็นโปรโตคอลแบ็กเอนด์

  • การทำ reverse proxy ด้วย HTTP นั้นใกล้เคียงกับ ทุ่งกับระเบิดด้านความปลอดภัย และยังมีปัญหาใหม่ ๆ โผล่มาเรื่อย ๆ เช่น ช่องโหว่ desync ใน media proxy ของ Discord ที่ทำให้สามารถแอบดูไฟล์แนบส่วนตัวได้
  • HTTP/1.1 แม้ภายนอกจะดูเหมือนเป็น text protocol ที่เรียบง่าย แต่มีวิธีแทนข้อความเดียวกันได้มากเกินไป และมีข้อยกเว้นจำนวนมาก จึงทำให้แต่ละ implementation ตีความต่างกันได้ง่าย
  • ปัญหาใหญ่ที่สุดคือ HTTP ไม่มี framing ที่ระบุชัดเจน สำหรับตัวข้อความ
    • จุดสิ้นสุดของข้อความถูกอธิบายจากตัวข้อความเองได้หลายแบบ
    • implementation แต่ละตัวอาจตีความจุดสิ้นสุดของข้อความหนึ่งและจุดเริ่มต้นของข้อความถัดไปไม่เหมือนกัน
  • ความไม่สอดคล้องนี้เป็นพื้นฐานของ HTTP desync attacks หรือ request smuggling ซึ่งเกิดจากรีเวิร์สพร็อกซีกับแบ็กเอนด์เข้าใจขอบเขตข้อความไม่ตรงกัน จนนำไปสู่ปัญหาความปลอดภัยร้ายแรง
  • การคอยแพตช์ความต่างของ parser ไปเรื่อย ๆ ยากที่จะเป็น คำตอบเชิงรากฐาน
    • James Kettle ยังคงค้นพบรูปแบบใหม่ ๆ อย่างต่อเนื่อง
    • หลังพบกรณีเพิ่มเติมเมื่อปีที่แล้ว เขาถึงกับใช้คำว่า "HTTP/1.1 must die"

การจัดการขอบเขตข้อความของ FastCGI และ HTTP/2

  • HTTP/2 หากใช้อย่างสม่ำเสมอระหว่างพร็อกซีกับแบ็กเอนด์ ก็สามารถทำให้ขอบเขตข้อความชัดเจนและแก้ปัญหา desync ได้
  • FastCGI ให้การแยกขอบเขตที่ชัดเจนแบบนี้ผ่านโปรโตคอลที่เรียบง่ายกว่ามาตั้งแต่ปี 1996
  • nginx รองรับแบ็กเอนด์ FastCGI มาตั้งแต่รีลีสแรก แต่การรองรับ แบ็กเอนด์ HTTP/2 เพิ่งถูกเพิ่มเข้ามาในช่วงปลายปี 2025
  • การรองรับแบ็กเอนด์ HTTP/2 ของ Apache ยังคงอยู่ในสถานะ "experimental"

ปัญหาเฮดเดอร์ที่ไม่น่าเชื่อถือและวิธีแยกของ FastCGI

  • ปัญหาไม่ได้มีแค่ desync เท่านั้น เพราะ HTTP ยังขาดวิธีที่แข็งแรงในการขนส่งข้อมูลที่พร็อกซีต้องเชื่อถือและส่งต่อ เช่น IP จริงของไคลเอนต์, ชื่อผู้ใช้ที่พร็อกซีตรวจสอบสิทธิ์แล้ว, หรือข้อมูลใบรับรองไคลเอนต์จาก mTLS
  • ในทางปฏิบัติ ข้อมูลเหล่านี้มักถูกใส่ใน HTTP header แต่ไม่มีการแยกเชิงโครงสร้างระหว่าง ข้อมูลที่เชื่อถือได้ ที่พร็อกซีเพิ่มเข้ามา กับ เฮดเดอร์ที่ไม่น่าเชื่อถือ ที่ไคลเอนต์ส่งมา
  • เฮดเดอร์อย่าง X-Real-IP มักถูกใช้เพื่อส่งต่อ IP จริงของไคลเอนต์ แต่จะปลอดภัยก็ต่อเมื่อพร็อกซีลบเฮดเดอร์เดิมทั้งหมดออกให้หมดก่อน รวมถึงรูปแบบตัวพิมพ์เล็กใหญ่ที่แปลงได้ แล้วค่อยใส่กลับเข้าไปใหม่
  • วิธีนี้เป็น พื้นที่เสี่ยงอย่างยิ่ง และมีหลายช่องทางที่ทำให้แบ็กเอนด์เผลอเชื่อข้อมูลที่ผู้โจมตีใส่มา
  • พร็อกซีจึงต้องลบไม่ใช่แค่ X-Real-IP แต่ต้องลบ ทุกเฮดเดอร์ ที่ใช้เพื่อจุดประสงค์ลักษณะนี้
  • ตัวอย่างเช่น middleware ของ Chi จะ ตรวจ True-Client-IP ก่อน เมื่อต้องกำหนด IP จริงของไคลเอนต์ และจะใช้ X-Real-IP ก็ต่อเมื่อไม่มีค่าแรกเท่านั้น
    • ดังนั้นแม้พร็อกซีจะจัดการ X-Real-IP ถูกต้อง หากผู้โจมตีส่ง True-Client-IP มาก็ยังอาจเกิดปัญหาได้
  • FastCGI แยกเฮดเดอร์จากไคลเอนต์กับข้อมูลที่พร็อกซีเพิ่มเข้ามาโดยใช้ domain separation
    • ทั้งสองแบบถูกส่งเป็นรายการพารามิเตอร์ key/value เหมือนกัน แต่ชื่อ HTTP header จะมีคำนำหน้า HTTP_
    • ดังนั้นจึงไม่เกิดโครงสร้างที่ทำให้เฮดเดอร์จากไคลเอนต์ถูกตีความเป็นข้อมูลที่เชื่อถือได้ของพร็อกซี

การจัดการข้อมูลที่เชื่อถือได้ของ FastCGI ใน Go

  • FastCGI กำหนด standard parameter อย่าง REMOTE_ADDR สำหรับส่งต่อ IP จริงของไคลเอนต์
  • net/http/fcgi ของ Go จะนำค่านี้ไปใส่ใน http.Request ที่ RemoteAddr โดยอัตโนมัติ ทำให้ใช้งานได้โดยไม่ต้องมี middleware เพิ่มเติม
  • พร็อกซียังสามารถส่งข้อมูลอย่างการใช้ HTTPS, TLS cipher suite ที่เจรจาได้, หรือใบรับรองไคลเอนต์ ผ่าน non-standard parameter ได้
  • Go จะตั้งค่า field TLS ของ Request ให้เป็นค่าที่ไม่ใช่ nil โดยอัตโนมัติเมื่อคำขอใช้ HTTPS
    • แม้ค่าภายในจะว่างอยู่ ก็ยังมีประโยชน์สำหรับตรวจสอบการบังคับใช้ HTTPS
  • สามารถเข้าถึงชุดพารามิเตอร์ที่เชื่อถือได้ทั้งหมดที่พร็อกซีส่งมาผ่าน fcgi.ProcessEnv

เหตุผลที่ยังไม่แพร่หลายและข้อจำกัดในโลกจริง

  • หาก FastCGI ดีกว่า เหตุใดจึงไม่ถูกใช้อย่างแพร่หลาย ผู้เขียนมองว่าน่าจะเป็นผลจาก ชื่อที่ดูเป็นเทคโนโลยียุคเก่า ร่วมกับการที่ผู้คนยังตระหนักถึงปัญหาความปลอดภัยของ HTTP reverse proxy ไม่มากพอ
  • Watchfire เคยกล่าวถึงการโจมตีแบบ desync ตั้งแต่ปี 2005 แล้ว และยังเตือนว่าปัญหานี้แก้ได้ไม่ง่าย แต่การโจมตีประเภทนี้กลับไม่ได้รับความสนใจอย่างจริงจังอยู่นานกว่าสิบปี
  • FastCGI ยังใช้งานจริงได้ในปัจจุบัน และที่ SSLMate ก็ใช้ใน production มานานกว่าสิบปี
  • อย่างไรก็ตาม เพราะเป็น เทคโนโลยีเก่า จึงมีจุดอ่อนอยู่บ้าง
    • ไม่ได้ถูกอัปเดตให้รองรับ WebSockets
    • ecosystem เครื่องมือยังไม่แข็งแรง
    • ตัวอย่างเช่น curl รองรับถึง FTP, Gopher, SMTP แต่กลับส่งคำขอ FastCGI ไม่ได้
  • เมื่อนำ Go FastCGI server ไป benchmark หลังรีเวิร์สพร็อกซีหลายตัว พบว่าบาง workload มี throughput ต่ำกว่า HTTP/1.1 หรือ HTTP/2
    • ผู้เขียนมองว่านี่น่าจะไม่ใช่ข้อจำกัดของตัวโปรโตคอลเอง แต่เป็นเพราะ code path ของ FastCGI ยังไม่ได้รับการปรับแต่งเท่ากับ HTTP

บทสรุปสุดท้าย

  • หากไม่ต้องใช้ WebSockets และประสิทธิภาพในปัจจุบันเพียงพอ FastCGI ก็ยังเป็นตัวเลือกที่น่าใช้
  • แม้ภายหลังจะเกิดคอขวดขึ้น ผู้เขียนก็เห็นว่าการ เพิ่มฮาร์ดแวร์ ยังดีกว่าต้องยอมรับความซับซ้อนและฝันร้ายด้านความปลอดภัยของการทำ HTTP reverse proxying

2 ความคิดเห็น

 
rtyu1120 2026-04-30

คอมเมนต์เกี่ยวกับ FastCGI ของ Twisted ที่เจอในคอมเมนต์ของ Lobsters น่าประทับใจทีเดียว https://web.archive.org/web/20160723091923/…

 
GN⁺ 2026-04-30
ความเห็นจาก Hacker News
  • เห็นด้วยกับเจตนาของบทความ สำหรับการใช้งานแบบนี้ ผมมองว่า FastCGI ดีกว่า HTTP
    อยากแนะนำโปรโตคอลชื่อ WAS (Web Application Socket) ด้วย เมื่อ 16 ปีก่อนตอนทำงานผมรู้สึกว่าแม้แต่ FastCGI ก็ยังดีไม่พอเลยออกแบบขึ้นมาเอง
    แทนที่จะใช้ main socket framing มันใช้ control socket 1 ตัวกับ pipe 2 ตัวสำหรับ raw request/response body และทั้ง WAS app กับ web server ก็ใช้ splice() กับ pipe ได้
    ไม่ต้องมี framing, ยกเลิก request ได้ และทำให้กู้คืน file descriptor ทั้งสามตัวได้เสมอ
    ใช้มันมาหลายปีทั้งกับแอปภายในและสภาพแวดล้อมเว็บโฮสติ้ง และยังเขียน PHP SAPI เองด้วย เว็บไซต์จำนวนไม่น้อยรันอยู่บน WAS ภายใน
    ทั้งหมดเป็นโอเพนซอร์ส
    library: https://github.com/CM4all/libwas
    documentation: https://libwas.readthedocs.io/en/latest/
    non-blocking library: https://github.com/CM4all/libcommon/tree/master/src/was/asyn...
    our web server: https://github.com/CM4all/beng-proxy
    WebDAV: https://github.com/CM4all/davos
    PHP fork with WAS SAPI: https://github.com/CM4all/php-src

    • FastCGI กับ HTTP ไม่ได้อยู่ในชั้นเดียวกัน
      HTTP มีไว้ส่งข้อมูลระหว่างปลายทั้งสองด้าน เช่น เบราว์เซอร์กับเซิร์ฟเวอร์ ส่วน FastCGI มีไว้ประมวลผลข้อมูลนั้นระหว่างเซิร์ฟเวอร์กับแอปพลิเคชัน
      ผมเพิ่งไล่อ่านบทความนี้คร่าว ๆ แล้วรู้สึกว่าผู้เขียนใช้มันแบบชวนให้สับสนราวกับว่าทั้งสองอย่างแทนกันได้ แต่จริง ๆ แล้วไม่ใช่เลย
      อ้างอิงจากประสบการณ์ ผมเองก็ใช้ fcgi กับบริการเว็บสำหรับลูกค้ามา 10 ปี
  • บทความนี้น่าสนใจเพราะมีหลายอย่างที่ไม่ได้พูดถึง
    ตอนที่ประเด็น FastCGI vs. SCGI vs. HTTP กำลังถกกันหนัก ๆ ผมก่อตั้งสตาร์ตอัป Web2.0 และประกอบฟรอนต์เอนด์สแต็กเอง สุดท้าย HTTP ชนะเพราะความเรียบง่าย
    ถ้าใช้ HTTP ที่เกตเวย์ต้องจัดการอยู่แล้วต่อไปตรง ๆ ก็ไม่ต้องเพิ่มโปรโตคอลอื่นเข้ามาในสแต็ก และทำให้ใส่ reverse proxy ได้หลายชั้น หรือแยก concern แบบข้ามส่วนอย่าง authentication, session, SSL termination, DDoS filtering ออกเป็นเซิร์ฟเวอร์ตามบทบาทได้ง่ายมาก
    ในสภาพแวดล้อมพัฒนา เราต่อเข้า app server ด้วย HTTP โดยตรงได้ ส่วนใน production ก็ใช้ reverse proxy มาจัดการ SSL, authentication และการตรวจจับการใช้งานผิดปกติ โดยยังใช้ app server ตัวเดิมได้เลย
    ตอนนั้น nginx ยังเร็วและเสถียรกว่าโมดูล FastCGI/SCGI ส่วนใหญ่มากด้วย ตอนแรกเราจัดเป็น HTTP -> Lighttpd -> FastCGI -> Django แต่ใช้ nginx ตรง ๆ เร็วกว่ามาก
    การใช้ HTTP ทำงานคล้าย End-to-End Principle ฉบับเว็บ คือเครือข่ายกับโปรโตคอลควรไม่สนใจสิ่งที่ส่งผ่าน และ logic ของแอปควรอยู่ที่ปลายทาง ไม่ใช่อยู่ในโหนดเครือข่ายที่คอยกรองหรือ redirect
    แต่ประเด็นสำคัญที่บทความชี้คือ ในแง่ความปลอดภัย หลายครั้งการยึด หลักสิทธิ์ขั้นต่ำ (PoLP) จะดีกว่า ควร allowlist เฉพาะการสื่อสารที่คาดไว้ เพื่อไม่ให้เผลอช่วยให้การเจาะระบบจากจุดอื่นทำงานได้
    สุดท้ายแล้วสองอย่างนี้มีความตึงกันอยู่ E2E ให้ความยืดหยุ่น แต่ความยืดหยุ่นนั้นก็เพิ่มช่องให้ถูกนำไปใช้ผิด ส่วน PoLP ให้ความปลอดภัย แต่ก็ทำให้ทำได้แค่สิ่งที่ออกแบบไว้ จึงปรับตัวยากเมื่อมีความต้องการใหม่
    [1] https://en.wikipedia.org/wiki/End-to-end_principle
    [2] https://en.wikipedia.org/wiki/Principle_of_least_privilege

    • ผมว่าอุปมานั้นไม่ค่อยตรง โดยเฉพาะในบริบทของ connection caching และ multiplexing
      ถ้าเกตเวย์กลาง multiplex HTTP request หลายตัวลงใน HTTP channel ตัวเดียวที่ต่อไปถึง listening service โดยตรง และไม่ demultiplex ก่อนถึง application socket นั่นถือว่าทำลายตรรกะ end-to-end อย่างพื้นฐานในหลายทาง
      อุปมานั้นพอจะใช้ได้ก็เฉพาะตอนที่ยังคงสมมาตรของการเชื่อมต่อแบบ 1:1 เท่านั้น
      ผมมองว่าช่องโหว่ของ reverse proxy ทั้งหมดเกิดขึ้นโดยตรงจากการละเมิด end-to-end
      ถ้าอุปมานั้นถูก การส่ง SMTP ผ่าน MX หลายตัวก็ควรถือเป็น end-to-end ด้วย แต่ในความจริงมันไม่ใช่ และยังเจอปัญหาคล้าย reverse proxy เยอะ เช่น message boundary desync
      ผมเข้าใจเจตนาที่พยายามเทียบ HTTP request กับข้อความ แต่พอเจอ semantics ของ TCP·HTTP จริง ๆ และรายละเอียดโปรโตคอลสารพัด มันก็พังเร็วมาก
      หลัก end-to-end ไม่ได้ยอมให้จัดการ semantics แบบหยาบ ๆ ได้ มันต้องการวินัยที่เข้มงวดมากเรื่อง state management และขอบเขตของ transport layer ของที่แค่พอคล้าย end-to-end ไม่ใช่ end-to-end
    • สำหรับนักพัฒนาเว็บแอป HTTP semantics มีประโยชน์ แต่ตัว HTTP wire protocol เองแย่มาก
      ตัวอย่างเช่นมันไม่มี multiplexing จนถึง HTTP 2.0 เพราะงั้นการใช้ HTTP ตรง ๆ ระหว่าง reverse proxy กับ backend จึงสิ้นเปลืองมาก
      ยังมีปัญหาด้านความปลอดภัยด้วย เพราะ parser ต่างตัวอาจตีความจุดสิ้นสุดของขอบเขต request ไม่ตรงกันด้วยซ้ำ
      Google เองก็นานมากแล้วที่ใช้โปรโตคอล Stubby ของตัวเองมาห่อ HTTP ระหว่าง front web server กับแอปพลิเคชัน
      มันเร็วกว่า HTTP wire protocol มากและฟีเจอร์ก็เยอะกว่า ปกติอาจเกินความจำเป็นสำหรับบริษัททั่วไป แต่เมื่อสเกลใหญ่ขึ้น ค่าใช้จ่ายในการทำ wire protocol อื่นพร้อม tooling รอบตัวขึ้นมาเองก็สมเหตุสมผลได้
    • การเอา end-to-end principle มาใช้ภายในดาต้าเซ็นเตอร์แทบไม่มีความหมาย และอย่างที่บทความนี้แสดงให้เห็น มันกลับเปิดทางให้เกิดพฤติกรรมที่ไม่ปลอดภัย
    • สิ่งที่ผมไม่ชอบใน nginx คือ เอกสาร จริง ๆ รู้สึกว่าแทบไม่มีประโยชน์
      httpd เองก็เดินไปในทางที่ทำให้การตั้งค่ายากขึ้น ณ จุดหนึ่ง และผมก็เลิกใช้ตอนที่มันเปลี่ยนรูปแบบคอนฟิกแบบหักดิบ
      ผมอาจจะปรับตัวได้ แต่เลือกย้ายไป lighttpd แทน แล้วหลังจากนั้น ruby ก็ช่วยทำคอนฟิกอัตโนมัติ จนในทางเทคนิคผมคงกลับไปใช้ httpd ก็ได้
      ถึงอย่างนั้นก็ไม่อยากกลับไปอยู่ดี ถ้าเป็นนักพัฒนาเว็บเซิร์ฟเวอร์ ควรคิดให้รอบคอบก่อนบังคับให้ผู้ใช้ต้องย้ายไปเข้ารูปแบบใหม่
      ถ้าจะเปลี่ยน format คอนฟิกด้วยเหตุผลง่าย ๆ แบบนั้น อย่างน้อยก็ควรมีตัวเลือกเพิ่มอย่าง yaml config ให้ใช้ด้วย แทนที่จะบังคับ syntax สไตล์ if-clause แบบใหม่ทันที
  • ตอนนี้ที่ WHATWG streams กระจายอยู่ทั่วไปในเบราว์เซอร์แล้ว การทำของคล้าย WebSocket เองบน HTTP request แบบอายุยาวก็ง่ายพอสมควร
    แค่ส่ง byte stream แล้วใส่ header ไว้หน้าข้อความแต่ละอัน ซึ่งหลายกรณีมีแค่ค่าความยาวก็พอ
    มันมีข้อดีด้วย ไม่ต้องมีเส้นทางพิเศษในชั้นเซิร์ฟเวอร์แบบ WebSocket, ใช้ backpressure ได้, ได้ประโยชน์จาก HTTP/2·HTTP/3 ฟรี และมี framing overhead ต่ำกว่า
    แต่เท่าที่ผมรู้ AFAIK ยังไม่รองรับการสตรีม request body ต่อเนื่องไปพร้อมกับรับ response พร้อมกัน ดังนั้นถ้าจะทำ full duplex streaming จริง ๆ ต้องใช้ request สองตัว

  • ผมเพิ่งกลับไปเจอ plain CGI แบบเก่าอีกครั้ง และมันเหมาะมากสำหรับให้ผู้ใช้บนแพลตฟอร์มเราทำหน้าแบบกำหนดเองด้วย vibe code [1]
    ฟังก์ชันที่มีมาให้พื้นฐานคือ task list กับ data viewer แต่ผู้ใช้มักอยากได้การปรับแต่งละเอียดกว่านั้นมาก เช่น Kanban view หรือ custom dashboard ที่มี data filter กับ chart
    ในกล่องนี้มี coding agent อยู่ เราเลยให้ผู้ใช้เขียนสิ่งที่ต้องการเองได้ แทนที่จะต้องมาสร้าง report builder แบบดั้งเดิม
    Go stdlib รองรับดีทั้งฝั่งเซิร์ฟเวอร์และ user space และถ้า coding agent สร้าง page-name/main.go ให้แล้วสื่อสารผ่าน CGI เซิร์ฟเวอร์ก็จะส่งต่อ request ไปที่นั่น
    ขนาดข้อมูลและ pageview ทั้งหมดอยู่ที่ระดับ person scale จึงไม่จำเป็นต้องมี optimization แบบ FastCGI อะไรเป็นพิเศษ
    ในยุคของ agent เทคโนโลยีเก่ากลับมาดูใหม่อีกครั้ง

    1. https://housecat.com
    • ต้องระวังว่า CGI ต่างจาก FastCGI ตรงที่มันส่ง HTTP header ผ่าน environment variable ซึ่งมีจุดอันตรายค่อนข้างใหญ่: https://httpoxy.org/
      implementation ฝั่ง CGI server ของ Go ไม่ได้ตั้งค่า $HTTP_PROXY จึงปลอดภัยในจุดนั้น แต่ถึงอย่างนั้นผมก็ยังไม่ชอบวิธีที่ CGI ใช้ environment variable อยู่ดี
  • ฝั่ง reverse proxy ส่วนใหญ่ทำงานไม่ซับซ้อน จึงใช้ความสามารถที่มีมาในตัวของ Nginx ก็เพียงพอแล้ว
    ถึงอย่างนั้น ถ้าต้องการอะไรที่ซับซ้อนกว่านั้น แนวคิดที่จะใช้ FastCGI ก็อาจไม่ใช่สิ่งที่ผมจะนึกถึง
    เมื่อราว 10 ปีก่อนผมเคยใช้ FastCGI นิดหน่อยเพื่อเอาโค้ด C++ บางส่วนมารันบนเว็บ แต่หลังจากนั้นแทบไม่ได้ใช้อีกเลย

    • ทุกวันนี้ embedded server พบได้บ่อยกว่ามาก
      แค่ใส่ HTTP server เข้าไปในแอปพลิเคชันโดยตรง แล้วจัดการสิ่งที่ต้องทำเองโดยไม่ต้องมีเกตเวย์
  • คอนฟิก PHP/Apache ที่แจกในสาย Red Hat คือ FPM (FastCGI Process Manager)
    ผมไม่แน่ใจว่าในดิสโทร RHEL มีการใช้ FastCGI ที่อื่นอีกหรือเปล่า
    $ rpm -qi php-fpm | grep ^Summary
    Summary : PHP FastCGI Process Manager

    • สิ่งที่คุณน่าจะหาอยู่ไม่ใช่ FPM แต่เป็น mod_proxy_fcgi มากกว่า
      มันอยู่ในแพ็กเกจ httpd-core ของ Fedora ส่วน RHEL ผมไม่แน่ใจ: https://packages.fedoraproject.org/pkgs/httpd/httpd-core/fed...
  • มี uwsgi protocol ด้วย
    มันเองก็มีลักษณะคล้าย RPC สำหรับแทบทุกอย่างเหมือนกัน

  • FCGI ก็เป็นระบบ orchestration ด้วย
    ถ้าโหลดสูงขึ้นมันจะเปิด server task เพิ่ม พอโหลดลดก็ปิดลง และถ้า task ตายก็เปิดสำเนาใหม่
    มันเหมือน Kubernetes สำหรับเครื่องเดียว

    • จากประสบการณ์ผม ฟีเจอร์นั้นไม่ค่อยดีเท่าไร
      ฟังดูดี แต่ที่เจอบ่อยคือโหลดต่ำ ๆ ทำงานได้ดี พอโหลดสูงขึ้นแล้วเริ่มสร้าง worker เพิ่มกลับกินหน่วยความจำจนหมด
      เพราะงั้นการกำหนดจำนวน worker แบบคงที่มักดีกว่า
      แต่ crash recovery ก็มีประโยชน์ถ้าต้องการ
    • ฝั่งเราก็ใช้แบบนั้นเหมือนกันเป๊ะ
  • ขอหยุดชื่นชม ความวิปลาส ของ HTTP header สักครู่
    ถ้าใช้ X-Real-IP เฉพาะตอนที่ไม่มี True-Client-IP ต่อให้ proxy ใส่ X-Real-IP มาอย่างถูกต้อง ผู้โจมตีก็ยังเจาะได้ด้วยการส่ง header True-Client-IP มาด้วย
    มีทั้ง X-Forwarded-For, X-Real-IP, และ custom header เฉพาะของแต่ละ CDN บางอันเป็นรายการคั่นด้วย comma และมักแถม IP ของ LB ฝั่งเราเองมาแบบไร้ประโยชน์ด้วย
    ผมเข้าใจว่าทำไมมันถึงเป็นแบบนั้น แต่มันไม่ได้ช่วยอะไรเลย
    ยิ่งไปกว่านั้น header พวกนี้ทั้งหมดถูก user-agent ที่เป็นอันตรายแทรกเข้ามาได้ด้วย เหมือนว่าไม่มีใครตกลงกันได้เลยว่าเซิร์ฟเวอร์ที่เชื่อถือได้ควรส่งข้อมูลสำคัญผ่าน pipeline อย่างไร
    ความวุ่นวายนี้ยังเข้าคู่กับ ความวิปลาส ของ header User-Agent ได้ดีอีกด้วย
    ฝั่งนั้น Apple ก็ยิ่งพาไปสุดทางด้วยการส่งข้อมูลปลอมแบบเต็มตัว โดยอ้างเรื่องความเป็นส่วนตัว เช่นหมายเลขเวอร์ชัน OS ปลอมอะไรทำนองนั้น

  • ข้อโต้แย้งนี้มีน้ำหนักมาก แต่ FastCGI มีข้อสูญเสียเพราะมันตาม CGI/1.1 ในจุดอย่าง PATH_INFO
    มันบังคับให้ทำ URL decoding เลยไม่สามารถแทน encoded slash อย่าง %2F ได้
    บาง implementation ยังรวม // ใน path ให้เหลือ / ด้วย ซึ่งปัญหานี้ก็พบใน HTTP implementation หลายตัวเหมือนกัน
    ในแง่ expressiveness มันด้อยกว่า HTTP และความต่างนี้จะสำคัญหรือไม่ก็ขึ้นอยู่กับแอปพลิเคชัน
    โดยส่วนตัวผมชอบแนวทางที่จัดการ URL ได้อย่างแม่นยำมากกว่า