如何提升minecraft server的效能?

可以透過ramdisk來解決I/O的問題。具體的方法如下:

1  #yum install java-1.7.0-openjdk
2  https://minecraft.net/download
#wget https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar

Ramdisk
http://www.minecraftwiki.net/wiki/Tutorials/Ramdisk_enabled_server
(1)建新的user
#useradd mine

修改mine這個user的密碼
#passwd  mine

(2) 在/home/mine下,建下列的資料夾 minecraft  minecraft_backups  minecraft_ramdisk
#cd /home/mine
#mkdir minecraft
#mkdir minecraft_backups
#mkdir minecraft_ramdisk

然後用把ownership 改回給mine這個使用者
#chown -R mine.mine /home/mine/*

(3) 由附加檔案minecraft的內容
新增/etc/init.d/minecraft
#vim /etc/init.d/minecraft   ( 複製, 貼上 )
#chmod +x /etc/init.d/minecraft

(4) 修改 /etc/init.d/minecraft的內容,username改成mine。( 修正路徑 ) ( 下方的檔案內容中已經做此修改。)

(5) #vim /etc/fstab
增加一行:
tmpfs  /home/mine/minecraft_ramdisk tmpfs  defaults,size=512m      0       0

(6) 直接掛上ramdisk
#mount -t tmpfs none /home/mine/minecraft_ramdisk -o size=512m
下 df -h指令來檢查有沒有變化。
#df -h

(7) 修改 cronjobs
#crontab -e

*/5 * * * * /etc/init.d/minecraft disksaverun
20 */6 * * * /etc/init.d/minecraft backup

(9)加入 system V style的啟動script
#chkconfig –list
#chkconfig –add minecraft
#service minecraft start

(10) 第一次啟動minecraft server 之後,client是無法連上的。
這個原因是因為/home/mine/minecraft_ramdisk/server.properties 這個檔案裡,
online-mode=true , 這樣子的話,只有正版才可以玩。
要改成
online-mode=false,這樣子,破解版才可以玩。

(11) #service minecraft restart

 ////////////////// 下方是minecraft server 的system V init script //////////////
#!/bin/bash

# /etc/init.d/minecraft
# version 0.5 2011-09-24 (YYYY-MM-DD)

### BEGIN INIT INFO
# Provides: minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Minecraft server
# Description: Starts the minecraft server
### END INIT INFO

#Settings
SERVICE='minecraft_server.jar'
USERNAME="mine"
MCSTORE="/home/$USERNAME/minecraft"
MCPATH="/home/$USERNAME/minecraft_ramdisk"
CPU_COUNT=1
INVOCATION="java -Xmx2048M -Xms2048M -server -jar $SERVICE nogui"
BACKUPPATH="/home/$USERNAME/minecraft_backups/"
ME=`whoami`
as_user() {
if [ "$ME" == "$USERNAME" ] ; then
bash -c "$1"
else
su - $USERNAME -c "$1"
fi
}

mc_start() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "Tried to start but $SERVICE was already running!"
else
echo "$SERVICE was not running... starting."
cd $MCPATH
if [ ! -f "$MCPATH/minecraft_server.jar" ]
then
echo "Ram drive empty... prepping."
as_user "cp -R $MCSTORE/* $MCPATH/"
fi
as_user "cd $MCPATH && screen -dmS minecraft $INVOCATION"
sleep 7
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is now running."
else
echo "Could not start $SERVICE."
fi
fi
}

mc_saveoff() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is running... suspending saves"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-off\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
sync
sleep 10
else
echo "$SERVICE was not running. Not suspending saves."
fi
}

mc_saveon() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is running... re-enabling saves"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-on\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP ENDED. Server going read-write...\"\015'"
else
echo "$SERVICE was not running. Not resuming saves."
fi
}

