ทำ Reverse Proxy เข้า Raspberry Pi เน็ตบ้าน ด้วย Cloudflare Workers และ Heroku

เมื่อสัปดาห์หลังจากที่ผมหาทางทำเปิดเร้าเตอร์ที่บ้านตลอดเวลาได้สำเร็จ ก็เกิดนึกสนุกอยากจะเอาเว็บอ่านการ์ตูนบน Raspberry Pi ในตำนานกลับขึ้นมาใช้อีกครั้ง แต่รอบนี้มันความท้าทายตรงที่ว่า เน็ตบ้านมันอยู่หลัง NAT ของ ISP ทำให้เข้าผ่าน Domain สวยๆ ไม่ได้ แต่ด้วยดันทุรังจึงหาทางทำ Reverse Proxy ขึ้นมาจนได้ แต่ก็ยังไม่สาแก่ใจ ด้วยกระแสความฮอตของ Serverless รอบนี้เลยขอทำแบบ Serverless ไปเลยละกัน ชายตามองไปเห็น Cloudflare Workers ยังไม่เคยใช้มาก่อน จึงเป็นโอกาสดีที่จะได้เรียนรู้ แต่หารู้ไม่ว่าเส้นทางนั้นคดเคี้ยวนัก คดเคี้ยวซะจนขอมาเขียน Blog บอกเล่าความพยายามซะหน่อย เผื่อจะมีเกร็ดความรู้ที่มีประโยชน์สำหรับหลายๆ คน

Project เว็บอ่านการ์ตูนส่วนตัว บน Raspberry Pi

ผมขอเล่าที่ไปที่มาของเว็บ https://manga.spicydog.org ต้นเรื่องของเรากันก่อน สืบเนื่องมาจากที่ผมเป็นคนอ่าน Manga อยู่ประมาณหนึ่ง (จริงๆ ก็แค่ 2 เรื่อง) ทีนี้ก็เป็นคนชอบทำ Web Crawler ด้วย บวกกับหน้าที่การงานที่วุ่นวายขึ้นเรื่อยๆ ก็เลยพยายามหาทางทำยังไงให้เราไม่ต้องมาคอยเช็คว่า Manga ตอนใหม่มันออกมาแล้วหรือยัง มันน่าจะต้องมี Notification แล้วส่งของมาให้เราอ่านได้เลยนะ จะทำยังไงดี

ด้วยความเป็นโปรแกรมเมอร์ อยากได้ก็ต้องทำเอง ก็เลยทำการเขียน Crawler ให้มันไปดูดข้อมูล Manga ที่เราสนใจมาเก็บเอาไว้บน Raspberry Pi ทีแรกก็จะทำ Sync กับ Dropbox แต่รู้สึกไม่สุด ยุคนี้เน็ตบ้านที่น่าจะ Serve เรื่องพวกนี้ไหว แล้วเราก็มี Raspberry Pi เหลือๆ อยู่ ก็เลยจับ Raspberry Pi Zero W ที่เคยซื้อมาทำ Open VPN Server ไว้ Remote เข้ามาดูกล้องวงจรปิด มาลง nginx + php-fpm แล้วก็ออกแบบเขียนโปรแกรมโหลดไฟล์ Manga ที่ต้องการมาวางอย่างเป็นระเบียบ การเอา MySQL ไปลง Raspberry Pi คงจะหนักไป จึงอาศัยระบบ File System กับ Logic เอาเนี่ยแหละ เขียน JSON ใช้เป็น Index เอาแทน Database แล้วก็ทำเป็นเว็บอ่านหนังสือการ์ตูนส่วนตัวขึ้นมาในท้ายที่สุด แต่งเติมด้วยระบบ Notification ที่จะแจ้งเตือนทันทีหลังพบ Manga ตอนใหม่โพสจากเว็บต้นทาง ส่งมาพร้อมลิงค์กดเข้าไปอ่านได้ทันที! (หยุดหายใจแปบ)

สำหรับใครอยากเห็นหน้าตา Source Code ก็ตามกันไปดูได้เลยที่ https://github.com/spicydog/personal-manga-reader จะเอาไปโม จะเอาไปทำอะไรก็ตามสบาย แต่ Code เขียนชุ่ยมาก ขอออกตัวเอาไว้ก่อน

