自前サーバでRocket Chatを構築するメモ

世はクラウド全盛時代。サーバーレスで基本企業やユーザは、利用させてもらうだけのお手軽な時代。とはいえ、様々な事情やセキュリティの観点から使わせないという企業も未だに多いのは事実。そんな時の助けになるのが、様々なオープンソース製品。

そんなものの1つにチャットシステムがあります。LINE駄目、Slack駄目と言ってもそれだけじゃ、ただシャドーITを推進しているようなもの。企業はシャドーIT撲滅したいなら、代わりになるものを提供しなければなりません。そこで使いたいのがRocket Chat。クラウドサービスもあり、またAndroidやiOS用のアプリも用意されていて、非常にオススメです。

図:病院やセキュアな環境で使える最高のシステムかも

今回使用するもの

今回は仮想環境上にLinuxを入れて、其の中にRocket Chat Serverを作るというベタなやり方です。Docker上に構築するという今どきな手法もありますよ。

また、RocketchatのメッセージログであるBSONファイルをJSONに変換したものから、Excelで読み取ってシートデータにするプログラムを作成しました。

いざ構築をしましょう

いろいろ注意点

httpd.confが見つからない

Rocket ChatはWebアプリケーションなので、SnapでインストールするとApache2もインストールされる。今回Ubuntuにインストールしてるのですが、肝心のhttpd.confが見つからない。色々なサイトでApacheを弄る場合これを編集するみたいなことが一般論みたいに書かれていますが、Ubuntuの場合にはhttpd.confがありません。

代わりに/etc/apache2の中にapache2.confというhttpd.confの役目を果たすものがあるので、編集する場合にはこちらを利用すると良いでしょう。

図:apache2.confが設定ファイルになります

ARM64の場合の注意点

M1 Mac環境やRaspberry PiのようなARM64環境の場合、Rocket Chat Server自体はインストールできるのですが、MongoDBの5.xからCPUにAVX命令が無いとインストールできないといった事象に巻き込まれてインストールが出来ません。

2023年頃から報告はありますが、解決法がどこにも掲示されておらず。

5.x以上のARM64対応のMongoDBはこちらのサイトにあるのですが、手動でdebをインストールしても解決できず。

図:MongoDBが原因でインストール出来ない

サーバーのインストール

Ubuntu Linuxのインストールについてはここでは省略します。今は昔と違って、Linuxのインストールはとてつもなく簡単になってるので、ここで躓く人は殆どいないでしょう。

ここでは、Rocket Chat Serverのインストールを中心に紹介します。Ubuntu Linux 16.04より採用されたsnapというパッケージ管理システムのおかげで、データベースとして利用するMongoDBやら設定ファイルを書かずに済むのでお手軽です。

  1. ターミナルを起動する
  2. まずは、OSを最新にアップデートしましょう。sudo apt-get updateを実行
  3. さらに、パッケージのアップデートの為に、sudo apt-get dist-upgrade -yを実行
  4. しばらくアップデート作業が完了するまで待機します。
  5. 完了したら、sudo snap install rocketchat-serverで、Rocket Chat本体をインストール(sudo snap remove rocketchat-server でアンインストール)
  6. インストールが完了すると、Rocket Chat ServerおよびMongoDBのインストールが完了しています。サービスはOS起動時に自動で立ち上がるようになっています。(手動で起動する時はsystemctl start snap.rocketchat-server.rocketchat-server.serviceを実行する)
  7. Rocket Chat Serverの稼働状況は、systemctl status snap.rocketchat-server.rocketchat-server.serviceで確認可能です。
  8. これですでにもうRocket Chatは使えるようになっています。

ログインして環境設定

