SoftEther VPN でVPN環境を構築 (SoftEhter VPN Server設定編)

前回に引き続きSoftEther VPNの設定を行っていきます。
設定に関する詳細な手順は省きますが、やることは以下の2つ

 ・ルーターのポート開放
 ・SoftEther VPN Serverの仮想Hubおよびユーザ、グループの設定

■ルーターのポート解放
SoftEther VPN Serverの設定内容によりますが、以下のポートを開放します

ポート番号 TCP/UDP 用途
443 TCP デフォルトのリスナーポート(HTTPSポート)
500 UDP L2TPのポート(L2TP over IPsecを利用する場合必要)
992 TCP デフォルトのリスナーポート(telnetポート)
1194 UDP OpenVPNリスナーポート(OpenVPNサーバー機能を利用する場合必要)
1701 UDP L2TPのポート(暗号化されていないL2TPを利用する場合必要)
4500 UDP L2TPのポート(L2TP over IPsecを利用する場合必要)
5555 TCP デフォルトのリスナーポート
8888 UDP デフォルトのリスナーポート

どのポートを開放すべきかは各自の利用構成に合わせてください。
私の場合443番はWebサーバーが使用しているため設定していません。

また当然ですが、サーバー側のファイアーウォールの設定をお忘れなく!

■SoftEther VPN Serverの仮想Hubおよびユーザ、グループの設定
SoftEther VPN では仮想Hubごとにユーザ、グループを持っているので、
仮想Hubを作成したのちユーザを作成します。

設定方法などは結構簡単なので割愛します。

結構すんなり設定も終わりいざ接続テストという段階になってみごとにはまりました;;;;
SoftEther VPN でVPN環境を構築 (SoftEhter VPN Serverトラブル編)

SoftEther VPN でVPN環境を構築 (SoftEhter VPN Serverインストール編)

今までルーターに付属していた機能でVPNを構築していましたが、
性能などの面で使い勝手が悪かったので、自宅のサーバーを使ってVPNサーバーを構築することにしました。

そして、当然のごとくはまりました;;;;
そのメモです。

まず今回構築する環境ですが。
・サーバーOS:Vine Linux 6.1
・VPNサーバーソフト:SoftEther VPN Server 4.0

ちなみにこれはEsxi5.5上で動作している仮想サーバーです。
(このESXi上というのが最初のはまりポイントでした。)

■SoftEhterVPNServerのインストール

まず、SoftEhterVPNServerをインストールします。
1.SoftEtherVPNServerをダウンロードサイトからダウンロードします。

2.ダウンロードファイルを展開する

# ダウンロードファイルを/usr/localに移動する
#mv softether-vpnserver-v4.03-9411-rtm-2014.01.07-linux-x64-64bit.tar.gz /usr/local/.
# 展開する
#tar zxvf softether-vpnserver-v4.03-9411-rtm-2014.01.07-linux-x64-64bit.tar.gz

展開すると「vpnserver」というフォルダができます。

3.ビルドする

# 展開してできたフォルダに移動
#cd vpnserver
# ビルドする
#make

makeを実行すると、利用規約に承認するかの表示が出ますので
画面の指示に従って承認してください。

4.vpnserverを起動する

#./vpnserver start

ざっくりと書きましたがインストールはこれで終了です。
詳しくはSoftEther VPNの導入マニュアルをご覧ください。

次は管理ツールを使ってサーバーの設定を行っていきます。
SoftEther VPN でVPN環境を構築 (SoftEhter VPN Server設定編)

スマートフォンを判別する正規表現

今回はメモ書き程度です。

サイトに来た人がどのデバイスで見ているのか判別してサイトを表示させたい時ってありますよね?
それを判別するのにUser-Agetntを使って判別するというのが一般的かと思います。

私が作成したサイトでは、スマートフォンのみを判別する必要があったので以下の正規表現を用いて判別を行いました。

(iPhone|iPod|Android)+[\w\d\s;,:\_\-\.\/\(\)]+(Mobile)+

簡単に解説すると
iOSの場合、User-Agentには「iPhone」「iPod」「iPad」が記載されています。
そしてすべてに「Mobile」と記載されています。
Androidの場合、スマートフォンでもタブレットでもUser-Agentには「Android」しか記載されていません。
その代わりスマートフォンの場合のみ「Mobile」と記載されています。

よってスマートフォンであるかどうかは”「iPhone」「iPod」「Android」があり、かつ「Mobile」と記載されている”という条件で判別を行います。
表にすると以下

