วิธีติดตั้ง Nginx กับ DirectAdmin

วิธีติดตั้ง nginx แบบนี้เหมาะสำหรับ server ที่มีหลายเว็บไซต์ในเครื่องเดียว เช่น Server ที่ให้บริการ Web Hosting ครับ เนื่องจากจะมีการ กระจาย cache และ config ของ nginx ไปยังทุกๆ user ของ directadmin


ขั้นตอนจะยุ่งยากนิดนึงครับ ถ้าท่านไม่มั่นใจกรุณาแจ้งให้เจ้าหน้าที่ของเราติดตั้งให้นะครับ
สำหรับท่านที่ต้องการติดตั้งเองค่อยๆ ทำตามมีละบรรทัดนะครับใจเย็นๆ พร้อมแล้วเริ่มเลยดีกว่าครับ


ขั้นตอนที่ 1 ก่อนอื่นเข้าไปดูก่อนครับว่า nginx version ล่าสุดเป็น version อะไรที่
http://nginx.org/en/download.html


*สำหรับ NginX Version ใหม่ๆ ฟังก์ชั่นบางตัวที่สาธิตในการติดตั้งครั้งนี้อาจถูกเลิกใช้แล้ว หรือถูกแทนที่ด้วย ฟังก์ชั่นใหม่แล้ว กรุณาอ้างอิง ฟังก์ชั่นใหม่ๆ หรือฟังก์ชั่นที่ยกเลิกไปแล้วกับ nginx.org โดยตรงนะครับ
** แล้วจะรู้ได้อย่างไรว่าฟังก์ชั่นไหนยกเลิกไปแล้ว ก็ลองติดตั้งแล้ว start nginx ดูครับ จะแสดงข้อความว่า start ไม่ได้เพราะอะไร แล้วไล่แก้เอาครับ


ขั้นตอนที่ 2 พบแล้วก็ download ลงมาเลยครับ ยกตัวอย่างว่าผมเจอ เป็น version 1.3.15
wget http://nginx.org/download/nginx-1.3.15.tar.gz


ขั้นตอนที่ 3 แตกไฟล์
tar xzf nginx-1.3.15.tar.gz


ขั้นตอนที่ 4 ทำการติดตั้ง (ทีละบรรทัดนะครับ)
cd nginx-1.3.15
./configure --sbin-path=/usr/local/sbin --with-http_ssl_module
make
make install



ขั้นตอนที่ 5 แก้ไขไฟล์ config

nano -w /usr/local/nginx/conf/nginx.conf

ขั้นตอนที่ 6 ใส่ค่าดังนี้ (ดูดีๆ นะครับ ใน code ชุดนี้มีจุดที่ต้องเปลี่ยน IP ด้วย) และ

user apache apache;
worker_processes 4;
worker_rlimit_nofile 150000;

error_log /var/log/nginx/error_log;

pid /var/run/nginx/nginx.pid;

