Redirect เว็บไซต์สำหรับมือถือด้วย Apache mod_rewrite

ทุกวันนี้หลายเว็บคงจะมีเว็บสำหรับ Mobile เพื่อรองรับการเข้าชมของอุปกรณ์ประเภท Smart Phone และ Tablet ซึ่งหากท่านใช้ CMS ที่สามารถแปลงเว็บไซต์จากหน้าเว็บแบบเข้าชมจากเครื่อง PC ไปเป็น Mobile ได้ก็คงไม่เป็นปัญหาอะไรมากนัก แต่ถ้าไม่มีก็คงต้องหาวิธีเขียนโปรแกรมเพื่อตรวจสอบเว็บเบราเซอร์กันเอาเอง วันนี้ผมมีวิธีง่ายๆ ในการ Redirect เว็บไซต์ ให้ถูกต้องตามอุปกรณ์ที่เรียกใช้กันครับ วิธีง่ายๆ ที่ว่าก็คือการใช้ mod_rewrite นี่แหละครับ

มาทำความเข้าใจกันก่อน สมมุติว่าคุณมีเว็บไซต์ที่ให้บริการผู้เข้าชม 2 แบบ คือแบบปกติเข้าชมผ่านเครื่องคอมพิวเตอร์ และแบบ Mobile เข้าชมผ่าน Smart Phone/Tablet มีโดเมนดังต่อไปนี้

  • เว็บปกติ http://www.my-example.com
  • เว็บสำหรับ Mobile http://m.my-example.com

หากผู้เข้าชมเปิดด้วยเครื่องคอมพิวเตอร์ปกติให้ Apache redirect ไปยังเว็บปกติ หากเป็น Smart Phone ก็ redirect ไปยังหน้าเว็บสำหรับ Mobile เงือนไขมีประมาณนี้ครับ มาลงมือกันเลย

เริ่มจากหน้าเว็บปกติคือ www.my-example.com ให้เพิ่ม .htaccess ใน document root ของ virtual host นี้เพื่อสั่ง redirect หากเข้าชมผ่าน Mobile ให้ redirect ไปที่ m.my-example.com เขียน rewrite rules ได้ดังนี้

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|googlebot-mobile|iemobile|ipad|iphone|ipod|opera mobile|palmos|webos" [NC]
RewriteRule ^$ http://m.my-example.com/ [L,R=302]
</IfModule>

ในหน้าเว็บ Mobile คือ m.my-example.com ให้เพิ่ม .htaccess ใน document root ของ virtual host นี้เพื่อสั่ง redirect หากเข้าชมผ่านคอมพิวเตอร์ ให้ redirect ไปที่ www.my-example.com เขียน rewrite rules ได้ดังนี้

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "!(android|blackberry|googlebot-mobile|iemobile|ipad|iphone|ipod|opera mobile|palmos|webos)" [NC]
RewriteRule ^$ http://www.my-example.com/ [L,R=302]
</IfModule>

เท่านี้ก็เรียบร้อยแล้ว :)

แก้ปัญหา DOS บน Apache

ปัญหา DOS และ Brute Force Attack เป็นปัญหาที่หลายๆ คนอาจได้พบบ้าง แต่ถ้า DDOS ก็ตัวใครตัวมันครับ :P ปัญหาเหล่านี้เป็นปัญหายอดนิยม โดยเฉพาะเครื่องที่โดน Attack มักจะมีของสำคัญๆ อยู่ในนั้น เช่น รูปภาพ, ไฟล์ข้อมูล หรือ ตกเป็นเป้าเพื่อใช้ยืมเครื่องไปยิงเครื่องอื่นๆ ต่อ ซึ่งวิธีการที่ยอดฮิดมากคือการยิงผ่านช่องโหว่ของ Web Application ที่เราใช้ๆ กันอยู่อย่างเช่น CMS, โปรแกรมจัดการฐานข้อมูล เป็นต้น หากวัตถุประสงค์เพื่อก่อกวนให้ Apache ทำงานไม่ได้ หรือเครื่องเซิร์ฟเวอร์ทำงานไม่ได้ มักจะโดน DOS หรือ DDOS แต่เราสามารถป้องกันเหตุการณ์เหล่านี้ได้ โดยใช้ fail2ban ครับ

