เห็นมีการคุยกันที่ codenone เรื่องโฮสต์ไพธอนหายากมาก
จึงขออนุญาตบันทึกการทำโฮสต์ไว้ใช้เองไว้ที่นี่แทน เพราะว่าเราใช้เดเบียน ;D
เพื่อจะได้สามารถใช้งาน Python Ruby หรือแพกเกจที่ไม่ใช่แพกเกจท้องตลาดได้อย่างอิสระเสรี
ขั้นตอนคร่าว ๆ คือ
เริ่มด้วย
นอกจากสองที่นี้แล้ว ยังมีอีกมาก สามารถลองค้นจากกูเกิลได้ ด้วยคำว่า "free dynamic dns" ครับ
เมื่อลงทะเบียนและใส่ชื่อโดเมนเราแล้ว เขาจะให้ชื่อ DNS เรามาสองชื่อ เช่นของ zoneedit จะเป็น ns1.zoneedit.com และ ns2.zoneedit.com (ชื่อ DNS จริงอาจแปลกไปจากตัวอย่าง) ซึ่งเราจะเอาชื่อทั้งสองชื่อนี้ ไปจดทะเบียนชื่อโดเมนต่อไป
เกร็ด
รวมทั้งขั้นตอนการอัปเดตก็ต่างกัน
# aptitude install portsentry
ต้องขอออกตัวก่อนครับ ว่าผมเป็นเพียงผู้ใช้งานเดเบียนคนนึง ไม่มีความรู้ลึกซึ้งกว้างขวางกับลินุกซ์เลย
ข้อเขียนต่อไปนี้จึงไม่ใช่สูตรสำเร็จแบบ How To แต่เขียนขึ้นเพื่อจุดประสงค์ในการแลกเปลี่ยนความรู้ จึงให้คิดว่าเป็นเพียงงานทดลองที่ใช้งานได้เท่านั้น
ในข้อเขียนนี้มีคำอธิบายที่ไม่ถูกต้องตามหลักวิชาการอยู่มากมาย (ลูกทุ่งสุด ๆ) ดังนั้นจึงยินดีรับข้อแนะนำเพื่อปรับปรุงให้ทราบกันต่อไปครับ
สมมุติว่า
สำหรับการต่อเน็ต adsl แบบใช้โมเด็มในตัวเครื่อง จะเปรียบเสมือนกับว่าเราเป็นเราเตอร์เอง
จึงไม่ต้องการการ ping เพื่อตรวจสอบไอพีเป็นระยะ เหมือนกับการเชื่อมต่อผ่านเราเตอร์
เมื่อสายหลุด โมเด็มจะทำการเชื่อมต่อใหม่โดยอัตโนมัติ โดยขั้นตอนในการเชื่อมต่อจะเป็นดังนี้
เราใช้แค่สคริปต์ /etc/ppp/ip-up.local ก็พอ โดยจะดักการเชื่อมต่อตรงจุดนี้
โดยเราจะสร้างสคริปต์ย่อยในการอัปเดตขึ้นมาอีกสคริปต์นึง เนื่องจากในการอัปเดต จำเป็นต้องมีชื่อผู้จดทะเบียนและรหัสผ่านอยู่ในสคริปต์ด้วย เราจึงต้องนำสคริปต์ไปไว้ในที่ปลอดภัย (ผมเอาไปใส่ใน /usr/sbin)
สำหรับ zoneedit.com
แก้ไขไฟล์ ip-up.local ดังนี้
# vi /etc/ppp/ip-up.local
... if [ $PPP_IFACE == "ppp0" ]; then # REFRESH DNS # REFRESH IPTABLES # REFRESH SQUID # RECONNECT DDNS /usr/sbin/d.updatezoneedit fi ...
สร้างสคริปต์อัปเดตชื่อ /usr/sbin/d.updatezoneedit ดังนี้
# vi /usr/sbin/d.updatezoneedit
#!/bin/bash # SCRIPT FOR PPP TO UPDATE DNS RECORD AT zoneedit.com # UPDATE FUNCTION #usage: updatezonedit $USER $PASSWORD $IP_ADDR $DOMAIN $HOST # : updatezonedit MYUSERNAME MYPASSWORD $PPP_IP example.com www.example.com updatezoneedit() { USER=$1 PASSWORD=$2 IP_ADDR=$3 DOMAIN=$4 HOST=$5 wget -O - --http-user=$USER --http-passwd=$PASSWD "http://www.zoneedit.com/auth/dynamic.html?host=$DOMAIN&type=A&dnsto=$IP_ADDR" } # BEGIN MAIN PROGRAM I_FACE=ppp0 USER="MYUSERNAME" PASSWD="MYPASSWORD" DOMAIN1="example.com" HOST1="www.example.com" IP_ADDR=`ifconfig $I_FACE | fgrep -i inet | cut -d : -f 2 | cut -d \ -f 1` # FOR example.com echo "Updating $DOMAIN1 ..." updatezoneedit $USER $PASSWD $IP_ADDR $DOMAIN1 $HOST1 echo "Finished."
# chmod 0700 /usr/sbin/d.updatezoneedit
ครั้งแรกเราเรียกใช้ครั้งเดียว ที่เหลือระบบจะทำอัตโนมัติทุกครั้งที่สายหลุด หรือเปิดเครื่อง
# /usr/sbin/d.updatezoneedit
เสร็จแล้วครับ
(ท่านใดเอาไปใช้งาน ถ้าไม่ผ่านรบกวนแจ้งด้วยนะครับ เพราะตัดทอนจากโปรแกรมที่ใช้งานอยู่ บางทีอาจตรวจทานหลุด เพราะทดสอบยาก)
สำหรับ everydns.net
แก้ไขไฟล์ ip-up.local ดังนี้
# vi /etc/ppp/ip-up.local
... if [ $PPP_IFACE == "ppp0" ]; then # REFRESH DNS # REFRESH IPTABLES # REFRESH SQUID # RECONNECT DDNS /usr/sbin/d.updateeverydns fi ...
สร้างสคริปต์อัปเดตชื่อ /usr/sbin/d.updateeverydns ดังนี้
# vi /usr/sbin/d.updatezeverydns
#!/bin/bash # SCRIPT FOR PPP TO UPDATE DNS RECORD AT everydns.net # PREREQUIST: # 0.REGISTER USERNAME & PASSWORD AT www.everydns.net # - ADD DYNAMIC DNS example.com # - ADD DYNAMIC DNS www.example.com # 1.DOWNLOAD FILE http://www.everydns.net/eDNS.pl # PUT IN /usr/local/bin # 2.INSTALL ncftp # # aptitude install ncftp # 3.INSTALL PERL MIME::Base64 # # perl -MCPAN -e 'install MIME::Base64' # UPDATE FUNCTION #usage: updateeverydns $USER $PASSWORD $IP_ADDR $DOMAIN $HOST # : updateeverydns MYUSERNAME MYPASSWORD $PPP_IP example.com www.example.com updatezone() { USER=$1 PASSWORD=$2 IP_ADDR=$3 DOMAIN=$4 HOST=$5 eDNS.pl -u $USER -p $PASSWORD -ip $IP_ADDR -d $DOMAIN eDNS.pl -u $USER -p $PASSWORD -ip $IP_ADDR -d $HOST } # BEGIN MAIN PROGRAM I_FACE=ppp0 USER="MYUSERNAME" PASSWD="MYPASSWORD" DOMAIN1="example.com" HOST1="www.example.com" IP_ADDR=`ifconfig $I_FACE | fgrep -i inet | cut -d : -f 2 | cut -d \ -f 1` # FOR example.com echo "Updating $DOMAIN1 ..." updatezone $USER $PASSWD $IP_ADDR $DOMAIN1 $HOST1 echo "Finished."
# chmod 0700 /usr/sbin/d.updateeverydns
ตามคำแนะนำของ everydns คือจะต้องใช้สคริปต์ของเขา ซึ่งสคริปต์นั้นเขียนด้วย perl มีการเรียกใช้ ncftp จึงต้อง...
ดาวน์โหลดสคริปต์มาก่อน และนำไปเก็บไว้ที่ /usr/local/bin
# wget http://www.everydns.net/eDNS.pl
# chmod 755 eDNS.pl
# mv eDNS.pl /usr/local/bin
ในสคริปต์จะต้องเรียกใช้ ncftp จึงต้องติดตั้ง ncftp ก่อน
# aptitude install ncftp
ติดตั้ง perl MIME::base64 ตามคำแนะนำ
# perl -MCPAN -e 'install MIME::Base64'
ครั้งแรกเราเรียกใช้ครั้งเดียว ที่เหลือระบบจะทำอัตโนมัติทุกครั้งที่สายหลุด หรือเปิดเครื่อง
# /usr/sbin/d.updateeverydns
เสร็จแล้วครับ
การแก้ปัญหาการส่งเมล สำหรับโฮสต์ที่ใช้ dynamic ip โดยใช้ gmail และ postfix
ปัญหาคือเมลเซิร์ฟเวอร์สาธารณะไม่ยอมรับจดหมายจากเครื่องที่มีไอพีไม่คงที่
จะแก้โดยให้ gmail เป็นผู้ส่งจดหมายให้
สมมุติว่าเราได้ติดตั้ง postfix ไว้แล้ว
เสร็จแล้ว
postconf -e 'relayhost = smtp.gmail.com' postconf -e 'smtp_sasl_auth_enable = yes' postconf -e 'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd' postconf -e 'smtp_sasl_security_options ='
echo "smtp.gmail.com USER@gmail.com:PASSWORD" >> /etc/postfix/sasl_passwd chown root:root /etc/postfix/sasl_passwd chmod 600 /etc/postfix/sasl_passwd postmap /etc/postfix/sasl_passwd
/etc/init.d/postfix restart
เสร็จแล้ว
หลังจากนี้เวลาเซิร์ฟเวอร์เราส่งเมลออก เขาจะใช้กูเกิลในการส่งแทน
อ้างอิง
กรณีเราเตอร์จะต่างจากกรณีโมเด็ม คือเราไม่สามารถทราบได้ว่าสายจะหลุดเมื่อใด ดังนั้นเราจึงต้องอาศัยการเช็คไอพีเป็นระยะ โดยอาศัยการทำงานของ crontab
การทำงานในขั้นตอนนี้ของแพกเกจสำเร็จรูปทั่วไป จะใช้การตรวจสอบไอพีไปที่ zoneedit เป็นระยะ เช่นทุก ๆ 5 นาที เป็นต้น แต่เนื่องจากเราเขียนสคริปต์เอาเอง เราจึงสามารถประหยัดแบนด์วิธ (แม้เพียงน้อยนิด) ได้ โดยแทนที่จะไปตรวจไอพีเอาจาก zoneedit เราก็ตรวจเอาจากเราเตอร์ของเราแทน
Internet -> Router -> Server:eth1 192.168.5.1 192.168.5.3 | v Server:eth0 -> Internal Network 192.168.1.1 192.168.1.0/16
สมมุติว่า
เราสามารถดูไอพีของเราเตอร์ที่เป็นสายนอกได้จากคำสั่ง wget
ตัวอย่างของผมใช้คำสั่ง
# wget -o /dev/null -O - --http-user="ADMIN" --http-passwd="ADMIN-PASSWORD" "http://192.168.5.1/wancfg.cmd?action=view"
จะได้ผลลัพธ์ออกมาเต็มไปหมด แต่ในนั้นจะมีหมายเลขไอพีเราอยู่ด้วย
ต่อไปเราจะกรองข้อมูลที่เราไม่ต้องการทิ้ง ให้เหลือแต่เลขไอพี
ตอนนี้เราใฃ้เทคนิกคือ แม้ว่าไอพีเราจะเปลี่ยนทุกครั้งที่ต่อสายใหม่ แต่ตัวที่ไม่เปลี่ยนคือตัวเลขสองหลักหน้า ดังนั้นเราจะเอาตัวเลขสองหลักหน้ามาเป็นตัวกรอง
เช่นของผมเป็น 58.9.XXX.XXX เราจะเพิ่มการกรองด้วยคำสั่ง grep 58.9
# wget -o /dev/null -O - --http-user="ADMIN" --http-passwd="ADMIN-PASSWORD" "http://192.168.5.1/wancfg.cmd?action=view" | grep 58.9
ได้ผลลัพธ์เป็น
<td>58.9.XXX.XXX</td>
เพิ่มการกรองอีกชั้นนึงให้ตัดแท็ก html:td ทิ้ง คำสั่งกลายเป็น
# wget -o /dev/null -O - --http-user="ADMIN" --http-passwd="ADMIN-PASSWORD" "http://192.168.5.1/wancfg.cmd?action=view" | grep 58.9 | cut -d ">" -f 2 | cut -d "<" -f 1
ได้แล้ว
58.9.XXX.XXX
ถึงตอนนี้เพื่อให้ใช้งานสะดวก และเป็นการปกปิดชื่อและรหัสผ่าน เราจะทำเป็นสคริปต์ เก็บไว้ที่ /usr/sbin ผมตั้งชื่อว่า d.router-getip
# vi /usr/sbin/d.router-getip
#!#!/bin/bash CMD="http://192.168.5.1/wancfg.cmd?action=view" USER="ADMIN" PASSWORD="ADMIN-PASSWORD" FIRSTTWODIGIT="58.9" IP_ADDR=`wget -o /dev/null -O - --http-user=$USER --http-passwd=$PASSWORD $CMD | grep $FIRSTTWODIGIT | cut -d ">" -f 2 | cut -d "<" -f 1` >> /dev/null echo $IP_ADDR
# chmod 0700 /usr/sbin/d.router-getip
เวลาเรียกใช้ก็สั่ง d.router-getip ก็จะได้ไอพีของ WAN ออกมา
ต่อไปเราจะสร้างสคริปต์ให้มีการตรวจสอบว่าไอพีตรงกับค่าปัจจุบันหรือไม่
ถ้าตรงก็ไม่ทำอะไร แต่ถ้าไม่ตรงก็จะให้ไปเรียกสคริปต์ให้ไปอัปเดต DDNS และเก็บค่าไอพีใหม่ ผมตั้งชื่อไฟล์ว่า d.router-cron-checkip ซึ่งผมเก็บไว้ที่ /usr/local/bin
# vi /usr/local/bin/d.router-cron-checkip
#!/bin/bash OLD_IP=`cat /root/router-ip` CUR_IP=`/usr/sbin/d.router-getip` if [ $OLD_IP != $CUR_IP ]; then echo $CUR_IP > /root/router-ip /usr/sbin/d.update-zoneedit fi
# chmod 755 /usr/local/bin/d.router-cron-checkip
งานต่อไปคือการตั้งให้ crontab ตรวจสอบค่าไอพีทุก 5 นาที
# crontab -e
... #CHECK ROUTER IP ADDRESS EVERY 5 MIN 0/5 0-23 * * * /usr/local/bin/d.router-cron-checkip ...
เสร็จแล้วครับ
เกร็ด
จากตัวอย่าง ผมละเลยที่จะกล่าวถึงการทำตาราง nat เพราะความรู้ไม่พอที่จะอธิบาย จึงขอลงวิธีการไว้ตอนท้ายเพื่อให้สามารถศึกษาต่อได้เองดังนี้ครับ
# vi /etc/sysctl.conf
... net.ipv4.ip_forward = 1 ...
# echo 1 > /proc/sys/net/ipv4/ip_forward
# route add default gw 192.168.5.1
# WAN_INT=eth1
# iptables -t nat -D POSTROUTING -o $WAN_INT -j MASQUERADE > /dev/null
# iptables -t nat -A POSTROUTING -o $WAN_INT -j MASQUERADE
http://192.168.5.1/wancfg.cmd?action=view
แต่เวลาใช้งานจริงต้องดูว่าเราเตอร์เราใช้คำสั่งเดียวกันนี้หรือไม่ ส่วนใหญ่ดูจาก Status Bar ด้านล่างของบราวเซอร์ เวลาที่เราเอาเมาส์ไปชี้ตรงลิงก์