วิธีสร้าง reverse proxy ด้วย Apache2 docker ด้วย subpath ใน Domain Name เดียวกัน

ในการเขียน web application บน docker (ผมชอบใช้ django / flask) เมื่อต้องการ deploy ไว้บนเครื่อง Production Server ซึ่งแต่ละ application ก็จะเปิด port ต่าง ๆ กัน เช่น 8080, 8081, 8082 … ว่ากันไป

เช่น จะมี URL เป็น IP Address แล้วตามด้วย Port อย่างนี้

192.168.x.y:8080
192.168.x.y:8081
192.168.x.y:8082

การสร้าง Reverse Proxy ทำให้ผู้ใช้สามารถ เข้าถึง web application เหล่านี้ได้ง่ายขึ้น โดยใช้วิธีการ เช่น ใช้ Web Server อย่าง Apache, Nginx ทำงานร่วมกับ DNS Server เพื่อจด Domain Name มายัง IP Address เช่น

app1 IN A 192.168.x.y
app2 IN A 192.168.x.y
app3 IN A 192.168.x.y

แล้วที่ Web Server ค่อยมากำหนดว่า เมื่อ ServerName เป็น app1.xxx.psu.ac.th จะส่งไปยัง 192.168.x.y:8080 อะไรทำนองนี้

ปัญหาคือ ถ้าต้องจดทะเบียน DNS ไปเรื่อย ๆ ก็คงไม่ไหว อีกทั้ง เมื่อต้องใช้ HTTPS ก็ต้องไปทำทีละ domain name อีกด้วย

แล้วจะทำอย่างไร ให้สามารถรวบ web application ที่อยู่บน production server ตัวเดียวกันนี้ ให้อยู่ใน domain name เดียวกัน แต่ แยกกันด้วย URL Path ด้านหลังแทน เช่น

xxx.psu.ac.th/app1/
xxx.psu.ac.th/app2/
xxx.psu.ac.th/app3/

และ ในเมื่อเราใช้ Docker บน Production Server อยู่แล้ว ก็ใช้ Web Server เป็น container ซะ

วิธีการทำมีดังนี้

  1. สร้าง apache2 container ให้ชื่อว่า httpd รับการเชื่อมต่อที่ port 80 ด้วยคำสั่ง
docker run -dit --name httpd -p 80:80 httpd:2.4

2. ตอนนี้ เราจะได้ container ชื่อ httpd มาแล้ว ต่อไป copy ไฟล์ httpd.conf ออกมา ด้วยคำสั่ง

docker cp httpd:/usr/local/apache2/conf/httpd.conf .

3. ตอนนี้ เราจะได้ไฟล์ httpd.conf ออกมา ให้แก้ไขไฟล์ด้วย Text Editor ตามถนัด โดยการทำ Reverse Proxy ด้วย apache2 นั้น ต้องเปิดใช้ module ดังนี้ (ค้นหา และ uncomment) แล้ว Save

LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so

4. เพิ่ม Directive “ProxyPass” และ “ProxyPassReverse” ตามด้วย URL Path ที่ต้องการของแต่ละ Application แล้ว URL ที่สร้างไว้ เสร็จแล้ว ก็ Save

ProxyPass "/app1/"  "http://192.168.x.y:8080/"
ProxyPassReverse "/app1/"  "http://192.168.x.y:8080/"
ProxyPass "/app2/"  "http://192.168.x.y:8081/"
ProxyPassReverse "/app2/"  "http://192.168.x.y:8081/"
ProxyPass "/app3/"  "http://192.168.x.y:8082/"                
ProxyPassReverse "/app3/"  "http://192.168.x.y:8082/"          

5. ต่อไป ก็ copy file httpd.conf ที่แก้ไขแล้ว กลับเข้าไปใน container ด้วยคำสั่ง

docker cp httpd.conf httpd:/usr/local/apache2/conf/httpd.conf

6. สุดท้าย restart container ด้วยคำสั่ง

docker restart httpd

ก็ประมาณนี้ เวลาจะเพิ่ม หรือ เปลี่ยนอะไร ก็ ทำซ้ำขั้นตอน 4,5,6 ครับ

หมายเหตุ: ในบาง web application อย่างเช่น Grafana ก็จะต้องไปแก้ไข root_url ให้ใช้ subpath ด้วย ในพวก django, flask ต้อง ALLOWED_HOST อีกเล็กน้อย ครับผม