มาวิเคราะห์สถานการณ์กันก่อน คำถามที่ต้องถามตัวเองคือ เราจะทราบได้อย่างไรว่าเครื่องไหน IP อะไรเข้าข่าย attack เราบ่อยครั้ง ? คำตอบง่ายๆ ก็ดู log หน้าเว็บที่ถูกเรียก และปริมาณของ package ที่ส่งเข้ามา ยกตัวอย่างเช่น เว็บ ABC โดน DOS โดยมีเครื่องคอมพิวเตอร์ไม่ซ้ำ IP เปิดเว็บหน้าหนึ่งซึ่งพยายามจะดาวน์โหลดไฟล์ xxx.exe ที่ไม่มีอยู่ในเครื่องเซิร์ฟเวอร์ของ ABC เลย ถ้าอย่างนี้เรียกโดน 2 เด้ง แสดงว่าเซิร์ฟเวอร์(เคย)มี trojan ฝังอยู่ และเครื่องที่ติด trojan หรือ virus ก็พยายามขยายตัวเองออกไปยังเครื่องอื่นๆ อย่างนี้เว็บ ABC ก็จะมี traffic จำนวนมหาศาลดาวน์โหลดไฟล์ xxx.exe นี้ หากเรามาพิจารณา log ไฟล์ จะพบ Error 404 ที่เรียกไฟล์ xxx.exe ดังนี้

...
220.191.231.206 - - [05/Mar/2007:11:50:20 +0100] "GET http://www.abc.com/xxx.exe HTTP/1.0" 404 534 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"
...

หาดูที่ log จะพบว่า เครื่องที่เรียกไฟล์ xxx.exe นี้มาจาก IP Address 220.191.231.206 หากมีการ attack นิดเดียว เราสามารถใช้ iptables มา band IP Address นี้ได้ แต่ถ้ามีมากจนนับไม่ได้นี่ก็ต้องใช้เครื่องมือช่วยครับ นั่นคือ fail2ban นั่นเอง ในส่วน config ไฟล์ชื่อ jail.conf เราสามารถใช้ regular expression ในการจัดการ filter ข้อมูลใน log ไฟล์ที่เราต้องการได้ ในที่นี้คือ IP ของเครื่องปลายทางที่เรียกไฟล์ xxx.exe นั่นเอง เราก็จะสามารถเพิ่ม config ให้ fail2ban ได้ดังนี้

[apache-trojan-xxx]

enabled = true
filter = ^<HOST> - .*GET.*/xxx\.exe
logpath = /var/log/apache/access.log
maxretry = 6

แค่นี้เราก็ได้วิธีการ band เครื่องที่เป็นปัญหาแล้ว :) ลองเอาไปประยุกต์ใช้กันดูนะครับ

จำกัดจำนวนการเชื่อมต่อให้ Apache ด้วย mod_limitipconn