まずは、http://localhost:3000にアクセスします。Rocket Chatのメイン画面が表示されます。初回起動時にだけ管理者のアカウントとして、ユーザ名(ニックネーム)、メアド、パスワードの設定を求められます。作成完了したら、早速ログインしましょう。

  • http://localhost:3000/admin/infoの管理画面に入る
  • 非常に沢山の設定項目があるが、主に使うのは、検索窓より上の設定項目。
  • 権限」では、ユーザに与えられたロールに応じて何が可能かを設定するエリアです。管理者だけしかルーム作れないように設定などをしたい場合には、変更を加えます。
  • ユーザ」では新規にユーザを追加したり、権限変更したり、削除したりするエリアです
  • インポート」では他のチャットサービスで使っていたデータを取り込む事が可能です。HipchatとSlackに対応しているみたいです。
  • Assets」では、サービスに表示されるロゴなどを変更する画面です。
  • E2E Encryption」は通信を暗号化する為のオプションです。
  • OAuth」では、他のクラウドサービスと連携する為のオプションです。
  • Slack Bridge」は、Slackに橋渡しをするための設定関係があります。
  • アカウント」では各ユーザが実行可能な細かいカスタマイズの変更許可について設定があります。
  • プッシュ通知」ではプッシュ通知をするためのゲートウェイ設定項目があります。
  • メッセージ」では投稿するメッセージに対する規制やフォーマットなどの設定項目があります。
  • メール」では、招待メールなどの通知に使用するSMTPサーバ設定やヘッダー、フッター、テンプレ設定があります。
  • レイアウト」では、RocketChatの見た目のカスタマイズを行うための設定項目があります。
  • 全般」では、REST APIの設定や翻訳などその他の設定項目があります。

Rocket Chatの主な機能

Rocket ChatはSlack風のチャットサービスです。Slackで実装されてるような主要なサービスは持ち合わせております。また、誰が今オンラインなのか?確認することも可能です。管理者設定からこれ以外にも多種多様な機能を追加可能です。

絵文字も簡単に送れる

非常に沢山の絵文字が用意されていますし、IMEで絵文字を送るのも手軽

メンバーリストやメンバー追加もお手軽

ユーザ招待はメールで送られるので、SMTPなどを事前に設定しておく必要があります。

写真や動画を送信可能

初期設定では最大100MBまで送ることが可能。ファイル自体を送れるので、画像や動画以外もアップロード可能。

いいね的なボタン機能

レスの右上にあるちっちゃなボタンから「いいね」的なリアクションを送れます。

プライベートルーム作成

左上のルーム作成ボタンから、作れます。プライベートルームは招待した人以外は参加が出来ない閉じたチャットルームです。

アプリを利用する