ทำไมต้องมาทำท่ายากด้วย

ปัญหามันเกิดจาก ยุคนี้ IPv4 ไม่พอ เน็ตบ้านก็เลยไม่ให้ Public IP แท้กับเรา โดนสั่งให้วิ่งผ่าน NAT อีกทีแทน ซึ่งทำให้ไม่สามารถเลือก Port ที่เป็นมาตรฐาน ทำให้ไม่สามารถทำ URL เว็บสวยๆ ได้ จึงเป็นเหตุให้เกิดความจะต้องเอาชนะให้ได้ขึ้นมา ก่อนหน้านี้ผมก็เอา host ตัวเองมาตั้ง nginx เป็น Reverse Proxy วึ่งก็ใช้งานได้ดีแหละ

แต่ยุคนี้ เราไม่ตั้ง VM กันแล้วป่ะ เขาต้อง Serverless กันแล้วจร้า (ไม่ใช่อะไร คืออยากจะลด Config บนเครื่อง VM เพื่อลดปัญหาต่างๆ ด้วย) ก็เลยเริ่มมองหาเครื่องมือที่เป็นไปได้ ทีแรกก็วิ่งไป Cloud Run จับ nginx ขึ้นไปรันบนนั้นแทน แล้วก็ Map Domain เรียบร้อย ซึ่งใช้ได้ Perfect มาก มันคือสมบูรณ์แบบตามที่ต้องการ ทั้งเร็วทั้งเล็ก ทั้งความเร็ว คือนี่ตอบโจทย์เลยแหละความจริงแล้ว แต่คือรู้สึกมันง่ายไป ไม่ท้าทาย แล้วก็อยากจะใช้ Cloudflare Workers อยู่แล้ว เพราะไม่เคยใช้มาก่อน ก็เลยขอจัดสักหน่อยละกัน

Cloudflare Workers มันใช้ NodeJS เราก็เขียน fetch ทำ stream จากเน็ตบ้านวิ่งเข้า Worker แล้วส่งไปให้ Client ไอ้ตอนเขียนก็ทำได้หรอก เพราะมัน Simulate การรันจากบน Web Browser ของเรา แต่เอาเข้าจริงตอน Deploy มันใช้ไม่ได้ เพราะ Cloudflare ไม่อนุญาตให้วิ่งไปหา Port ที่เน็ตบ้านมันเปิดให้ไง ไอ้เราก็งงอยู่นานว่าทำไมมันไม่ได้ จนสุดท้ายไปเจอโพส https://blog.cloudflare.com/cloudflare-now-supporting-more-ports/ ถึงได้ถึงอ้างอ้อ มันเปิดให้เฉพาะแค่บาง Port ซึ่งไม่มีเลขของเราอยู่ในลิสนั่นเอง

แล้วทีนี้จะทำยังไงล่ะ ก็ต้องไปหา Reverse Proxy ตัวอื่นซิครับ Cloud Run เราตัดออกไปแล้ว ง่ายเกินไป ที่ยังเหลือในหัวก็ Heroku ซึ่งมันก็ใช้ได้ง่ายเลย แต่ปัญหาคือ Heroku ใจร้ายไม่ยอมทำ HTTPS กับ Custom Domain ให้ แต่เอาวะ อย่างน้อยก็ยิงกลับมาที่ Port 80 ให้ ทีนี้ Cloureflare Worker ก็เลยได้กลับมาฉายแวว เพราะมันทำ HTTPS กับ Custom Domain ได้ จึงเป็นเหตุให้เกิดการวาง Reverse Proxy 2 ชั้น เพื่อจะเอา HTTPS กับ Domain Name สวยๆ 😀

Reverse Proxy คืออะไร?

ก่อนเราจะไปกันไกล ขอเล่าเรื่อง Reverse Proxy กันก่อน Reverse Proxy ถ้าจะเล่าแบบสั้นๆ มันคือเครื่องที่เอาไว้ส่งต่อข้อมูลนั่นเอง ดังนั้นผู้ที่ส่งข้อมูลไปหาปลายทางจริงๆ ก็จะคือเจ้า Reverse Proxy แทนที่จะเป็นเครื่องต้นทาง