種別(iPhoneやAndroidなど) Mobile記載 判定
iPhone iPhone Mobile スマフォ
iPod iPod Mobile スマフォ
iPad iPad Mobile タブレット
Android(スマフォ) Android Mobile スマフォ
Android(タブレット) Android (なし) タブレット

参考サイト

Webサイトのキャプチャーを作る

現在私が管理しているWebサイトで、リンク先がサイト名だけではわかりにくいな~と思ったので、
マウスオーバーするとリンク先のイメージが表示されるような機能を付けることにしました。
その時のメモです。

今回の想定ではリアルタイムにスクリーンショットを作成する必要はないので(負荷が高くなるのでそもそもやりたくない)
wkhtmltoimageを利用して一定時間ごとにバッチでキャプチャーを撮る方式にしました。

wkhtmlimageのインストール

まず、wkhtmltoimageをインストールします。
インストールサーバーはUbuntu13.04(64bit)です。

1. ファイルをダウンロード

#wget http://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.10.0_rc2-static-amd64.tar.bz2

最新のwkhtmltoimage-0.11.0_rc1-static-amd64.tar.bz2だとエラーが出てキャプチャーが取れないので
1つ前のバージョンをダウンロードします。

2. 解凍する

#tar jxf wkhtmltoimage-0.10.0_rc1-static-amd64.tar.bz2

解凍すると wkhtmltoimage-amd64 というファイルができます。
これがそのまま実行ファイルですので ./wkhtmltoimage-amd64 http://www.google.co.jp test.png とコマンドを実行すれば
キャプチャーが作成できるはずです。

もし、ライブラリが足りないなどのエラーが表示された場合は

#sudo apt-get install wkhtmltopdf

を実行して wkhtmltopdf をインストールしてみてください。
もともとwkhtmltopdfの機能だったものを分離しているのでwkhtmltopdfをインストールすれば
必要なライブラリ類も自動的にインストールされちゃうわけです。

3. /usr/bin/に配置

#mv wkhtmltoimage-0.10.0_rc1-static-amd64 /usr/bin/wkhtmltoimage

私はこれだけでパスの設定などは特に必要なかったです。

4. 日本語フォントのインストール
このままだと日本語が文字化けするので日本語フォントをインストールします。
今回はIPAフォントを利用しました。
ダウンロードしたものを解凍して .ttfファイルを/usr/share/fonts/配下に配置するだけです。

#sudo cp ipaexg00201/*.ttf /usr/share/fonts/.

以上が終わればインストール完了です。

#wkhtmltoimage http://www.google.co.jp test.png

とコマンドを実行すればキャプチャーが作成できているはずです。

ApacheOpenMeetings(TV会議システム)を試してみた

前回に引き続きTV会議システムの話題です。

今回ためしたのは「Apache OpenMeetings」です。
これもお手軽にからISOイメージを使ってインストールしました。
(もちろんESXi5.5にです・・)

ここからISOをダウンロードしてあとはインストールするだけです。
Ubuntuベースなのでインストールはすんなりいきました。

インストールしたらhttp://[インストールサーバーのIP]:5080/openmeetings/にアクセスすれば
ログインページが表示されます。
apacheOpenMeetings_Login

初期ログインIDである「toro/123456」を入力するとログインできます。
このユーザは言語設定が「英語」になっているので、管理 > ユーザ管理から言語設定を japanese に変更しておくと操作しやすいでしょう。
(新規ユーザを作ってもいいかも・・・)
あと、BBBと同じく共有ファイルの文字化けが起こったので
言語パッケージをインストールしておくとよいでしょう。

所感

さて、所感ですが。
このApache OpenMeetingsはBigBlueButtonと違い、
ユーザ管理や会議のスケジューリングといった機能がトータルにサポートされています。
機能面でいけばBigBlueButtonより充実しているといえますね。
ただし、共有ファイルをアップロードしてから表示するまでの時間がBigBlueButtonよりかなり遅いです。 

個人的にはBigBlueButtonのほうがUI的にもデザイン的にも好みですね。

BigBlueButton(TV会議システム)を試してみた

オープンソースのTV会議システムを見つけたので試してみた。

今回試してみたのはBigBlueButton(BBB)というツール
当初は試しにインストールして放置していたopenSUSE12.1にインストールしようとしたが
説明をよく読むとUbuntu10.04にしか対応していないっぽい。。。

Ubuntu10.04をインストールしてからセットアップするのも面倒なので
配布されているVMを利用することにしました。

インストール手順