events {
worker_connections 25000;
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log off

limit_zone one $binary_remote_addr 10m;
limit_conn one 7;
limit_rate 512K;
limit_zone cglob $binary_remote_addr 16m;

client_header_timeout 60;
client_body_timeout 60;
send_timeout 120;
proxy_read_timeout 60;
proxy_connect_timeout 60;
proxy_send_timeout 180;

msie_padding on;

proxy_buffer_size 32K;
proxy_buffers 64 512K;
proxy_busy_buffers_size 1024K;
proxy_temp_file_write_size 1024K;

gzip on;
gzip_min_length 10240;
gzip_buffers 32 64k;
gzip_types application/x-javascript text/css text/xml text/plain;

client_header_buffer_size 4K;
client_max_body_size 100000000;
large_client_header_buffers 16 8K;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

output_buffers 32 256k;
postpone_output 1460;

lingering_time 30;
lingering_timeout 6;
reset_timedout_connection on;

keepalive_timeout 10;
server_names_hash_bucket_size 10240;

server {
listen **ใส่ ip ของ server ที่นี่**:85 default rcvbuf=8192 sndbuf=16384;
server_name localhost;
access_log /var/log/httpd/access_log main;
error_log /var/log/nginx/error_log info;

location / {
proxy_pass http://**ใส่ ip ของ server ที่นี่**/;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

# Main Static files location
#location ~* ^/(phpmyadmin|webmail|squirrelmail|uebimiau|roundcube)/.+\.(jpg|jpeg|gif|png|ico|css|zip|tar|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js|wmv|avi|cur|swf|mp3|wma|htc|cur)$ {
#root /var/www/html/;
#expires 30d;
#access_log off;
#}

# MRTG
#location ~* ^/(stats|mrtg)/.+\.(jpg|jpeg|gif|png|html|htm)$ {
#root /var/www/html/;
#access_log off;
#}

#Static files location
#location ~* ^.+\.(jpg|jpeg|gif|mp3|png|avi|vob|mpg|mpeg|mp4|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js)$ {
#root /var/www/html;
#}

#some bot does not send user-agent, just block them
if ($http_user_agent = "") {
set $proxyflag "forbidden";
return 403;
}

#security for timthumb remote code execution exploit
if ($request_uri ~* "\.php.*src=.*(flickr\.com|picasa\.com|blogger\.com|wordpress\.com|img\.youtube\.com|upload\.wikimedia\.org|photobucket\.com|imgur\.com|imageshack\.us|tinypic\.com)") {
set $proxyflag "forbidden";
return 403;
}

#cached folder should not have any php file
if ($request_uri ~* "/cache/.*\.php") {
set $proxyflag "forbidden";
return 403;
}

#bad behavior url (known botnet/trojan)
if ($request_uri ~* "\?.*eval\(") {
set $proxyflag "forbidden";
return 403;
}
if ($request_uri ~* "act=phptools") {
set $proxyflag "forbidden";
return 403;
}

#sql injection tools
if ($http_user_agent ~* "Havij") {
set $proxyflag "forbidden";
return 403;
}
if ($http_user_agent ~* "^sqlmap/") {
set $proxyflag "forbidden";
return 403;
}
}
include /usr/local/nginx/etc/virtual.conf;
}


เมื่อเรียบร้อยแล้วจากนั้นให้สร้าง 4 ไฟล์ตามลำดับดังนี้

ขั้นตอนที่ 7 สร้างไฟล์ที่ 1 ด้วยคำสั่ง
nano -w /usr/local/directadmin/data/templates/custom/nginx.conf


ขั้นตอนที่ 8 ใส่ข้อความด้านล้างนี้ลงไปในไฟล์ที่สร้า้งในขั้นตอนที่ 7
server {
listen |IP|:85;
server_name |DOMAIN| www.|DOMAIN| |SERVER_ALIASES|;
access_log /var/log/httpd/domains/|DOMAIN|.log main;
error_log /var/log/httpd/domains/|DOMAIN|.error.log error;
location / {
proxy_pass http://|IP|;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

client_max_body_size 10m;
client_body_buffer_size 128k;

proxy_connect_timeout 60;
proxy_send_timeout 90;
proxy_read_timeout 90;

proxy_buffer_size 64k;
proxy_buffers 120 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location @back {
proxy_pass http://|IP|;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

#Static files location
location ~* ^.+\.(jpg|jpeg|gif|mp3|png|avi|vob|mpg|mpeg|mp4|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js)$ {
root |HOME|/domains/|DOMAIN|/public_html;
expires 14d;
error_page 404 = @back;
}
}


ขั้นตอนที่ 9 สร้างไฟล์ที่ 2 ด้วยคำสั่ง
nano -w /usr/local/directadmin/scripts/nginx_direct.sh


ขั้นตอนที่ 10 ใส่ข้อความด้านล้างนี้ลงไปในไฟล์ที่สรา้งขึ้นในขั้นตอนที่ 9
#!/bin/bash

NGINXHOST=/usr/local/nginx/etc/virtual.conf;

PATH_CONF=/usr/local/directadmin/data/users;

NGINXTEMPATE=/usr/local/directadmin/data/templates/custom/nginx.conf;

NGINXSUBTEMPATE=/usr/local/directadmin/data/templates/custom/nginx_sub.conf;

HOLD=/tmp/nginx.conf.$$;

 

showHelp() {

echo "Rewrite all users's nginx.conf from template:";

echo "$0 all ";

echo "Rewrite users nginx.conf :";

echo "$0 -u username";

echo "For useing modify nginx.conf , you mast create file:";

echo "/usr/local/directadmin/data/users/USERNAME/domains/DOMAIN_NAME.custom_nginx with modify config.";

}

do_exit() {

exit 1;

}

check_user(){

if [ "$1" = "" ] ; then

#echo "User not exit";

return 1;

else

return 0;

fi

}

check_domain()

{

if [ ! -s $1 ];then

return 1;

else

return 0;

fi

}

user_configs(){

_UHOME=`grep -e "^${1}:" /etc/passwd | cut -d: -f6`;

_USER=$1;

_DOMAINLIST=${PATH_CONF}/$_USER/domains.list;

_NGINXCONF=${PATH_CONF}/$_USER/nginx.conf;

if ! check_user $_UHOME; then

return 1;

fi

if ! check_domain $_DOMAINLIST; then

return 1;

fi

_UIP=`cat ${PATH_CONF}/$_USER/user.conf | grep ip= | cut -d= -f2`;

if [ ! -f $_NGINXCONF ]

then

echo "include $_NGINXCONF;" >> $NGINXHOST;

else

cat $_NGINXCONF > $HOLD;

rm -rf $_NGINXCONF;

fi

 

for i in `cat $_DOMAINLIST`; do

if [ -f ${PATH_CONF}/$_USER/domains/$i.custom_nginx ]

then

cat ${PATH_CONF}/$_USER/domains/$i.custom_nginx >> $_NGINXCONF;

else

if [ -f ${PATH_CONF}/$_USER/domains/$i.pointers ]

then

for j in `cat ${PATH_CONF}/$_USER/domains/$i.pointers | awk -F= '{print $1}' `; do

park=`echo "$park $j www.$j"`;

done

fi

if ! cat $NGINXTEMPATE | sed 's#|HOME|#'$_UHOME'#g' | sed 's!|DOMAIN|!'$i'!g' |sed 's/|SERVER_ALIASES|/'"$park"'/' | sed 's!|IP|!'$_UIP'!' | sed 's!|USERNAME!'$1'!' >> $_NGINXCONF; then

if [ -f $HOLD ]; then

cat $HOLD > $_NGINXCONF;

fi

return 1;

fi

fi

for l in `cat ${PATH_CONF}/$_USER/domains/$i.subdomains`; do

cat $NGINXSUBTEMPATE | sed 's#|HOME|#'$_UHOME'#g' | sed 's!|DOMAIN|!'$i'!g'|sed 's/|SUB|/'$l'/g' | sed 's!|IP|!'$_UIP'!' | sed 's!|USERNAME|!'$1'!' >> $_NGINXCONF;

done

park="";

done

if [ -f $HOLD ]; then

rm -rf $HOLD;

fi

}

doAll(){

for i in `ls /usr/local/directadmin/data/users/`; do

user_configs $i;

done

}

 

case "$1" in

all) doAll;

;;

-u) user_configs $2;

;;

* ) showHelp;