ตัวอย่างที่เห็นชัดที่สุดก็คือ Hacker อยากจะแฮคธนาคาร แล้วทำยังไงจึงจะโบ้ยความผิดให้คนอื่นได้ ก็ทำได้โดยการไปแฮคเครื่องชาวบ้านเสียก่อน แล้วก็ทำการแฮคธนาคารผ่านทางเครื่องของเหยื่อนั่นเอง เวลาเขาตามตัวกลับมา เหยื่อก็จะงงๆ ว่าเกิดอะไรขึ้น เค้าไม่รู้เรื่องด้วยนะ แต่โดนจับไปสอบสอน เคสแบบนี้มาเกิดขึ้นมาแล้ว แต่เวลาเขาทำกันจริงๆ ก็จะ Chain กันยาวไปหลายชั้น แล้วก็จะแบ่งการยิงปลายทางหลายๆ เครื่องด้วย แบบนี้ก็จะทำให้ตามตัวกันไม่ได้เลยทีเดียว

มาฝั่งธรรมะบ้าง ประโยชน์ของ Reverse Proxy นั้นมีอยู่มาก บางครั้งเราเอามาใช้กั้นข้างหน้าป้องกันการโจมตีโดยตรงไปยัง Server ทำให้ปลอดภัยมากขึ้นจากการโจมตี หรือสร้างเป็นตัวลดโหลดจากเครื่อง Server ต้นทาง อย่างที่พวก CDN เอามาใช้กัน

และอีกประโยชน์ที่เอามาใช้ในงานนี้ก็คือ การทำ Routing ใหม่ เปลี่ยน URL เปลี่ยน Path ให้เป็นอย่างที่ต้องการ ล้วนสามารถจัดการได้ผ่านทาง Reverse Proxy ทั้งสิ้น

ถ้าจะให้อธิบายในเชิงการเขียนโปรแกรมแล้ว มันก็คือการเขียนว่ารับ Request มายังไง ก็ให้ไปดึงข้อมูลจากอีกที่มาส่งให้ User กลับไปตรงๆ เลย แค่นั้นแหละ

Heroku คืออะไร

Heroku เป็นบริการ PaaS (Platform as a Service) หรือให้บริการให้เราเอา Code ไปวางและรันได้ โดยไม่จำเป็นต้องมาตั้งค่า Server เอง พูดง่ายๆ คือถ้าเขียนโปรแกรมเป็นก็เอาโปรแกรมขึ้นไปรันได้เลย เราเอา Code ไป Deploy ก็พอ ส่วนเครื่องจะล่ม เครื่องจะโดนโจมตี เรื่องของเขา เขาจัดการให้หมด ถ้าใช้งานฟรี เครื่องจะปิดเองถ้าไม่มีการใช้งานเกิน 30 นาที เวลามี Request เข้าไปมันก็จะเปิดใหม่ขึ้นมาให้เอง ก็จะช้าๆ หน่อยในครั้งแรกที่มันเพิ่งเปิด ขึ้นอยู่กับว่าโปรแกรมใหญ่ขนาดไหน แต่หลังจากเครื่องรันอยู่ก็จะพร้อมตอบสนองในทันที

Cloudflare คืออะไร

Cloudflare โดยโครงสร้างแล้วมันเป็นบริการ CDN (Content Delivery Network) ประมาณว่าเขามีการวาง Edge Server (Server ที่ปลายทาง) กระจายอยู่ทั่วโลกตามหัวเมืองต่างๆ เวลา User เปิดใช้งาน มันจะวิ่งผ่าน Edge Server เหล่านั้นก่อน เช็คดูว่ามีไฟล์ที่ User ร้องขอมาไหม ถ้าไม่มีมันก็จะต่อมาหา Origin Server ของเรา พอมันได้ไฟล์มาแล้วมันก็จะส่งให้ User พร้อมกับ Cache เอาไว้บน Edge Server เลย ทีนี้พอ User มาเปิดไฟล์เดิมอีกครั้ง ซึ่งอาจจะเป็นคนละคนก็ได้ มันก็จะไม่ต้องติดต่อมาหาเราอีก ช่วยลดโหลดจาก Origin Server แล้วก็ช่วยให้ User ได้ไฟล์ไปเร็วขึ้นด้วย เพราะ Edge Server มีกระจายอยู่ทั่วโลก และมักจะอยู่ใกล้ User มากกว่า Origin Server