หลายท่านที่ใช้บริการดาวน์โหลดไฟล์ในโครงการ Suriyan, Chantra, ThaiOS และเอกสารใน pub.thaiopensource.org อาจสงสัยว่าทำไมดาวน์โหลดไฟล์ยากจัง? และดาวน์โหลดได้เพียงไม่กี่กิโลไบต์ สาเหตุมาจากการใช้งานที่ท่วมท้นของสมาชิกทำให้เน็ตเวิร์คภายใน SIPA เดี๊ยง ถึงเดี๊ยงที่สุด :P และทีมงาน Thai Open Source ก็โดนดุตามระเบียบ ก็เลยทำให้มีการแจ้งย้ายแหล่งดาวน์โหลดทั้งหมดไปไว้ที่ pub.thaiopensource.org และทำการ shape bandwidth ด้วย mod_cband เพื่อให้ Apache คุม bandwidth ของเว็บที่ให้ดาวน์โหลดไว้ ให้วิ่งไม่กี่กิโลไบต์ ทำให้ลดเรื่องการใช้ bandwidth เกินกำลัง แต่ปัญหาที่ตามมาคือ ไฟล์ iso ขนาด 1.5GB ใช้เวลาดาวน์โหลดประมาณ 9 วัน T_T ใช่ครับ 9 วัน ไร้สาระมากๆ และระยะเวลายิ่งนานผู้ใช้ก็ยิ่งซอยชิ้นของไฟล์ให้มากขึ้น และคิดว่ามันจะช่วยให้ดาวน์โหลดเร็วขึ้นซึ่งนั่นคิดผิดครับ :P ผมก็เลยตัดสินใจ กดเครื่องคิดเลขและเปลี่ยนมาจำกัดจำนวนการเชื่อมต่อของแต่ละ IP ให้ Apache แทน ซึ่งมีวิธีการดังนี้

เครื่องมือที่เรานำมาใช้จำกัดจำนวนการเชื่อมต่อของแต่ละ IP ชื่อ mod_limitipconn ซึ่งเจ้าตัวนี้สามารถกำหนดไดเรคทอรี และชนิดของไฟล์ที่เราต้องการจำกัดจำนวนการเชื่อมต่อได้ ยกตัวอย่างเช่น เว็บไซต์ http://pub.thaiopensource.org/suriyan-archive ในไดเรคทอรี suriyan-archive ทั้งหมดผมต้องการจำกัดการเชื่อมต่อเพื่อดาวน์โหลดไฟล์ iso ที่อยู่ในนั้น เราก็สามารถทำได้ มาดูของจริงกันครับ Continue reading

จัดการ Load Balance ให้กับ Apache ด้วย Pound

เมื่อคราวที่แล้วเขียนเรื่อง Load Balance ให้ Apache Web Serverv ง่ายๆ โดยใช้ DNS Round Robin ซึ่งสามารถทำ Load Balance ได้ง่ายๆ แต่มีปัญหาที่มีโอกาสเกิดขึ้นได้ คือ เมื่อ Web Server ตัวใดตัวหนึ่งมีปัญหา ผู้เข้าเว็บที่โชคดีได้ IP Address เครื่องนั้นไปก็จะไม่สามารถเข้าถึงเว็บได้ DNS Round Robin ช่วยเรื่อง Load Balance ได้จริง แต่จัดการเรื่อง fail over ไม่ได้ :) ครั้งนี้จะมาแนะนำการทำ Load Balance ง่ายๆ อีกเช่นเคย โดยใช้ Pound

Pound ทำหน้าที่

  • reverse proxy : ส่ง request จากเว็บเบราเซอร์ไปยัง back-end server ที่มีอยู่
  • load balancer : ส่ง request จากเว็บเบราเซอร์ไปยัง back-end server ที่มีอยู่และจัดการข้อมูล session ด้วย
  • SSL Wrapper : ถอดรหัส HTTPS จากเว็บเบราเซอร์และส่งไปยัง back-end server ที่มีอยู่
  • กลั่นกรอง HTTP/HTTPS : ตรวจสอบ request เพื่อความถูกต้องและรับ reuest ที่มีรูปแบบถูกต้องเท่านั้น
  • fail over-server : หากมี back-end server ตาย Pound จะจำเครื่อง server นั้นและหยุดส่ง request จนกว่าจะมีการแก้ไข
  • request redirector : request จาก Pound สามารถกระจายไปยัง back-end server ทั้งหมดได้ขึ้นอยู่กับ request URL

Continue reading

จัดการ Download Speed และ Traffic ของ Apache ด้วย mod_cband

