เห็นมีการคุยกันที่ codenone เรื่องโฮสต์ไพธอนหายากมาก จึงขออนุญาตบันทึกการทำโฮสต์ไว้ใช้เองไว้ที่นี่แทน เพราะว่าเราใช้เดเบียน ;D เพื่อจะได้สามารถใช้งาน Python Ruby หรือแพกเกจที่ไม่ใช่แพกเกจท้องตลาดได้อย่างอิสระเสรี
ขั้นตอนคร่าว ๆ คือ
เริ่มด้วย
นอกจากสองที่นี้แล้ว ยังมีอีกมาก สามารถลองค้นจากกูเกิลได้ ด้วยคำว่า "free dynamic dns" ครับ
เมื่อลงทะเบียนและใส่ชื่อโดเมนเราแล้ว เขาจะให้ชื่อ DNS เรามาสองชื่อ เช่นของ zoneedit จะเป็น ns1.zoneedit.com และ ns2.zoneedit.com (ชื่อ DNS จริงอาจแปลกไปจากตัวอย่าง) ซึ่งเราจะเอาชื่อทั้งสองชื่อนี้ ไปจดทะเบียนชื่อโดเมนต่อไป
ขั้นตอนนี้ สำหรับโมเด็ม adsl ในตัว ให้ดูในหัวข้อถัดไปครับ ส่วนกรณีที่ใช้เราเตอร์ ขอติดไว้เป็นครั้งหน้า
เกร็ด
รวมทั้งขั้นตอนการอัปเดตก็ต่างกัน
# aptitude install portsentry
โดยเราจะใช้ค่าปริยายทั้งหมด โดยไม่ต้องปรับแต่งอะไรเลย
ส่วนการป้องกันเซิร์ฟเวอร์ให้ดียิ่งขึ้น ควรศึกษาเพิ่มเติมด้วยครับ
สมมุติว่า
สำหรับการต่อเน็ต ADSL แบบใช้โมเด็มในตัวเครื่อง จะเปรียบเสมือนกับว่าเราเป็นเราเตอร์เอง จึงไม่ต้องการการ ping เพื่อตรวจสอบไอพีเป็นระยะเหมือนกับการเชื่อมต่อผ่านเราเตอร์ เมื่อสายหลุด โมเด็มจะทำการเชื่อมต่อใหม่โดยอัตโนมัติ โดยขั้นตอนในการเชื่อมต่อจะเป็นดังนี้
เราใช้แค่สคริปต์ /etc/ppp/ip-up.local ก็พอ โดยจะดักการเชื่อมต่อตรงจุดนี้ โดยเราจะสร้างสคริปต์ย่อยในการอัปเดตขึ้นมาอีกสคริปต์นึง เนื่องจากในการอัปเดต จำเป็นต้องมีชื่อผู้จดทะเบียนและรหัสผ่านอยู่ในสคริปต์ด้วย เราจึงต้องนำสคริปต์ไปไว้ในที่ปลอดภัย (ผมเอาไปใส่ใน /usr/sbin)
แก้ไขไฟล์ 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.update-zoneedit
fi
...
สร้างสคริปต์อัปเดตชื่อ /usr/sbin/d.update-zoneedit ดังนี้
# vi /usr/sbin/d.update-zoneedit
#!/bin/bash # SCRIPT FOR PPP TO UPDATE DNS RECORD AT zoneedit.com # UPDATE FUNCTION #usage: updatezoneedit $USER $PASSWORD $IP_ADDR $DOMAIN $HOST # : updatezoneedit 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.update-zoneedit
ครั้งแรกเราเรียกใช้ครั้งเดียว ที่เหลือระบบจะทำอัตโนมัติทุกครั้งที่สายหลุด หรือเปิดเครื่อง
# /usr/sbin/d.update-zoneedit
เสร็จแล้วครับ
แก้ไขไฟล์ 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.update-everydns
fi
...
สร้างสคริปต์อัปเดตชื่อ /usr/sbin/d.update-everydns ดังนี้
# vi /usr/sbin/d.update-everydns
#!/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 updateeverydns() { 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 ..." updateeverydns $USER $PASSWD $IP_ADDR $DOMAIN1 $HOST1 echo "Finished."
ทำให้รันได้
# chmod 0700 /usr/sbin/d.update-everydns
ตามคำแนะนำของ 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.update-everydns
เสร็จแล้วครับ
(ท่านใดเอาไปใช้งาน ถ้าไม่ผ่านรบกวนแจ้งด้วยนะครับ เพราะตัดทอนจากโปรแกรมที่ใช้งานอยู่ บางทีอาจตรวจทานหลุด และไม่มีฮาร์ดแวร์สำหรับทดสอบแล้ว)
จากครั้งก่อนเรื่อง ทำโฮสต์ใช้เอง ยังขาดเนื้อหาว่า ถ้าอุปกรณ์ของเราเป็นเราเตอร์ เราจะมีวิธีในการอัปเดตข้อมูล DNS อย่างไร
กรณีเราเตอร์จะต่างจากกรณีโมเด็ม คือเราไม่สามารถทราบได้ว่าสายจะหลุดเมื่อใด ดังนั้นเราจึงต้องอาศัยการเช็คไอพีเป็นระยะ โดยอาศัยการทำงานของ 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/24
สมมุติว่า
เราสามารถดูไอพีของเราเตอร์ที่เป็นสายนอกได้จากคำสั่ง 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.router-update-zoneedit
fi
# chmod 755 /usr/local/bin/d.router-cron-checkip
สร้างไฟล์อัปเดตเอาไว้ที่ /usr/sbin
# vi /usr/sbin/d.router-update-zoneedit
#!/bin/bash
# SCRIPT FOR ROUTER TO UPDATE DNS RECORD AT zoneedit.com
updatezoneedit() {
USER=$1
PASSWORD=$2
IP_ADDR=$3
DOMAIN=$4
HOST=$5
# NEW wget 48-10-8 USED WHEN dynamic.zoneedit.com IS DOWN
wget -O - --http-user=$USER --http-passwd=$PASSWORD \
"http://www.zoneedit.com/auth/dynamic.html?host=$DOMAIN&type=A&dnsto=$IP_ADDR"
}
USER="MYUSERNAME"
PASSWD="MYPASSWORD"
DOMAIN1="example.com"
HOST1="www.example.com"
IP_ADDR=`/usr/sbin/d.router-getip`
updatezoneedit $USER $PASSWD $IP_ADDR $DOMAIN1 $HOST1
เสร็จสำหรับ zoneedit
# 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.router-update-everydns
fi
# chmod 755 /usr/local/bin/d.router-cron-checkip
สร้างไฟล์อัปเดตเอาไว้ที่ /usr/sbin
# vi /usr/sbin/d.router-update-everydns
#!/bin/bash
# SCRIPT FOR ROUTER TO UPDATE DNS RECORD AT everydns.net
updateeverydns() {
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
}
USER="MYUSERNAME"
PASSWD="MYPASSWORD"
DOMAIN1="example.com"
HOST1="www.example.com"
IP_ADDR=`/usr/sbin/d.router-getip`
updateeverydns $USER $PASSWD $IP_ADDR $DOMAIN1 $HOST1
เสร็จสำหรับ everydns
งานต่อไปคือการตั้งให้ 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 ด้านล่างของเบราว์เซอร์ เวลาที่เราเอาเมาส์ไปชี้ตรงลิงก์การแก้ปัญหาการส่งเมล สำหรับโฮสต์ที่ใช้ dynamic ip โดยใช้ gmail
ปัญหาคือเมลเซิร์ฟเวอร์สาธารณะไม่ยอมรับจดหมายจากเครื่องที่มีไอพีไม่คงที่
จะแก้โดยให้ 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
เสร็จแล้ว
หลังจากนี้เวลาเซิร์ฟเวอร์เราส่งเมลออก เขาจะใช้กูเกิลในการส่งแทน
อ้างอิง