BigBlueButtonのVm配布ページからZIPファイルをダウンロードしてきます。

解凍したものをEsxi5.5のデータストアにアップロードして新しいVMとしてインベントリに追加するのですが、
ZIPに入っているvmxファイルではうまく追加できなかった・・・
そのため新規にVMをHDDなしで作成して、そこにZIPのvmdkファイルを追加
そしたらうまく起動しました。

起動したらfirstuser/defaultでログイン
パスワードを再設定するように促されるので初期パスワードを入力して
新規パスワードを2回入力して再設定します。

このまま表示されるURLにブラウザでアクセスすればdemo画面が表示され、
TV会議を試すことができます。
bigbluebuttonDemo

ただ、このまま文書共有すると日本語が化けるので追加で言語パッケージをインストールしておいたほうがいいでしょう。

sudo apt-get install language-support-fonts-ja
sudo apt-get install language-support-ja
sudo apt-get install openoffice.org-l10n-ja
sudo apt-get install ttf-ipafont

所感

使ってみたところこのツールはTV会議の機能のみを提供して、
管理する機能はAPIを利用した外部ツールで行うようですね。
MoodleやwordpressなどのCMSツールにプラグインがあり、
redmineにも存在するようです。
redmineは仕事でも利用しているし、今度試してみようかな・・

VMDKファイルのコピーに失敗する

ESXiアップデート時に起こった問題
「なぜかコピーできないVM(しかもこれがメインサーバーのVM)」
実はこれが一番原因を探るのに時間がかかりました。


・vSphere Client上でコピーしてもダメ、
・cpコマンドでコピーしてもダメ
・vmkfstoolsコマンドでクローンを移行先HDDに作ろうとしてもダメ


オプションをあれこれ変えながらいろいろ試行錯誤しましたが、どうにもならずギブアップ・・・
(コピーに時間がかかる上エラーとなるのが99%になったあたりだった)


結局、入れ替え先HDD上にVMを新規に作りそこに旧サーバーの設定やらDBデータやらを持っていく
いわゆる「サーバーの立て直し」することにしまいした。




立て直したサーバーは前のサーバーと同じvine linux 4.1 だったこともあり
以下の流れで結構すんなり移行することができました。
1. ユーザの移行
  ユーザ数が少なかったので新サーバーに手動でユーザを作り
  旧サーバーのユーザフォルダをガバーとコピーしてやりました。

2. mysqlのインストールと設定ファイルのコピー

3. 旧サーバーからmysqのデータをエクスポート→新サーバーにインポート
  mysqldumpコマンドで全データをエクスポート→インポート

4. apacheの設定ファイルと公開しているサイトのファイルをコピー

5. 新サーバーのIPアドレスを旧サーバーのものに変更する
  これが終われば速やかに旧サーバーは停止します


うちはWebサーバー以外立てていなかったためこれだけで済みましたが、
他にも色々なサーバーを立てている人は各サーバーの移行が必要でしょうね。


今回の「サーバーの立て直し」は苦肉の策、最終手段というところです。

ESXi 5.5 容量は問題ないのにコピーできない

さて、前回のESXiアップグレード時に起こった問題の1つ
「容量は問題ないのに容量オーバーとなりコピーできない。」についてです。


この問題の原因はRawデバイスマッピング(RDM)したHDDでした。

/vmfs/volumes/524d5df7-3408bde8-5d18-d4ae52ca3c1d/windows7 # ls -l
total 43148312
-rw------- 1 root root 2000398934016 Oct 4 13:47 WDC_WD20EARX2D00PASB0-rdmp.vmdk
-rw------- 1 root root 539 Oct 5 18:22 WDC_WD20EARX2D00PASB0.vmdk
-rw------- 1 root root 132120576 Oct 5 16:39 vmx-windows7-1955177614-1.vswp
-rw------- 1 root root 1073741824 Oct 5 16:39 windows7-7489a48e.vswp
-rw------- 1 root root 27 Oct 3 15:30 windows7-f185cab4.hlog
-rw------- 1 root root 42949672960 Oct 22 17:20 windows7-flat.vmdk
-rw------- 1 root root 8684 Oct 20 15:51 windows7.nvram
-rw------- 1 root root 495 Oct 5 18:22 windows7.vmdk
-rw------- 1 root root 0 Oct 3 12:08 windows7.vmsd
-rw------- 1 root root 3658 Oct 22 09:46 windows7.vmx
-rw------- 1 root root 0 Oct 5 16:39 windows7.vmx.lck
-rw------- 1 root root 3937 Oct 5 18:23 windows7.vmxf
-rw------- 1 root root 3659 Oct 22 09:46 windows7.vmx~