Rocket Chatの優れている点はブラウザ上で動くだけでなく、主要な環境用にクライアントアプリが用意されている点です。Android, iOS, デスクトップPC用(Electronで作られてる)やWindows10 UWPアプリと用意されているので、ローカルサーバに接続して使うことが可能です。ここでは、Android版での接続をしてみます。

  1. Rocket Chatアプリをインストールする
  2. 起動するとWelcome to Rocket.Chatの画面が出るので、Connect with a Serverをクリック。
  3. サーバー接続画面が出るので、http:を選び(SSL有効にしてるならばhttps://)、相手のサーバのIPアドレスとポート番号を入れる(例:http://192.168.1.3:3000
  4. 次にログイン画面が出るので、登録したメアドとパスワードを入力してログイン。
  5. ログインが完了すると、チャンネルを作ったり、プロフィール設定、チャットを行う事がすぐに可能です。

図:サーバアドレスを入力する画面

    

図:Slack風で多機能なチャットが出来ます

図:macOS X クライアントで接続してみた

メンテナンス

不具合対策

最新版のRocket Chatに於いて、ファイルのアップロードが出来ない現象が出ています。理由はGridFSの設定の場合、/tmp/ufsのフォルダを経由してファイルを取り込んでいるのですが、これが存在しません・・・また、/tmpディレクトリというのは、OS起動時にクリーンする場所と決められているので、通常は一時ファイル以外は置いていけない場所です。Ubuntu 18.04で発生を確認しています。

ということで、シェルスクリプトなどに以下のコマンドを追加して、起動時に読み込ませるか?gnome-session-properties。これは、Ubuntuが起動後に自動的に起動するアプリケーションを登録しておく為のもので、systemdのような仕組みというより、Windowsのスタートアップフォルダみたいなものです。ここで以下のように登録しておきます。

  1. 右下の●の粒をクリックする
  2. アプリケーション一覧が出てくるので、検索画面でsessionと入れる。「自動起動するアプリケーションの設定」が出てくるので、クリックする
  3. 追加ボタンをクリック
  4. 適当な名前、実行するコマンドの入力(今回はシェルスクリプトを作ってそれを登録してあります)します。
  5. 保存を押して完了

これで、毎回ログイン後に、コマンドの入ったシェルスクリプトが起動し、自動的に/tmp/ufsが作成されて、アップロードができるようになります。Ubuntu Linux 16.04では特になにもせずとも運用できましたので、スクリプトは不要でした。

図:アプリやシェルスクリプトをX起動後に実行します。

#!/bin/sh
mkdir /tmp/ufs
chmod 777 /tmp/ufs

日本語ルーム作成可能にする

デフォルトの設定では英語のルームしか作れません。そこで以下の変更を施して、日本語のルームを作成できるようにします。

  1. 管理に入る
  2. 左サイドバー一番下の「全般」をクリック
  3. UTF8をクリック
  4. UTF8形式名の検証パターンには[ぁ-んァ-ヶーa-zA-Za-zA-Z0-9一-龠-0-9-、。_.]+を入れる
  5. 変更を保存をクリックして完了。

図:面倒な設定ですね・・・

デフォルトアバターの設定をオフにする

デフォルトの設定だとアバターとしてGravatorを取りに行こうとしますが、社内運用等では全く必要ないので、オフにしておきます。

  1. 管理設定に入ります。
  2. アカウントに入ります。
  3. アバターの項目にある「デフォルトのアバターを設定」を「いいえ」に設定
  4. 変更を保存ボタンをクリック。

図:アバター設定はオフにしておく

アップロードした画像がぼやける

localhostでテストしていて忘れがちなのですが、その状態のまま本番で固定IPをセットして運用するとファイルがアップロードできなかったり、できても画像がぼやけた状態のまま、またアップロードしたファイルがダウンロードができないなどの現象が起きます。必ず本番環境でリリースする時には、以下の設定を見直しましょう。

  1. rocketchatの管理設定に入ります。
  2. 左サイドバーの一番下の「全般」の設定に入ります。
  3. 一番上の「サイトURL」が、localhostのままになっているので、本来のURLを入れてあげる(固定IPとポート番号など)
  4. 変更を保存ボタンをクリックする

図:地味に忘れがちな項目です

ファイアウォール関係の設定

  • snapでのインストールはサーバ環境自体がメジャーリリース時に自動アップデートされる仕組みです。
  • 自動でServerが起動しない場合には、sudo systemctl start snap.rocketchat-server.rocketchat-server.serviceで手動で起動します。
  • ファイアウォール設定時には、以下のコマンドでPort3000番を開けるようにする
firewall-cmd --add-port=3000/tcp --zone=public --permanent
firewall-cmd --reload
firewall-cmd --list-all
  • 自動起動設定ファイルは、/usr/lib/systemd/system/rocketchat.serviceに記述されています。
  • サービスで自動起動設定をする場合は、systemctl enable rocketchat.serviceで行う
  • Rocket Chat自体は、Githubで公開されています。

デフォルトポートを変更する

snapでインストールしたRocketChatのデフォルトポートを変更するには、公式ドキュメントによると以下の手順を踏みます。

  1. /var/snap/rocketchat-server/current/に、Caddyfileという設定ファイルを作成する
  2. 以下の設定を書き込む。
  3. sudo systemctl restart snap.rocketchat-server.rocketchat-caddyにて再起動
  4. sudo systemctl status snap.rocketchat-server.rocketchat-caddyにて再起動を確認し、ポート指定でアクセスする
  5. ポートの稼働状況をnetstat -plnatu | grep :80で確認
http://:8080
proxy / localhost:3000 {
  websocket
  transparent
}

上記の設定で、localhostの3000ポートを8080ポートに変更しています。

バックアップ

Rocket Chatのバックアップについてですが、コマンドラインから可能なので、cronと合わせて定期的に外部HDDなどに退避させておくと良いでしょう。

  • バックアップをする時は、sudo snap run rocketchat-server.backupdbを実行
  • リストアする時は、sudo snap run rocketchat-server.restoredb --noIndexRestoreを実行
  • アップロードしてるファイルは、データベースに格納された形で/var/snap/rocketchat-server/common/に保存されていますので、tar cf /tmp/backup/rocket.tarなどをcronに登録しておくと良いでしょう。
  • JSON形式だけでなく、BSON形式になってるものもあるので、mongoDB付属のbsondumpを使ってBSON形式からJSON形式に変換すると二次利用が可能になります。

図:アップロードされたファイルの在り処

社内で使うと接続が途切れる場合

小さな企業内の場合、せいぜいルーターが1個ある程度の環境なので、普通にサーバを立てれば普通に運用が可能だと思いますが、ある程度の組織の場合、途中に存在するルータ、スイッチその他いろいろなものが入っています。ネットワークの設計上早めにTCPのコネクションを解除するような設定が入っていると、立てたRocketChat Serverに他の方が接続できなくなったり、しにくくなったりすることがあります。

そこで、OS側に定期的に生存している旨のパケットを送る設定がありますが、これを少し変更しておくと接続を維持できるようになります。もちろん、OS自体が勝手にスリープしてしまったり、サスペンドしないように設定しておくようにしましょう。今回はUbuntu Linuxをベースに記述します。これらの作業はターミナルとテキストエディタで行います。

logind.confでサスペンドをオフ

//geditでlogind.confを編集
sudo gedit /etc/systemd/logind.conf

geditが起動したら、以下の項目を新規に追記

HandleLidSwitch=ignore

追記したら再起動すればサスペンドしないようになります。

InterfacesにDNS設定

//geditでlogind.confを編集
sudo gedit /etc/network/interfaces

geditが起動したら以下の項目を新規に追記。すでにあるdns-nameserversはコメントアウト。DNSは社内にあるならそれを指定。

dns-nameservers 8.8.8.8

追記したら再起動するだけです。

nsswitch.confでhostsの設定

//geditでnsswitch.confを編集
sudo gedit /etc/nsswitch.conf

geditが起動したら以下の項目に編集しなおす。

hosts: files dns

追記したら再起動するだけです。

resolv.conf関係にDNSを設定

//geditで編集
sudo gedit /etc/resolvconf/resolv.conf.d/base

geditが起動したら、以下の項目を追記する

nameserver 8.8.8.8

さらに以下のコマンドで編集を行う

sudo resolvconf -u
sudo gedit /etc/resolv.conf

起動したら既存のdns-nameserversをコメントアウトして、以下の項目を追記

nameserver 8.8.8.8

追記したら再起動するだけです。

sysctl.confでkeepaliveの設定

最後に一番重要な設定。キープアライブの設定とIPv6の設定を行います。UbuntuはIPv6の設定をオフにしておきます。

//geditでsysctl.confを編集する
sudo gedit /etc/sysctl.conf

geditが起動したら以下の項目を追記する

#IPv6の設定を無効にする
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

#キープアライブの設定
net.ipv4.tcp_keepalive_time = 10
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_intvl = 3

追記したら以下のコマンドで設定を反映する。sysctl -a | grep keepalive_timeは保存した設定を確認するコマンドです。

sudo sysctl -p
sysctl -a | grep keepalive_time

これで即時にキープアライブとIPv6の設定が反映されます。

仮想環境で構築した場合

仮想環境にRocket Chat Serverを構築した場合、通常であれば仮想マシン側に固定IPを割り当てて運用するところですが、ネットワークによってはこれが非常に遅く、またブツ切れを招くことがあります。つながったりつながらなかったり・・・

そこで、親機に固定IPを持たせて、仮想マシン側はNAT接続にすると具合がよかったりします。また、その場合親のポートを仮想マシン側へポートフォワーディングさせる設定が必要です。VirtualBoxの場合、NATで接続する場合には簡単に仮想マシン側へポートフォワーディングが可能です。親の3306にアクセスすると、仮想マシン側の3306につながります。

図:ポートフォワーディングで一気にパフォーマンス改善

発言内容を取得する

REST APIを使用する

Rocket Chatにも様々なREST APIが装備されています。また、β版且つ未公開となってるRealtime APIを用いると、発言内容などを取得出来るようです。メッセージを送ったり、ルームを作ったり様々なAPIが用意されているので、これらを元に自前のアプリケーションに組み込む事が可能です。メッセージ部分に関する取り込みはこちらを参照

OAuth2.0認証周りはこちらにドキュメントがあります。いずれGoogle Apps Scriptで接続するための仕組みを作ってみたいと思います。

Excelで取り出す

Rocket ChatはMongoDBというNoSQLなデータベースを採用しています。そのままではJSONオブジェクトなので、JavaScriptとは相性が良さそうです。しかし、VBAから扱うには、VBA-JSONなどのライブラリを使って、JSONをパースする仕組みが必要になります。

前項でバックアップを実行して取得したバックアップデータからメッセージをExcelで取り出したいケースもあるかと思います。以下の手順で取り出すことが可能です。まずは、BSONをJSONに変換します。この変換プログラムであるbsondumpですが、64bitでないと動きません・・・

  1. バックアップファイルであるtar.gzファイルを解凍する
  2. mongodbよりzip形式のファイル群をダウンロードして解凍する(lastest.zipという名のファイル)
  3. 解凍したファイル内にbsondumpという実行ファイルがあるのでみつける。
  4. bsondumpと同じフォルダに1.で解凍した中身にある「rocketchat_message.bson」をコピーする
  5. 以下のコマンドラインでBSONをJSONに変換する
//BSONをJSONに変換する
bsondump.exe rocketchat_message.bson > message.json

そして、変換したJSONはVBA-JSONなどでプログラムから解析して取得するのも良いのですが、以下の手法でExcelに取り込むことが可能です。

  1. Excel2016ではPowerQueryが標準装備になりましたが、ソレ以前のExcelではPowerQueryを別途インストールが必要です。
  2. Excel2013の場合、PowerQueryタブ内の「Webから」をクリック
  3. パスはmessage.jsonのある場所のフルパスを入れてとりあえず、OKを実行
  4. 取り込みに失敗するので、編集をクリック。
  5. 詳細をクリックして、元のファイルの文字コードはUTF-8を指定する。もし、BOMなしのUTF8ファイルならば、予めBOM有りのUTF8じゃないと取り込めないです。
  6. OKを押すと開始
  7. テーブルに変換をクリックする
  8. 変換されたのちに、Nameの列のフィルタっぽいのをクリックする
  9. msgを選ぶとメッセージの部分がvalue列で取り出せます。
  10. 閉じて読み込むをクリックするとExcelのシートにテーブルとして取り込めます。
  11. ただし、時々、余計な文字があるといわれ取り込めないケースがあります。その時は素直に、VBAでプログラムを組みましょう。

図:PowerQueryを使って読み込む

図:Query編集画面

JSONファイルを分解するExcelプログラム

今回とある機会で、前項のBSON=>JSONへ変換したデータの塊を、Excelのシートに綺麗に変換する為のプログラムを作成しました。JSONファイルをこのVBAプログラムで開くと、メッセージID、部屋ID、メッセージ、添付ファイル名を取り出して一覧にしてくれます。

コード自体は非常にシンプルです。メンションなどいろいろ考慮すべき要素はありますが、今回は純粋にユーザのメッセージを塊から取り出すだけです。リボンにボタンが1個あるだけなので、簡単仕様です。

図:ボタン1個だけのシンプル設計です

'Rocket ChatのJSONファイルを変換するメインルーチン
Public Function rocketjson()
    '変数の宣言
    Dim dlg As Object, boolResult As Boolean
    Dim jsonfile As String
    
    'オブジェクト変数にFileDialogオブジェクトを代入
    Set dlg = Application.FileDialog(msoFileDialogOpen)

    'JSONをパースする用の変数
    Dim doc
    Dim JsonObject As Object
    Dim kinoko As Variant
    Dim dlength As Variant
    Dim i As Variant
    Dim fileflg As Boolean
    fileflg = False

    'レコード要素用変数
    Dim rid As Variant
    Dim mid As Variant
    Dim msgstr As Variant
    Dim attachman As Variant
    Dim atdata

    'FileDialogオブジェクトの各種プロパティを設定
    With dlg
        .AllowMultiSelect = False
        .Filters.Clear
        .Filters.Add "解析対象のJSONファイル", "*.json"
        .FilterIndex = 3
        .Title = "変換されたRocketChatデータ"
        .ButtonName = "変換する"
    End With
 
    'ファイルを開くダイアログを開く
    boolResult = dlg.Show

    If boolResult Then
        'インポートルーチンに渡す
        jsonfile = dlg.SelectedItems(1)
    Else
        '[キャンセル]ボタンが押された場合の処理
        MsgBox "シートデータの取り込みはキャンセルされました。"
        Exit Function
    End If
    
    'ワークシートのデータをクリアする
    Dim lastrow As Variant
    lastrow = Worksheets("rocket").UsedRange.Rows.Count
    
    If lastrow = 1 Then
        'タイトル行だけなので何もしない
    Else
        '2行目移行を削除する
        Worksheets("rocket").Range("A2:D" & lastrow).Clear
    End If

    'バッファにJSONファイルを読み込む
    Dim buf As String
    With CreateObject("ADODB.Stream")
        .Charset = "UTF-8"
        .Open
        .LoadFromFile jsonfile
        buf = .ReadText
        .Close
    End With
    
    '連想配列にし、LF改行コードをカンマに変換して、CRLF改行コードを追加
    buf = "{'kinoko':[" & buf & "]}"
    buf = Replace(buf, vbLf, vbCrLf)
    buf = Replace(buf, vbCrLf, "," & vbCrLf)

    'JSON受信用
    'HTMLDocumentを取得
    Set doc = CreateObject("HtmlFile")
    'scriptタグを追加
    doc.Write "<script>document.JsonParse=function (s) {return eval('(' + s + ')');}</script>"
    
    'JSONをパースする
    Set JsonObject = doc.JsonParse(buf)
    
    'kinoko部分の連想配列を取得する
    Set o = CallByName(JsonObject, "kinoko", VbGet)
    
    'データの件数を調べる
    dlength = CallByName(o, "length", VbGet)
    
    'ループで値を取り出す
    For i = 0 To dlength - 1
        'fileflg初期化
        fileflg = False

        '個別レコードを取得する
        Set o2 = CallByName(o, i, VbGet)

        'file要素があるかどうかチェック
        fileflg = keycheck("file", buf, i + 1)

        'レコード要素を取得する
        rid = CallByName(o2, "rid", VbGet)
        mid = CallByName(o2, "_id", VbGet)
        msgstr = CallByName(o2, "msg", VbGet)
        
        'msgの改行コードを変換
        msgstr = Replace(msgstr, "\n", vbVCrLf)
        
        'fileflgがtrueならば添付ファイル名を取得する
        If fileflg = True Then
            Set atdata = CallByName(o2, "file", VbGet)
            attachman = CallByName(atdata, "name", VbGet)
            Debug.Print attachman
        Else
            attachman = ""
        End If
        
        'シートに書き込む
        With Worksheets("rocket")
            .Cells(i + 2, 1).Value = mid
            .Cells(i + 2, 2).Value = rid
            .Cells(i + 2, 3).Value = msgstr
            .Cells(i + 2, 4).Value = attachman
        End With

    Next i
    
    '終了処理
    MsgBox "データの変換が完了しました。"
End Function

'指定のキーが要素の中にあるかどうかをチェック
Public Function keycheck(keyname As String, json As Variant, keynum As Variant) As Boolean

    Dim Parse As Object
    Dim Key As Variant
    Dim keyflg As Boolean
    
    keyflg = False

    Set Parse = JsonConverter.ParseJson(json)
    
    '指定のレコードの要素数を調べる
    'Debug.Print Parse("kinoko")(keynum).Count
    
    For Each Key In Parse("kinoko")(keynum)
        
        If Key = keyname Then
            keyflg = True
            Exit For
        End If
        
    Next

    keycheck = keyflg
End Function

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)