mc_stop() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is running... stopping."
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 5 SECONDS. Saving map...\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
sleep 5
as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
sleep 5
else
echo "$SERVICE was not running."
fi
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE could not be shut down... still running."
else
echo "$SERVICE is shut down."
fi
}
mc_update() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is running! Will not start update."
else
MC_SERVER_URL=http://minecraft.net/`wget -q -O - http://www.minecraft.net/download.jsp | grep minecraft_server.jar\ | cut -d \" -f 2`
as_user "cd $MCPATH && wget -q -O $MCPATH/minecraft_server.jar.update $MC_SERVER_URL"
if [ -f $MCPATH/minecraft_server.jar.update ]
then
if `diff $MCPATH/minecraft_server.jar $MCPATH/minecraft_server.jar.update >/dev/null`
then
echo "You are already running the latest version of $SERVICE."
else
as_user "mv $MCPATH/minecraft_server.jar.update $MCPATH/minecraft_server.jar"
echo "Minecraft successfully updated."
fi
else
echo "Minecraft update could not be downloaded."
fi
fi
}

mc_backup() {
echo "Backing up minecraft files"
if [ -f $BACKUPPATH/MCBKUP_`date "+%Y.%m.%d"`.tar.gz ]
then
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
do
if [ -f $BACKUPPATH/MCBKUP_`date "+%Y.%m.%d"`-$i.tar.gz ]
then
continue
else
as_user "cd $MCSTORE && tar zcf $BACKUPPATH/MCBKUP_`date "+%Y.%m.%d"`-$i.tar.gz ."
break
fi
done
else
as_user "cd $MCSTORE && tar zcf $BACKUPPATH/MCBKUP_`date "+%Y.%m.%d"`.tar.gz ."
fi
echo "Backup complete"
}

mc_disksaverun() {

if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "Saving ramdrive to disk."
if [ ! -f $MCPATH/$SERVICE ]
then
echo "Error.. Minecraft not in ram"
else
if [ -d $MCSTORE/world2 ]
then
as_user "rm -r $MCSTORE/world2"
fi
if [ -d $MCSTORE/world ]
then
as_user "mv $MCSTORE/world $MCSTORE/world2"
fi

as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-off\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
as_user "cp -R $MCPATH/* $MCSTORE/"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-on\"\015'"

if [ -d $MCSTORE/world2 ]
then
as_user "rm -r $MCSTORE/world2"
fi
fi
else
echo "Service is not running"
fi

}

mc_disksavehalt() {
echo "Saving ramdrive to disk."
if [ ! -f $MCPATH/minecraft_server.jar ]
then
echo "Error.. Minecraft not in ram"
else
if [ -d $MCSTORE/world2 ]
then
as_user "rm -r $MCSTORE/world2"
fi
if [ -d $MCSTORE/world ]
then
as_user "mv $MCSTORE/world $MCSTORE/world2"
fi

echo "Saving, screen session closed"
as_user "cp -R $MCPATH/* $MCSTORE/"

if [ -d $MCSTORE/world2 ]
then
as_user "rm -r $MCSTORE/world2"
fi
fi
}
#Start-Stop here
case "$1" in
start)
mc_start
;;
stop)
mc_stop
mc_disksavehalt
;;
restart)
mc_stop
mc_disksavehalt
mc_start
;;
update)
mc_stop
mc_backup
mc_update
mc_start
;;
backup)
mc_disksaverun
mc_saveoff
mc_backup
mc_saveon
;;
disksavehalt)
mc_disksavehalt
;;
disksaverun)
mc_disksaverun
;;
status)
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
then
echo "$SERVICE is running."
else
echo "$SERVICE is not running."
fi
;;

*)
echo "Usage: /etc/init.d/minecraft {start|stop|update|backup|status|restart|disksaverun}"
exit 1
;;
esac

exit 0

apache mod_security關閉單一網域

有一些程式,例如Ecshop,遇到apache mod_security這個模組,ecshop的舊版本,會有不相容的情況。這種時候,如果客戶不願意升級,我必須採取的處理方式,就是針對該客戶的單一網域,關閉apache mod_security

要針對單一網域關閉apache的mod_security,根據我的測試,無法使用.htaccess檔來做,會當掉。一定要直接把相關的指令,寫在apache的config檔裡。而cpanel/WHM的apache config檔,是配合GUI自動生成的,不能隨便修改。所以這個改法,必須考慮cpanel的檔案配置。方法如下:

mkdir -p /usr/local/apache/conf/userdata/std/2/username/domain.com

然後生成檔案:

/usr/local/apache/conf/userdata/std/2/username/domain.com/mod_security.conf

在這個檔案中,加入:

<IfModule mod_security2.c> SecRuleEngine Off </IfModule>

存檔

然後,執行:

/scripts/ensure_vhost_includes --user=username

其中,username是cpanel的使用者名稱,而domain.com是網域名稱。

cpanel主機下,設定不同的帳戶可以共用資料夾

收到了客戶的要求,希望在他所租用的獨立主機下的二個account,A和B,有共用的資料夾。也就是說:

/home/A/public_html/share
/home/B/public_html/share
這兩個資料夾,是指到同一個位置。

本來我以為,只要用ln -s來建softlink,就可以把問題解決了。結果卻失敗了,softlink所在的那個帳戶,用ftp登入後,看不到share這個資料夾。這是為什麼呢?原因是在這邊,它寫說,symbolic link只能指向「正確的」的地方。使用者的ftp帳戶基本上是一個被chroot的環境,所以當然不能去看到別的使用者的檔案。

A symbolic link is a pointer to the “right” file. But if that original file is outside the jail then you can’t access it. This is the goal of a jail. Otherwise a normal user could create a symbolic link in the jail to/etc/passwd and just read it. What a security risk!

So jailed is jailed. Probably a hard link will do the job, as this is a “copy without duplicating the used size”. And for the FTP server it is like a normal file (with all the problems).

那麼,這樣的問題該如何處理呢?用 mount –bind來處理吧。這個是正確的作法。

mkdir /home/website/files/
mount –bind /home/shared/files /home/website/files/

像這樣子的作法,shared這個使用者ftp登入後,就看得到 website這個使用者的資料夾files了。因為 /home/shared/files 和 /home/website/files是同一個資料夾。

Discuz的圖形驗証碼出不來

客戶反映,他們的獨立主機上,有Discuz的圖形驗証碼出不來的錯誤。

我們一查php生成的error檔,看到的訊息是:
PHP Fatal error:  Call to undefined function imagettftext()

看來是有少php的library。這個imagettftext()所對應的php library,是GD和freetype這兩個。所以解決之道就是:

  1. 執行cpanel的easyapache:WHM -> Software -> EasyApache
  2. If prompted to upgrade, do so then repeat the above step
  3. Begin customizing based on the current provile
  4. Proceed through the screens until you get to “Step 5”
  5. On “Step 5,” click on “Exhaustive Options”
  6. Under PHP, check the checkbox for GD, ttf
  7. Proceed with Build & Compile Process

一旦成功了,圖形驗証碼就出來了。

php 5.3.10-joomla

2012年4月初,我們開始陸續升級主機上的php版本。舊版的php 5.2.17已經是deprecated了。在接連得知有客戶的網站因為php 5.2的bug問題,被駭客攻擊之後,我們決定還是要忍痛升級php 5.3.10

升級php這件事,我相信對各家的主機商都是大工程。主要也是相容性的問題。如果升級一台shared host的php,老客戶的程式出現問題,我們還是得幫忙處理。

果然,我們一升級之後,客戶的joomla程式就出現了問題:本來沒有狀況的網頁,冒出了 Warning: Parameter 1 to modMainMenuHelper::buildXML() expected to be a reference, value given in  …的字樣。

後來我們終於找到了問題,php 5.3對於語法嚴謹度的要求,比5.2還來得高。所以在 joomla的 modMainMenuHelper::buildXML() 這個函數,如果參數1傳入時,並不是用reference的型態傳入,就會造成問題。

解法是這樣子:
在檔案 /modules/mod_mainmenu/helper.php 中

修改一行,把&去掉
function buildXML(&$params)
改成
function buildXML($params)

這樣就搞定了。

 

透過.htaccess檔,禁止來自日本的ip的訪問

客戶似乎受到來自日本的壓力?(OS:被AV女優爬到身上嗎?)