ความเด็ดคือ Cloudflare ให้ใช้งานได้ฟรี คือยิ่งมีคนใช้มาก มันยิ่งทำให้เขาประเมินบริมาณ Traffic ได้แม่นขึ้น กลายเป็นช่วยลดต้นทุนความเสี่ยงไป แล้วก็สามารถเอามาใช้เป็น DNS Server ได้ด้วย UI หน้าตาดี ผมเอา Domains ผมทั้งหมดไปไว้ที่นี่หมดเลย DNS ไม่เคยล่ม บริการนี้ผมเชียร์สุดใจ รักมาก

Cloudflare Workers คืออะไร

Cloudflare Workers คือบริการ Computing Server ที่เพิ่งเปิดใหม่จาก Cloudflare ลองจินตนาการให้ Cloudflare มีเครื่อง Edge Server กระจายเต็มไปหมดทั่วโลก ถ้าเราเอาโปรแกรมไปวางบนเครื่องพวกนั้นได้จะ Powerful ขนาดไหน ดังนั้นนี่คือการเปิดให้เราเอาโปรแกรมเล็กๆ ของเราขึ้นไปรันบนเครื่องเหล่านั้น มันเจ๋งคือโปรแกรมของเราจะถูก Deploy บนเครื่องจำนวนมากทั่วโลกโดยอัตโนมัติ ดังนั้นไม่ต้องกลัวโหลดไม่ไหวเพราะ Server ไม่พอ

Cloudflare Worker ให้บริการฟรี 100,000 Requests/Day ซึ่งก็น่าจะเพียงพอสำหรับงาน Scale เล็กๆ

โครงสร้างการทำ Routing ของ Reverse Proxies

ขั้นตอนในการปฏิบัติการ

ขั้นแรกก็แน่นอน เราต้องตั้ง Raspberry PI Server แล้วก็ทำการเปิด Port ออกมาข้างนอก ทำ DDNS NAT ที่ทาง ISP ให้มา ซึ่งตอนนี้ผมได้ Domain Name และ Port ที่สามารถเข้าได้ดังนี้ http://spicydog.thddns.net:1113 อันนี้ก็คือเปิดตรงๆ เข้าไปที่ Raspberry Pi เลย

ใครอย่าแกล้ง Stress Test นะ เดี๋ยวมันจะล่มเอาได้ โปรดเห็นใจ SD Card กับอุปกรณ์ CPU ช้าเต่ากันหน่อย


หลังจากได้ Origin Server แล้ว ต่อมาจากนั้นก็ทำ Request Proxy บน Heroku ผมหาอยู่สักพักนึงก็เจอมีคนเขียนเอาไว้แล้ว แค่กดปุ่มก็ Deploy ไปติดตั้งบน Heroku ได้เลย https://elements.heroku.com/buttons/cwarden/heroku-reverse-proxy

เราตั้งค่า UPSTREAM_SERVER ให้เป็น Origin Sever ที่ต้องการได้ทันที

เรียบร้อยแล้วก็ลองเปิดดูซิว่า Heroku มันใช้ได้ ผ่านทาง URL ที่ Heroku ให้มา https://spicydog-manga.herokuapp.com ซึ่งเวลา Request ผ่านทางนี้ ก็จะต้องไปอ้อมโลกที่ USA ก่อน แล้วค่อย Route กลับมาหาเร้าเตอร์ที่บ้านในไทย 555


หลังจากได้ Port 443 สมความตั้งใจ เราก็สามารถเอามาใช้กับ Cloudflare Workers ได้แล้ว ก็เริ่มจากการเข้าไปสร้าง Worker ใหม่ ซึ่งผมตั้งชื่อว่า https://manga-reader.spicydog.workers.dev