上記の「WDC_WD20EARX2D00PASB0-rdmp.vmdk」がRDMしたvmdkです。
御覧の通りRDMしたHDDは見掛け上マウントしたHDDと同じ容量となっています。


どうやら、この見掛け上の容量が問題でコピー時に容量オーバーとなっていたようなのです。


vShere Client上でのデータコピー、SSH接続でcpコマンドを使用したコピーなどの方法を試しましたが
すべて容量エラーでコピーに失敗してしまいました。。。


結局入れ替え先のHDDにRDMのvmdkを新しく作ることにして移行しました。


備考ですが、ESXiでRMDを作成する方法はこちらをご覧ください。
vSphere(ESXi)でSATAディスクをRDMで使う

ESXi5.1 → 5.5 へのバージョンアップ

3か月の出張を終えて帰ってまえりました。

戻ってきて即、出張している間に公開されたESXi5.5に自宅サーバーをアップグレードしてみましたw。

そしてみごとにはまり・・・・10/3~5の間サーバーにほとんど接続できなくなり、
訪れていただいた方々に非常にご迷惑をおかけしたことをこの場を借りて謝罪いたします。

さて、はまった内容ですが・・
実はESXiのアップグレードが原因ではなく、同時に行ったHDDの入れ替えがなかなかうまくいかなかったことが原因です。
1.容量は問題ないのに容量オーバーとなりコピーできない。
2.なぜかコピーできないVM(しかもこれがメインサーバーのVM)

この2つが同時に起こるものだから原因を特定するのにえらい時間がかかりました。
それぞれの詳細は別記事で書かせていただきます。

ではノシ

RSSリーダーを作ってみる その2

前回の公開したrssLoader
実はRSS2.0だとitemタグを解析できないというバグがある