do_exit 0;

;;

esac

do_exit 0;


ขั้นตอนที่ 11 สร้างไฟล์ที่ 3 ด้วยคำสั่ง
nano -w /usr/local/directadmin/scripts/nginx_task.sh

ขั้นตอนที่ 12 ใส่ข้อความด้านล้างนี้ลงไปในไฟล์ที่สร้างขึ้นในขั้นตอนที่ 11
#!/bin/bash

if [ -f /usr/local/nginx/etc/task.nginx ]; then

`cat /usr/local/nginx/etc/task.nginx | sort -u > /usr/local/nginx/etc/task.nginx.do`

rm -rf /usr/local/nginx/etc/task.nginx

while read LINE

do

`echo sh $LINE`;

done < /usr/local/nginx/etc/task.nginx.do

rm -rf /usr/local/nginx/etc/task.nginx.do

/etc/init.d/nginx reload

fi


ขั้นตอนที่ 13 สร้างไฟล์ที่ 4
nano -w /usr/local/directadmin/scripts/nginx_del.sh

ขั้นตอนที่ 14 ใส่ข้อความด้านล่างนี้ลงไปในไฟล์ที่สร้างในขั้นตอนที่ 13
#!/bin/bash

USER_CONF="include /usr/local/directadmin/data/users/$1/nginx.conf;";

if cp /usr/local/nginx/etc/virtual.conf /usr/local/nginx/etc/virtual.conf.bak; then

rm -rf /usr/local/nginx/etc/users/$1;

STR="/usr/bin/perl -pi -e 's#$USER_CONF##' /usr/local/nginx/etc/virtual.conf.bak";

eval ${STR};

sed '/^$/d' /usr/local/nginx/etc/virtual.conf.bak > /usr/local/nginx/etc/virtual.conf;

rm -rf /usr/local/nginx/etc/virtual.conf.bak

fi


ขั้นตอนที่ 15 ทำการเปลี่ยน Directory
cd /usr/local/directadmin/scripts/custom