มีปัญหาเรื่อง Apache มาพอสมควรเนื่องจากมีเว็บหนึ่งใน Virtual Host มี traffic เยอะมากจนทำให้เว็บอื่นๆ ที่เป็น Virtual Host เหมือนกันเข้าไม่ได้ ได้ลองพยายามปรับแต่งทั้งโปรแกรมและส่วนอื่นๆ เช่น PHP, MySQL, CMS จนหมดแล้ว สุดท้ายต้องหาวิธีจัดการ bandwidth ของ Apache ให้ได้ ผมมีวิธีการง่ายๆ มานำเสนอ ใช้ mod_cband ครับ :)

mod_cband มักถูกใช้ใน hosting เนื่องจากผู้ให้บริการต้องการจำกัด bandwidth ของเว็บนั้นๆ ต่อเดือน และจำกัดความเร็วในการโหลดหน้าเว็บนั้นๆ เพื่อรักษา bandwidth โดยรวมเพื่อให้เว็บอื่นๆ เข้าใช้งานได้ปกติ ซึ่งการจำกัด bandwidth ลักษณะนี้ได้ผลดีมากเพราะสามารถกำหนดได้เป็นรายเว็บไซต์ เพื่อสร้างเงื่อนไขทางด้านราคาและการทำการตลาด น่าจะพอเห็นภาพกันบ้างแล้วทีนี้เรามาจัดการ Apache กัน อ้อเกือบลืมผมอ้างอิงกับ Ubuntu 10.04 LTS ครับ
Continue reading

สร้างระบบให้บริการพื้นที่เว็บไซต์เล็กๆ กันเถอะ

เคยมีคนถามเรื่องจะทำระบบให้บริการพื้นที่เว็บไซต์เล็กๆ โดยเก็บข้อมูลผู้ใช้ลงในฐานข้อมูล MySQL การอัพเดทโหลดให้ใช้ผ่าน FTP เท่านั้น ก้อเป็นแนวคิดดีๆ ซึ่งอาจจะเอามาประยุกต์ใช้ในโรงเรียนหรือวิทยาลัยที่บริการพื้นที่เว็บไซต์ ให้นักเรียนได้สร้างบล็อกหรือเว็บส่วนตัวกันได้ การที่เราจะไปทำแบบ Hosting ขนาดใหญ่โต มีเครื่องแรงๆ ก้อคงจะเกินงบประมาณไปสักหน่อย เอาเครื่อง PC เล็กๆ ที่มี Harddisk ขนาดเหมาะสม และ Main Memory สัก 512MB-1GB กำลังดีครับ (ยุคประหยัด)

งานเขียนครั้งนี้จะมาอธิบายวิธีการสร้าง ระบบให้บริการพื้นที่เว็บไซต์ โดยใช้ PureFTPd และ MySQL กันทำไมถึงเลือก PureFTPd สาเหตุที่เลือก PureFTPd ก้อเพราะว่าเป็นโปแกรม FTP Server ที่สามารถเก็บข้อมูลผู้ใช้ลงในฐานข้อมูล MySQL หรือ Directory Service อย่าง LDAP ได้ นอกจากนี้ยังสามารถทำ Bandwidth Control ได้ด้วย อ้อและที่สำคัญเวลาย้ายเครื่อง,ย้ายข้อมูลเว็บ,ข้อมูลผู้ใช้ และการตั้งค่าต่างๆ ก้อไม่ยุ่งยากและวุ่นวายอีกต่อไป เอาล่ะลองมาดูวิธีการกันครับ

Continue reading

Rewrite URL ด้วย Apache mod_rewrite