どこが悪くて読み込めないかというと以下の部分

        // 各記事を取得する
        foreach($rssDom->item as $item) {
 
            $itemBean = new itemBean();

RSSのフォーマット・仕様・構造 – RSS1.0、RSS2.0、Content-Type」を見ていただくと分かるが
RSS1.0ではitemタグはchannelタグと同列のDom階層に存在するが
RSS2.0ではitemタグはchannelタグ配下のDom階層にある

RSS2.0を読み込むには「$rssDom->channel->item」としなければならないのだ

修正したソースは以下のようになる

<?php
require_once __DIR__."/channelBean.php";
require_once __DIR__."/itemBean.php";
require_once __DIR__."/rssException.php";
require_once __DIR__."/lib/httpConnecter.php";
require_once __DIR__."/lib/xmlLoader.php";

class rssLoader {

	const VERSION_1 = 1;
	const VERSION_2 = 2;

	const VERSION_ALL = 0;

	public function __construct() {
	}

	public function __destruct() {
	}

	/**
	 * RSSを読み込みchannelBeanで取得
	 *
	 * @param int $version 対象RSSバージョン指定
     *                    全バージョンのRSS  : rssLoader::VERSION_ALL
     *                    バージョン1.0のRSS : rssLoader::VERSION_1
     *                    バージョン2.0のRSS : rssLoader::VERSION_2
	 *
	 */
	public function loadRss($path, $version = self::VERSION_ALL) {

		/**
		 * RSSを取得
		 */
		$http = new httpConnecter();
		$http->connect($path);
		$rssStr = $http->loadText();
		if($rssStr === "") {

			// 取得できなければエラー
			throw rssException::notRss("RSSファイルの取得ができませんでした。");
		}


		/**
		 * RSSを解析
		 */
		$xml = new xmlLoader();
		$rssDom = $xml->parsor($rssStr);

		// すべてのバージョン
		if($version == self::VERSION_ALL) {

			try {

				return $this->loadRss2($rssDom);

			} catch (Exception $e) {

				return $this->loadRss1($rssDom);
			}
		}

		// rss1.0
		else if(isset($rssDom->attributes()->version) == false && $version == self::VERSION_1) {

			return $this->loadRss1($rssDom);
		}
		// rss2.0
		else if($rssDom->attributes()->version == 2 && $version == self::VERSION_2) {

			return $this->loadRss2($rssDom);
		}
		else {

			throw rssException::notMatchVersion("このRSSは正しい型式ではありません。");
		}

		return $channelBean;
	}

	/**
	 * RSS1.0を解析
	 * @param unknown $rssDom
	 */
	private function loadRss1($rssDom) {

		//if($rssDom->attributes()->version != self::VERSION_1) {

		//	throw rssException::notMatchVersion("このRSSはVertion1.0ではありません。");
		//}


		$channelBean = new channelBean();

		$channelBean->encoding = "UTF-8";
		$channelBean->rssVersion = self::VERSION_1;
		$channelBean->rssUrl = $rssDom->channel->link;


		// RSSの本体情報を取得
		if(isset($rssDom->channel->title)) {
			$channelBean->title = $rssDom->channel->title;
		}
		if(isset($rssDom->channel->link)) {
			$channelBean->link = $rssDom->channel->link;
		}
		if(isset($rssDom->channel->description)) {
			$channelBean->description = $rssDom->channel->description;
		}
		// dcの要素を取得
		$dc = $rssDom->channel->children('http://purl.org/dc/elements/1.1/');
		if(isset($dc->date)) {
			$channelBean->date = $dc->date;
		}
		if(isset($dc->language)) {
			$channelBean->language = $dc->language;
		}
		if(isset($dc->creator)) {
			$channelBean->creator = $dc->creator;
		}


		// ver1.0各記事を取得する
		foreach($rssDom->item as $item) {

			$itemBean = new itemBean();

			if(isset($item->title)) {
				$itemBean->title = $item->title;
			}
			if(isset($item->link)) {
				$itemBean->link = $item->link;
			}
			if(isset($item->description)) {
				$itemBean->description = $item->description;
			}
			if(isset($item->category)) {
				$itemBean->category = $item->category;
			}
			if(isset($item->pubDate)) {
				$itemBean->date = $item->date;
			}
			// dcの要素を取得
			$dc = $item->children('http://purl.org/dc/elements/1.1/');
			if(isset($dc->date)) {
				$itemBean->date = $dc->date;
			}
			if(isset($dc->subject)) {
				$itemBean->category = $dc->subject;
			}
			if(isset($dc->creator)) {
				$itemBean->creator = $dc->creator;
			}

			array_push($channelBean->itemList, $itemBean);
		}

		return $channelBean;
	}

	/**
	 * RSS2.0を解析
	 * @param unknown $rssDom
	 */
	private function loadRss2($rssDom) {

		if($rssDom->attributes()->version != self::VERSION_2) {

			throw rssException::notMatchVersion("このRSSはVertion2.0ではありません。");
		}

		$channelBean = new channelBean();

		$channelBean->encoding = "UTF-8";
		$channelBean->rssVersion = self::VERSION_2;
		$channelBean->rssUrl = $rssDom->channel->link;


		// RSSの本体情報を取得
		if(isset($rssDom->channel->title)) {
			$channelBean->title = $rssDom->channel->title;
		}
		if(isset($rssDom->channel->link)) {
			$channelBean->link = $rssDom->channel->link;
		}
		if(isset($rssDom->channel->description)) {
			$channelBean->description = $rssDom->channel->description;
		}
		// dcの要素を取得
		$dc = $rssDom->channel->children('http://purl.org/dc/elements/1.1/');
		if(isset($dc->date)) {
			$channelBean->date = $dc->date;
		}
		if(isset($dc->language)) {
			$channelBean->language = $dc->language;
		}
		if(isset($dc->creator)) {
			$channelBean->creator = $dc->creator;
		}


		// ver2.0各記事を取得する
		foreach($rssDom->channel->item as $item) {

			$itemBean = new itemBean();

			if(isset($item->title)) {
				$itemBean->title = $item->title;
			}
			if(isset($item->link)) {
				$itemBean->link = $item->link;
			}
			if(isset($item->description)) {
				$itemBean->description = $item->description;
			}
			if(isset($item->category)) {
				$itemBean->category = $item->category;
			}
			if(isset($item->pubDate)) {
				$itemBean->date = $item->date;
			}
			// dcの要素を取得
			$dc = $item->children('http://purl.org/dc/elements/1.1/');
			if(isset($dc->date)) {
				$itemBean->date = $dc->date;
			}
			if(isset($dc->subject)) {
				$itemBean->category = $dc->subject;
			}
			if(isset($dc->creator)) {
				$itemBean->creator = $dc->creator;
			}

			array_push($channelBean->itemList, $itemBean);
		}

		return $channelBean;
	}
}

上記ソースはほかにもネームスペース「dc」の要素が読み込めていない問題などを修正している

ダウンロードはこちらから→[download id=”1″]