ขั้นตอนที่ 16 สร้าง script สั่งการทำงานของ NginX ให้ DirectAdmin ค่อยๆ สั่งทีละบรรทัดนะครับ
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > domain_create_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > domain_destroy_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > domain_pointer_create_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > domain_pointer_destroy_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > subdomain_create_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > subdomain_destroy_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_direct.sh -u \$username\" >> /usr/local/nginx/etc/task.nginx" > user_create_post.sh;
echo "echo \"/usr/local/directadmin/scripts/nginx_del.sh $username" > user_destroy_post.sh;

ขึ้นตอนที่ 17 ทำการเปลี่ยนเจ้าของไฟล์ให้ DirectAdmin สามารถรันได้
chown diradmin:diradmin -R /usr/local/directadmin/scripts/*

ขั้นตอนที่ 18 ทำการเปลี่ยน Permission ไฟลให้รันได้์
chmod a+x /usr/local/directadmin/scripts/custom/*.sh
chmod a+x /usr/local/directadmin/scripts/*.sh

ขั้นตอนที่ 19 เรียบร้อยแล้วสร้าง cron เพื่อรัน script ที่เราสร้างไว้ทุกๆ 2 นาทีด้วยคำสั่ง
echo "*/2 * * * * /usr/local/directadmin/scripts/nginx_task.sh" >> /etc/crontab
/etc/init.d/crond restart

ขั้นตอนที่ 20 ให้สร้างไฟล์ nginx_sub.conf
nano -w /usr/local/directadmin/data/templates/custom/nginx_sub.conf