คุณ Zee ส่งอีเมล์มาจากระบบติดต่อของ gotoknow.org มาถามเรื่อง DNS Wildcard จำได้ว่าเคยเขียนเรื่องนี้ใน ThaiOpenSource.Org มาแล้วแต่พอเข้าไปดู how-to ที่เคยเขียนเป็นกรณีที่เราสามารถแก้ไข DNS Record เองได้ในกรณีของคุณ Zee เช่าบริการโฮสติ้งแต่ทางผู้ให้บริการให้เพิ่ม subdomain ได้เพียง 1 ชื่อเท่านั้นดังนั้นการทำ DNS Wildcard จึงทำไม่ได้ คุณ Zee เลยเขียนจดหมายมาถามในทางกลับกันคือ ไม่ใช้ subdomain แต่อยากให้แบ่งคล้ายๆ กับ DNS Wildcard ได้มั๊ย

ผมมาพิจารณาดูจากกรณีของคุณ Zee เข้าใจว่าพยายามทำ Pritty URL ของเว็บไซต์ หรือ SEO ง่ายๆ จาก URL โดยคุณ Zee จะให้ชื่อ URL เป็น http://domain.com/yourname บอเบราส์ไปแล้วก็ไปเปิดหน้าของ yourname ซึ่งไม่มีไดเรคทอรี yourname อยู่จริงๆ ในเซิร์ฟเวอร์ เอ้าเอาเป็นว่าน่าจะพอเข้าใจปัญหาคร่าวๆ กันแล้ว หาใครเคยทำ Pritty URL หรือคุ้ยเคยกับ SEO มาบ้างก็จะบอกว่า Rewrite URL ใช่มั๊ยครับ

How-To วันนี้ก็จะเป็นเรื่อง Rewrite URL ให้สนับสนุนกับโค้ดของโปรแกรมที่พัฒนาครับ โดยปกติการเขียนโค้ดของโปรแกรมในแบบ dynamic เรามักเห็นตัวแปรยุบยับผ่านทาง URL เช่น http://domain.com/index.php?name=yourname เป็นต้น เรามาทำให้มันสวยอย่างนี้ http://domain.com/yourname ได้ ด้วยการ Rewrite URL ครับ แล้วจะทำอย่างไร? วิธีการง่ายๆ เราสามารถเขียนกฏการแปลง URL ผ่านทาง htaccess ได้ครับ เขียนอย่างนี้ครับ

# Don't show directory listings for URLs which map to a directory.
Options -Indexes

# Follow symbolic links in this directory.
Options +FollowSymLinks

# Customized error messages.
ErrorDocument 404 /index.php

# Set the default handler.
DirectoryIndex index.php

RewriteEngine on
#RewriteBase /mydir
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?name=$1 [L,QSA]

หลัง จากนั้นให้เขียน index.php ขึ้นมาไฟล์นึงแล้วตรวจสอบ ค่า $_GET[‘name’] ว่าเป็นค่าอะไร เช่น สมมุติ http://domain.com/anoochit ค่า $_GET[‘name’] ที่ได้คือ anoochit ใน Request URI จะเป็น index.php?name=/anoochit ให้อัตโนมัติ ง่ายๆ แค่นี้เองครับ

ประยุกต์ Wildcard DNS กับ Apache

คราวที่แล้วเขียนเรื่อง Wildcard DNS record ไป เพื่อบอกให้ Bind รู้ว่าอะไรที่เกี่ยวข้องหรือตรงกับเงื่อนไขให้อ้างอิง domain นั้นโดยตรง สำหรับ How-To ครั้งนี้จะมาเล่าวิธีกการประยุกต์ใช้? Wildcard DNS และการตั้งค่า VirtualHost เพื่อรองรับการเรียกผ่าน subdomain ใดๆ ใครจำเรื่อง DNS Wildcard ไม่ได้ลองมาพิจารณาดู record ดังนี้

example.com.        A    10.11.12.13
*.example.com.    CNAME    example.com.