ต่อมาก็จะเห็นหน้า Editor ตามภาพ ซึ่งอันนี้แหละคือตัวเอาไว้เขียน Serverless Function ของ Cloudflare มันจะ Simulate การทำงานผ่านทาง Web Browser ของเราเลย ผมมองว่าฟีเจอร์นี้เด็ดมาก ไม่ต้องรอ Deploy แล้วถึงจะเห็นผล ขอยกความดีความชอบให้ NodeJS

ต่อมาเราก็เอา Script สำหรับทำ Reverse Proxy บน Cloudflare ไปใส่ ซึ่งมันมาสิ่งที่เรียกว่า fetchAndStream มาให้ดูเป็นตัวอย่าง แต่ผมต้องเอามาโมเพิ่มนิดหน่อย แล้วก็ลองใช้งานดูบนตัว Editor ก็พบว่าใช้งานได้เลย

หลังจากนั้นก็ Deploy แล้วก็ลองเข้าผ่านทาง Worker ของ Cloudflare ดู ซึ่งก็พบว่าใช้งานได้ วิ่งทะลุไปหา Heroku เรียบร้อย

ต่อมาเป็นการเพิ่ม Routing ให้ได้ https://manga.spicydog.org อย่างที่เราต้องการ ที่หน้า Worker ข้างใน Config ของ Cloudflare มันจะมีให้ Map Route กับ Worker ได้ เราก็ทำการใส่ Subdomain ลงไป แล้วก็ให้ใส่ /* ด้วยนะ มันจะได้ส่งต่อ Parameters เข้าไปใน Worker ด้วย แล้วก็เลือก Worker ที่เราต้องการ

เรียบร้อยแล้วก็จะได้หน้าตาประมาณนี้

อ่อ แล้วก็อย่าลืมไปเซทก้อนเมฆสีส้มใน DNS ด้วยล่ะ Traffic จะได้วิ่งผ่าน Cloudflare แล้วก็ติด Rule ของ Worker


ลองเปิด https://manga.spicydog.org ดู เข้าได้แล้ว! Traffic วิ่งผ่าน Cloudflare ด้วย ดังนั้นมันจะติด Cache ที่ Edge Server ด้วย ช่วยให้ไม่ต้องวิ่งมาโหลดรูปออกไปจากเร้าเตอร์อินเทอร์เน็ตบ้านช้าๆ ชน Edge Server แล้วก็เอารูป Manga ไปดูได้เลย ยกเว้นตัว HTML Document ที่โหลดจาก PHP อันนี้ยังไง Raspberry Pi ก็ต้องเป็นคน Generate ให้

เช็ค SSL ดูก็ได้ HTTPS จากทาง Cloudflare มาใช้งาน มาเปิดดูก็มั่นใจได้ว่า ไม่มีคนรู้ว่าเรากำลังเปิดเว็บอ่านการ์ตูนอยู่


อันนี้หน้าตาของ Server เก็บ Manga ที่เปิดให้บริการ เสียบใช้ไฟ USB จากเร้าเตอร์ได้เลย ประหยัดไฟมาก 😀

คร่าวๆ สำหรับการทดลองของเล่น Cloudflare Worker ของผมก็ประมาณนี้ล่ะครับ ถ้าไม่ต้องวิ่งเข้า Heroku คงจะไวกว่านี้มากๆ เพราะตอนนี้กว่าจะโหลดแต่ละหน้า แต่ละไฟล์ได้ ต้องไปอ้อมโลกก่อนถึงจะได้ข้อมูล หา Solution กันต่อไป ความจริงถ้ายอมจำนนให้ Google Cloud Run ก็จบแล้วก็ตั้งไว้ที่ Asia ใกล้ๆ กับเราได้แล้วตอนนี้

สำหรับท่านผู้อ่านที่มีข้อสงสัยก็สามารถ Comment พูดคุยกันได้ครับ ส่วนตอนนี้ก็ขอจากกันเพียงเท่านี้ สวัสดีครับ