總之,客戶請我們幫忙擋掉來自日本ip address的訪問。要透過.htaccess檔禁止來自日本的ip的訪問,得先上網找分配給日本的IP清單。後來湊關鍵字了湊老半天,總算不負我多年來的日本A片素養日本語能力素養。關鍵字是「日本に割り当てられているIPアドレスリスト」

這個.htaccess檔就放這邊了,有需要的請取用吧。XD

awk抓成績

最近接的一個case,是東光舞蹈教室的自由盃網站維護:客戶的要求之一,是要在網站上提供17屆、18屆的比賽成績連結。跟客戶要資料時,客戶表示,在某某網站上就可以”抓”了。像這個網站

由於我太好凹了,就算了很便宜的價錢給客戶,不過是個成績網頁嘛,就是複製、貼上,修一下html,就結束了。(我是這樣想的。) 真的開始做的時候,才發現,糗大了。那個客戶叫我去抓資料的網站… 怎麼會出來的html,居然是…硬寫的。完全沒有<tr><td>。這叫我要怎麼湊啊。

後來,我想了一招:來吧, awk

cat original | awk '{if ($3!="") {print "array( " $1"," $2",\""
$3"\",\""$4"\"),"} else { if ($1!="") { print "\""$1"\"=>array("  } else
{print "\n" }  }  }'

試了一下噁心的awk指令,似乎有好一些了…
至少…打幾個字就變成可以用的code了。

"業餘組A組拉丁_決賽"=>array(
array( 名次,背號,"選手姓名一","選手姓名二"),
array( 1,138,"Patara","Melissa"),
array( 2,134,"潘彥儒","吳靜雯"),
array( 3,122,"劉漢偉","姚又齊"),
array( 4,139,"Puttipong","Sahaifa"),
array( 5,132,"鄭嘉文","石毓琳"),
array( 6,143,"賴建霖","郝偵汝"),
array( 7,144,"曾洺寘","李安洏"),
array( 8,137,"吳京橋","林婉姍"),
array( 9,145,"楊東原","陳蘭芳"),

 

在cpanel裡,無法將rvskin的theme由Rvblue轉回x3

客戶向我抱怨,他無法在cpanel裡,無法將rvskin的theme由Rvblue轉回x3。

我試了幾種方法,也是解決不了。後來查閱了cpanel官方論壇的解法

動用到root的權限:
vim /var/cpanel/users/${username}
將其中的RS=rvblue 改成 
                RS=x3
再執行
/scripts/updateuserdomains
才成功地改回。

透過command來搬mysql資料庫

獨立主機的客戶,從別家搬過來,mysql的資料庫總是搬不好。透過phpmyadmin也是搞不定。其實phpmyadmin會有error也是很正常的事。phpmyadmin是跑在http protocol之上的。http 的post如果有時間限制或是php的執行時間有限制,就很容易timout。

沒有辦法,只好直接下command來搬。

<<匯出>>
mysqldump -u “your_username” -p –lock-tables –databases DB1 [DB2 DB3…] > your_database_dump.sql

<<匯入>>
mysql -u “your username” -p “your_database” < database_dump.sql

如果匯出的時候,有using –all-databases 選項,可以使用:
mysql -u “your_username” -p < your_database_dump.sql   來匯入,比較簡單。

日本的虛擬主機

又接到了客戶的神奇的要求。客戶問我們,為什麼不去租日本的主機,他認為日本距離台灣比較近,RTT(round trip time)應該會比較小,可以小於100ms。日本的虛擬主機價格也跟美國差不多,但是美國的虛擬主機,以Unethost用的美西線路,最快仍然需要130~150ms之間。

我們被客戶問的沒有話講,遇到太專業的客戶也是頭痛的。XD

於是我上網查了一下日本的虛擬主機。查了老半天,我才搞清楚,要用的關鍵字不應該是「仮想サーバー」而是「レンタルサーバー」( rental server ),用錯關鍵字的話,還以為日本人沒有主機商。XD 。這邊有一個專業的評價網,供大家參考。

不過,這筆生意最後還是沒有成,因為我們幫客戶代租主機是有收代管費的,但是客戶認為應該要更便宜。這也沒有辦法~誰叫他是客戶呢?XDXD