หาก เรา dig xyz.example.com เราจะพบว่า DNS จะบอกว่า IP เป็น 10.11.12.13 คือ CNAME ของ example.com นั่นเอง คราวนี้หากเราจะเพิ่ม VirtualHost ให้ Apache จะทำได้อย่างไร และต้องการให้ซัพพอร์ทในทุกๆ subdomain มาลองดูวิธีกันนะครับอันดับแรก เริ่มจากการตั้งค่า DNS กันก่อน ในโซนไฟล์ให้เพิ่ม wildcard สำหรับ domain ดังนี้

*.example.com.    IN      A       192.168.1.1

ผม ยกตัวอย่าง domain ที่ชื่อ example.com นะครับ เมื่อกำหนด wildcard ให้กับ DNS แล้วนั่นหมายความว่า subdomain ใดๆ ที่อยู่ภายใต้โดเมน example จะถูกกำหนดเป็น IP 192.168.1.1 ทั้งหมด มาตั้งค่า VirtualHost ให้กับ Apache กันต่อครับ ในไฟล์ VirtualHost ให้เพิ่ม ServerAliase เป็น *.example ดังตัวอย่าง

<VirtualHost *>
ServerName  www.example.com
ServerAlias *.example.com

DirectoryIndex index.html
DocumentRoot /home/www/www.example.com/htdocs

....
</VirtualHost>

จาก ตัวอย่างข้างต้น subdomain ใดๆ ที่อยู่ภายใต้โดเมน example จะมี DocumentRoot อยู่ที่ /home/www/www.example.com/htdocs ตัวอย่างเช่น หากเราเปิด xxx.example.com ก้อจะเปิดไฟล์ index ที่อยู่ในไดเรคทอรี /home/www/www.example.com/htdocs หากต้องการแยก subdomain อยู่คนละ directory สามารถกำหนดเพิ่มได้ในส่วน VirtualHost เรื่อยๆ หากต้องการตั้งค่า VirtualHost เพียงครั้งเดียวเราสามารถใช้ mod_rewrite เพื่อสร้าง redirect ไปยังไดเรคทอรีใดๆ ที่อยู่ใน DocumentRoot ได้ ตัวอย่างเช่น

webmail.example.com??? ชี้ไปที่ http://www.example.com/webmail
scm.example.com??? ชี้ไปที่ http://www.example.com/scm
dm.example.com??? ชี้ไปที่ http://www.example.com/dm
download.example.com??? ชี้ไปที่ http://www.example.com/download

การตั้งค่า ใน VirtualHost เพื่อ redirect ในแต่ละ request ให้เพิ่มข้อมูลดังนี้

RewriteEngine on
RewriteCond %{http_host} .
RewriteCond %{http_host} !^www.example.com [NC]
RewriteCond %{http_host} ^([^.]+)\.example.com [NC]
RewriteRule ^(.*) http://www.example.com/%1/ [R=301,L,QSA]

ใน กรณีที่เราเรียกใช้ subdomain ที่ไม่มีไดเรคทอรีรองรับ เช่น dummy.example.com จะต้องมีไดเรคทอรี dummy อยู่ที่ DocumentRoot หากไม่มีจะพบข้อความ Error 404 ซึ่งเป็นค่า default หากต้องการกำหนด Error Page เฉพาะในแต่ละ VirtualHost สามารถเพิ่มไฟล์แสดงผล Error ในแบบต่างๆ ของเราลงไปได้

Alias /error/ "/home/www/www.example.com/htdocs"
ErrorDocument 400 /error/invalidSyntax.html
ErrorDocument 401 /error/authorizationRequired.html
ErrorDocument 403 /error/forbidden.html
ErrorDocument 404 /error/fileNotFound.html
ErrorDocument 405 /error/methodNotAllowed.html
ErrorDocument 500 /error/internalServerError.html
ErrorDocument 503 /error/overloaded.html

เท่านี้คุณก็สามารถตั้งค่า DNS แบบ Wildcard เพื่อเชื่อมต่อกับ Apache VirtualHost ได้แล้ว ลองนำไปประยุกต์ใช้ดูนะครับ