ขั้นตอนที่ 21 ใส่ข้อความด้านล้างนี้ลงไปในไฟล์ที่สร้างในขั้นตอนที่ 20
server {
listen |IP|:85;

server_name |SUB|.|DOMAIN| www.|SUB|.|DOMAIN|;

access_log /var/log/httpd/domains/|DOMAIN|.|SUB|.log main;

error_log /var/log/httpd/domains/|DOMAIN|.|SUB|.error.log error;

location / {

proxy_pass http://|IP|;

proxy_redirect off;

 

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

 

client_max_body_size 10m;

client_body_buffer_size 128k;

 

proxy_connect_timeout 60;

proxy_send_timeout 90;

proxy_read_timeout 90;

 

proxy_buffer_size 4k;

proxy_buffers 120 64k;

proxy_busy_buffers_size 64k;

proxy_temp_file_write_size 64k;

 

}

location @back {

proxy_pass http://|IP|;

proxy_redirect off;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

#Static files location

location ~* ^.+\.(jpg|jpeg|gif|mp3|png|avi|vob|mpg|mpeg|mp4|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|js)$ {

root |HOME|/domains/|DOMAIN|/public_html/|SUB|;

expires 14d;

error_page 404 = @back;

}

}


ขั้นตอนที่ 22 สร้างโฟลเดอร์ 2 ชุด ทีละบรรทัดนะครับ
mkdir /var/run/nginx/
mkdir /usr/local/nginx/etc/

ขั้นตอนที่ 23 สร้างไฟล์เปล่า ชื่อ virtual.conf
vi /usr/local/nginx/etc/virtual.conf

ขั้นตอนที่ 24 สร้างโฟลเดอร์เพื่อเก็บ log
mkdir /var/log/nginx

ขั้นตอนที่ 25 สร้างไฟล์เปล่าเพื่อเก็บ log
/var/log/nginx/error_log

ขั้นตอนที่ 26 กระจาย nginx config เข้าไปใน directadmin user
rm -f /usr/local/directadmin/data/users/*/nginx.conf
cat /dev/null > /usr/local/nginx/etc/virtual.conf
/usr/local/directadmin/scripts/nginx_direct.sh all

ขั้นตอนที่ 27 สร้างไฟล์เพื่อ start/stop/restart nginx service
nano -w /etc/init.d/nginx

ขั้นตอนที่ 28 ใส่ config ด้านล่างนี้ที่ไฟล์ที่สร้างในขั้นตอนที่ 27
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemin

# Taken from http://www.hikaro.com

# chkconfig: - 85 15

# description: Nginx is an HTTP(S) server, HTTP(S) reverse \

# proxy and IMAP/POP3 proxy server

# processname: nginx

# config: /usr/local/nginx/conf/nginx.conf

# pidfile: /usr/local/nginx/logs/nginx.pid

# Source function library.

. /etc/rc.d/init.d/functions

# Source networking configuration.

. /etc/sysconfig/network

# Check that networking is up.

[ "$NETWORKING" = "no" ] && exit 0

nginx="/usr/local/sbin/nginx"

prog=$(basename $nginx)

NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

lockfile=/var/lock/subsys/nginx

start() {

[ -x $nginx ] || exit 5

[ -f $NGINX_CONF_FILE ] || exit 6

echo -n $"Starting $prog: "

daemon $nginx -c $NGINX_CONF_FILE

retval=$?

echo

[ $retval -eq 0 ] && touch $lockfile

return $retval

}

stop() {

echo -n $"Stopping $prog: "

killproc $prog -QUIT

retval=$?

echo

[ $retval -eq 0 ] && rm -f $lockfile

return $retval

}

restart() {

configtest || return $?

stop

start

}

reload() {

configtest || return $?

echo -n $"Reloading $prog: "

killproc $nginx -HUP

RETVAL=$?

echo

}

force_reload() {

restart

}

configtest() {

$nginx -t -c $NGINX_CONF_FILE

}

rh_status() {

status $prog

}


rh_status_q() {

rh_status >/dev/null 2>&1

}


case "$1" in

start)

rh_status_q && exit 0

$1

;;

stop)

rh_status_q || exit 0

$1

;;

restart|configtest)

$1

;;

reload)

rh_status_q || exit 7

$1

;;

force-reload)

force_reload

;;

status)

rh_status

;;

condrestart|try-restart)

rh_status_q || exit 0

;;

*)

echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"

exit 2

esac


ขั้นตอนที่ 29 เปลี่ยน permission ไฟล์ถูกเรียกใช้งานได้
chmod +x /etc/init.d/nginx

ขั้นตอนที่ 30 ทำการ Restart nginx ด้วยคำสั่ง
service nginx restart

ขั้นตอนที่ 31 สั่งให้ nginx ทำงานทันทีที่ reboot server
/sbin/chkconfig nginx on

ขั้นตอนที่ 32 เพิ่ม NginX ที่ Service Monitor ของ DirectAdmin ด้วยการแก้ไขไฟล์ Service Status ของ DirectAdmin
nano -w /usr/local/directadmin/data/admin/services.status

ขั้นตอนที่ 33 เพิ่ม Code ด้านล่างนี้ไปที่ท้ายสุดของไฟล์ในขั้นตอนที่ 29
nginx=ON

ขั้นตอนที่ 34 สั่ง Restart DirectAdmin
service directadmin restart
ถึงขั้นตอนนี้ให้ทดสอบเรียกเว็บด้วย port 85 ที่เราตั้งค่าไว้ดูครับโดยเรียกผ่าน
www.domain.com:85
ถ้าไม่พบปัญหาหน้าเว็บเพี้ยน เจอ error รูปไม่แสดงผล

ก็สั่งให้ NginX ทำงานเป็น Reverse Proxy ก่อน Apache ด้วย iptables
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 85

ถ้าเกิดข้อผิดพลาดสามารถย้อคำสั่งได้ด้วย
iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 85

ถ้าไม่มีปัญหาก็สั่งบันทึก iptables ได้เลยครับ
iptables save

การติดตั้ง NginX รูปแบบนี้จะทำให้ log ของ Apache ไม่ตรงครับ IP ที่เรียกเข้ามาจะแสดงเป็น IP ของ Server ล้วนๆ
วิธีแก้ไขสามารถทำได้โดยติดตั้ง mod_rpaf ครับ ขั้นตอนติดตั้งสามารถดูจาก link ด้านล่างได้เลยครับ http://support.hostatom.com/knowledgebase.php?action=displayarticle&id=105

Was this answer helpful?

 Print this Article

Also Read

วิธีเพิ่ม NginX ลงที่หน้าดู Service Monitor ของ Directadmin

เริ่มด้วยการแก้ไขไฟล์ Service Status ของ DirectAdmin nano -w...

วิธีสร้างไฟล์เพื่อ Start Restart หรือ Stop Service NginX

เริ่มต้นด้วยการสร้างไฟล์เพื่อ start/stop/restart nginx service เลยครับ touch /etc/init.d/nginx...

NginX basic security configuration

เป็น Security Config ที่สามารถป้องกัน bot ที่ไม่มีประโยชน์และการโจมตีบางประเภทได้ครับ...

วิธีสั่งให้ NginX ทำงานทันทีเมื่อ restart เครื่อง

ก่อนทำวิธีนี้ต้องทำการสร้างไฟล์เพื่อทำการ Start Stop และ Restart NginX ก่อนนะครับจาก link นี้ครับ...