カテゴリー
サーバー

FreeBSD 12 とApacheでJitsi Meetを動かしてみた

Ubuntuで安定稼働するアプリケーションであるとは知りながら、一番好きなFreeBSDで動かすことに挑戦しました。

ウェブサーバーにもnginxではなくApacheを使いました。理由はただ一つ。慣れているからです。

結果、何とか動かすことに成功したので、成功した時点での設定内容をメモしておきます。

This is an instant note when I successfully set up Jitsi Meet with Apache 2.4 on FreeBSD 12.

I don’t think engineers need translations but with my pleasure translate words in English.

先にお断りを書いておきます。

  • 暗号化されない経路を極力作らないような設定を目指したので、暗号化に関心がない方の助けにはならないかもしれません。
  • websocketを使ってみたかったのですが、うまく動かせませんでした。掲載した設定の中にもコメントアウトで残してあります。
  • どの設定にどういう意味があるのかの説明は、大変なので省略します。
  • 困ったらマニュアルに戻ってください。なんだかんだ言って、基本はここにあります。
  • This article in which I wrote about full encryption may not help you if you don’t want the full encrypted communications.
  • I gave up using websocket, but remained the config lines in comments.
  • I don’t add detailed explanations because it’s too much tough in this big article.
  • Back to the manual when in trouble.

pkg

おそらく、以下のコマンドで必要はものはすべて揃います。

# pkg install jitsi-videobridge prosody jicofo

Apacheの設定

Jitsi用のバーチャルホストを作成します。

<VirtualHost _default_:443>
    DocumentRoot /usr/local/www/jitsi-meet
    ServerName jitsi.midgen.asia
    ServerAdmin ryow@midgen.asia
    ErrorLog "/var/log/httpd/jitsi.midgen.asia-error.log"
    TransferLog "/var/log/httpd/jitsi.midgen.asia-access.log"
    CustomLog "/var/log/httpd/jitsi.midgen.asia-ssl_request.log" \
        "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    Header always set Strict-Transport-Security "max-age=63072000"
    ErrorDocument 404 /static/404.html

    SSLEngine on
    SSLCertificateFile "/usr/local/etc/letsencrypt/live/jitsi.midgen.asia/fullchain.pem"
    SSLCertificateKeyFile "/usr/local/etc/letsencrypt/live/jitsi.midgen.asia/privkey.pem"

    SSLProxyEngine on
    ProxyPreserveHost on
    ProxyPass /http-bind https://localhost:5281/http-bind/
    ProxyPassReverse /http-bind https://localhost:5281/http-bind/
    #ProxyPass /xmpp-websocket wss://localhost:5281/xmpp-websocket
    #ProxyPassReverse /xmpp-websocket wss://localhost:5281/xmpp-websocket
    #ProxyPassMatch ^/colibri-ws/default-id http://localhost:9090
</VirtualHost>

通常ここにRewriteRuleを書きますが、わたしは日本語のトークルームを作成できるようにするために.htaccessに書きます。Wordpressに倣った書き方です。

As a not common way, I write RewriteRule/s in .htaccess to make it possible to create rooms with Japanese names (multi-byte strings). They are from WordPress.

# vi /usr/local/www/jitsi-meet/.htaccess
Options MultiViews Includes SymLinksIfOwnerMatch
AddOutputFilter INCLUDES .html

# WordPress-like RewriteRule settings.
RewriteEngine On
RewriteBase /
RewriteRule ^$ /index.html [L]
RewriteRule ^/lang/countries(.+?)\.json$ /lang/languages$1.json [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Prosodyの設定

Prosodyの設定は主にモジュール、バーチャルホスト、コンポーネントから構成されています。

ProsodyはProsodyというユーザーとグループで実行されるようにできているので、/var/run/prosodyや/var/log/prosodyというようなProsodyという書き込み可能なディレクトリを用意する必要があります。

Prosody runs as prosody:prosody, so we have to create writable directory “/var/run/prosody” and “/var/log/prosody”.

---------- Server-wide settings ----------
admins = { "focus@auth.jitsi.midgen.asia" }
modules_enabled = {

    -- Generally required
        "roster"; -- Allow users to have a roster. Recommended ;)
        "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
        "tls"; -- Add support for secure TLS on c2s/s2s connections
        "dialback"; -- s2s dialback support
        "disco"; -- Service discovery

    -- Not essential, but recommended
        "carbons"; -- Keep multiple clients in sync
        "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
        "private"; -- Private XML storage (for room bookmarks, etc.)
        "blocklist"; -- Allow users to block communications with other users
        "vcard4"; -- User profiles (stored in PEP)
        "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard

    -- Nice to have
        "version"; -- Replies to server version requests
        "uptime"; -- Report how long server has been running
        "time"; -- Let others know the time here on this server
        "ping"; -- Replies to XMPP pings with pongs
        "register"; -- Allow users to register on this server using a client and change passwords
        "mam"; -- Store messages in an archive and allow users to access it
        --"csi_simple"; -- Simple Mobile optimizations

    -- Admin interfaces
        "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
        --"admin_telnet"; -- Opens telnet console interface on localhost port 5582

    -- HTTP modules
        --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
        --"websocket"; -- XMPP over WebSockets
        --"http_files"; -- Serve static files from a directory over HTTP

    -- Other specific functionality
        --"limits"; -- Enable bandwidth limiting for XMPP connections
        --"groups"; -- Shared roster support
        --"server_contact_info"; -- Publish contact information for this service
        --"announce"; -- Send announcement to all online users
        --"welcome"; -- Welcome users who register accounts
        --"watchregistrations"; -- Alert admins of registrations
        --"motd"; -- Send a message to users when they log in
        --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
        --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use

        "external_services";
        "turncredentials";
}

allow_registration = false
c2s_require_encryption = true
s2s_require_encryption = true
s2s_secure_auth = false
authentication = "internal_hashed"
archive_expires_after = "3d" -- Remove archived messages after 1 week
log = {
    info = "/var/log/prosody/info.log"; -- Change 'info' to 'debug' for verbose logging
    error = "/var/log/prosody/error.log";
}
statistics = "internal"
https_certificate = "certs/jitsi.midgen.asia.crt"
pidfile = "/var/run/prosody/prosody.pid"
consider_websocket_secure = true

turncredentials_host = "localhost"
turncredentials_port = 5349
turncredentials_secret = "TURNSERVER_SECRET"

----------- Virtual hosts -----------
VirtualHost "jitsi.midgen.asia"
    key = "certs/jitsi.midgen.asia.key";
    certificate = "certs/jitsi.midgen.asia.crt";
    authentication = "anonymous"
    modules_enabled = {
        "bosh";
        "http_files";
        "pubsub";
    }
VirtualHost "auth.jitsi.midgen.asia"
    key = "certs/auth.jitsi.midgen.asia.key";
    certificate = "certs/auth.jitsi.midgen.asia.crt";

------ Components ------
Component "conference.jitsi.midgen.asia" "muc"
    key = "certs/conference.jitsi.midgen.asia.key";
    certificate = "certs/conference.jitsi.midgen.asia.crt";

Component "jitsi-videobridge.jitsi.midgen.asia"
    component_secret = "JVB_SECRET"
    key = "certs/jitsi-videobridge.jitsi.midgen.asia.key";
    certificate = "certs/jitsi-videobridge.jitsi.midgen.asia.crt";

Component "focus.jitsi.midgen.asia"
    component_secret = "JICOFO_SECRET"
    key = "certs/focus.jitsi.midgen.asia.key";
    certificate = "certs/focus.jitsi.midgen.asia.crt";

Certificates (証明書の設定)

証明書を設定しないと煩雑なエラーが発生しますので、設定しましょう。Certbot(Let’s Encrypt)を使えば証明書は無料です。

Certificates must be installed for suppressing noisy errors. Certbot (Let’s Encrypt) are useful for free.

# prosodyctl --root cert import focus.jitsi.midgen.asia /usr/local/etc/letsencrypt/live/focus.jitsi.midgen.asia/fullchain.pem
Imported certificate and key for hosts focus.jitsi.midgen.asia

# prosodyctl --root cert import jitsi.midgen.asia /usr/local/etc/letsencrypt/live/jitsi.midgen.asia/fullchain.pem
Imported certificate and key for hosts jitsi.midgen.asia

# prosodyctl --root cert import conference.jitsi.midgen.asia /usr/local/etc/letsencrypt/live/conference.jitsi.midgen.asia/fullchain.pem
Imported certificate and key for hosts conference.jitsi.midgen.asia

# prosodyctl --root cert import jitsi-videobridge.jitsi.midgen.asia /usr/local/etc/letsencrypt/live/jitsi-videobridge.jitsi.midgen.asia/fullchain.pem
Imported certificate and key for hosts jitsi-videobridge.jitsi.midgen.asia

# prosodyctl --root cert import auth.jitsi.midgen.asia /usr/local/etc/letsencrypt/live/auth.jitsi.midgen.asia/fullchain.pem
Imported certificate and key for hosts auth.jitsi.midgen.asia

設定を確認するコマンドがありますので、積極的に使いましょう。

There is a command to check settings, so aggressively use it.

# prosodyctl check
Checking config...
Done.

Checking DNS for component jitsi-videobridge.jitsi.midgen.asia...
    jitsi-videobridge.jitsi.midgen.asia A record points to internal address, external connections might fail

Checking DNS for host jitsi.midgen.asia...
    jitsi.midgen.asia A record points to internal address, external connections might fail

Checking DNS for component conference.jitsi.midgen.asia...
    conference.jitsi.midgen.asia A record points to internal address, external connections might fail

Checking DNS for component focus.jitsi.midgen.asia...
    focus.jitsi.midgen.asia A record points to internal address, external connections might fail

Checking DNS for host auth.jitsi.midgen.asia...
    auth.jitsi.midgen.asia A record points to internal address, external connections might fail

Checking certificates...
Checking certificate for jitsi-videobridge.jitsi.midgen.asia
  Certificate: /usr/local/etc/prosody/certs/jitsi-videobridge.jitsi.midgen.asia.crt
Checking certificate for jitsi.midgen.asia
  Certificate: /usr/local/etc/prosody/certs/jitsi.midgen.asia.crt
Checking certificate for conference.jitsi.midgen.asia
  Certificate: /usr/local/etc/prosody/certs/conference.jitsi.midgen.asia.crt
Checking certificate for focus.jitsi.midgen.asia
  Certificate: /usr/local/etc/prosody/certs/focus.jitsi.midgen.asia.crt
Checking certificate for auth.jitsi.midgen.asia
  Certificate: /usr/local/etc/prosody/certs/auth.jitsi.midgen.asia.crt

All checks passed, congratulations!

Javaが証明書情報を参照できるようにする必要があります。以下のようにします。

We have to make Java refer to the certificates like this.

# keytool -noprompt -keystore /usr/local/etc/jitsi/jicofo/keystores/jitsiTrustStore.jks -importcert -alias auth.jitsi.midgen.asia -file /usr/local/etc/prosody/certs/auth.jitsi.midgen.asia.crt
キーストアのパスワードを入力してください:
証明書がキーストアに追加されました

# keytool -noprompt -keystore /usr/local/etc/jitsi/jicofo/keystores/jitsiTrustStore.jks -importcert -alias focus.jitsi.midgen.asia -file /usr/local/etc/prosody/certs/focus.jitsi.midgen.asia.crt
キーストアのパスワードを入力してください:
証明書がキーストアに追加されました

# keytool -noprompt -keystore /usr/local/etc/jitsi/jicofo/keystores/jitsiTrustStore.jks -importcert -alias jitsi.midgen.asia -file /usr/local/etc/prosody/certs/jitsi.midgen.asia.crt
キーストアのパスワードを入力してください:
証明書がキーストアに追加されました


# keytool -noprompt -keystore /usr/local/etc/jitsi/jicofo/keystores/jitsiTrustStore.jks -importcert -alias conference.jitsi.midgen.asia -file /usr/local/etc/prosody/certs/conference.jitsi.midgen.asia.crt
キーストアのパスワードを入力してください:
証明書がキーストアに追加されました

# keytool -noprompt -keystore /usr/local/etc/jitsi/jicofo/keystores/jitsiTrustStore.jks -importcert -alias jitsi-videobridge.jitsi.midgen.asia -file /usr/local/etc/prosody/certs/jitsi-videobridge.jitsi.midgen.asia.crt
キーストアのパスワードを入力してください:
証明書がキーストアに追加されました

Authentication (認証の設定)

トークルームを作成する際の認証情報は、Prosodyで管理します。これをしないと認証エラーになるはずです。

The authentication information to create rooms is handled by Prosody. Authentication failures should occur if you don’t do this.

# prosodyctl adduser focus@auth.jitsi.midgen.asia
Password: [SECRET1 and Enter]

Jicofo

# vi /usr/local/etc/jitsi/jicofo/jicofo.conf
JVB_XMPP_HOST=localhost
JVB_XMPP_DOMAIN=jitsi.midgen.asia
JVB_XMPP_PORT=5347
JVB_XMPP_SECRET=SECRET1
JVB_XMPP_USER_DOMAIN=auth.jitsi.midgen.asia
JVB_XMPP_USER_NAME=focus
JVB_XMPP_USER_SECRET=SECRET1

MAX_MEMORY=2048m

Prosodyの認証情報はJicofoにも必要です。JVB_XMPP_USER_NAMEとJVB_XMPP_USER_DOMAINとJVB_XMPP_USER_SECRETで作成します。

Authentication information of Prosody is needed to Jicofo. It is made from JVB_XMPP_USER_NAME, JVB_XMPP_USER_DOMAIN and JVB_XMPP_USER_SECRET.

# prosodyctl adduser <JVB_XMPP_USER_NAME>@auth.jitsi.midgen.asia
Password: [<JVB_XMPP_USER_SECRET> and Enter]

Videobridge (Jitsi Video Bridge)

音声と映像を司るサービスです。

# vi /usr/local/etc/jitsi/videobridge/jitsi-videobridge.conf
JVB_XMPP_HOST=localhost
JVB_XMPP_DOMAIN=jitsi.midgen.asia
JVB_XMPP_PORT=5347
JVB_XMPP_SECRET=JVB_SECRET
VIDEOBRIDGE_MAX_MEMORY=4096m

JVBとJicofoの共通設定

Jitsi VideoBridge(JVB)とJicofoには共通設定ファイルのようなものがあります。

最後の二行はNAT環境下では必ず必要です。

JVB and Jicofo have a “common” configuration file. The last two lines are necessary for the server behind NAT.

# vi /usr/local/etc/jitsi/jicofo/sip-communicator.properties
org.jitsi.videobridge.DISABLE_TCP_HARVESTER=true
org.jitsi.videobridge.PUBSUB_NODE=sharedStatsNode
org.jitsi.videobridge.PUBSUB_SERVICE=jitsi.midgen.asia
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=pubsub

org.jitsi.jicofo.auth.URL=XMPP:auth.jitsi.midgen.asia
org.jitsi.jicofo.STATS_PUBSUB_NODE=sharedStatsNode

# Running behind NAT
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=10.0.129.80
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=114.19.84.254

また、このファイルはJVBとJicofoの両方のホームディレクトリで読み込み可能なファイルでないといけませんが、インストール直後はJicofoの方にしかないので、JVBの方からリンクを張ります。それぞれのスタートアップスクリプトを読むと、この作業の必要性がわかります。

And this file must be stored in the home directory of both, but only Jicofo has one after installation, so create a link to the one from JVB home directory. You can find the necessity of this from their startup script.

# ln -s /usr/local/etc/jitsi/jicofo/sip-communicator.properties /usr/local/etc/jitsi/videobridge/sip-communicator.properties

Turnserver

jitsi.netではなく自前のネットワークでピアツーピアを実現したい場合は、TURN server(coTURN)をインストールする必要があります。pkgでもインストールできますが、MySQL5.7を要求されます。わたしはMySQL8.0を入れてしまってあった関係上、ソースコードからビルドしました。

If you want to set up Jitsi system completely DIY, need to install TURN server(coTURN). pkg has such package, but I didn’t choose it because it requires MySLQL5.7, while I installed MySQL 8.0. So I built from its source.

# cd /tmp
# git clone https://github.com/coturn/coturn.git
# cd coturn
# ./configure --prefix=/usr/local
# make
# make install

スタートアップスクリプトはJicofoのものを改造して作りました。

I created the startup script from Jicofo’s one.

# vi /usr/local/etc/rc.d/turnserver
#!/bin/sh
#
# turnserver_enable:        run turnserver server (default=NO)
# turnserver_flags:        additional flags for turnserver server (default="")
#

. /etc/rc.subr

name="turnserver"
rcvar=${name}_enable

load_rc_config "${name}"

: ${turnserver_enable="NO"}
: ${turnserver_flags=""}

command="/usr/local/bin/turnserver"
pidfile="/var/run/turnserver.pid"

start_cmd=${name}_start
stop_cmd=${name}_stop
status_cmd=${name}_status
restart_cmd=${name}_restart

turnserver_start()
{
        ${command} ${turnserver_flags} 2>&1 /dev/null
        echo "Started"
}

turnserver_stop()
{
        if [ -f ${pidfile} ]
        then
                kill `cat ${pidfile}`
                rm ${pidfile}
                echo "Stopped"
        fi
}

turnserver_status()
{
        # If running, show pid
        if [ -f ${pidfile} ]
        then
                echo "${name} is running as pid" `cat ${pidfile}`
        else
                echo "${name} is not running"
        fi
}

turnserver_restart()
{
        echo "Performing restart"
        turnserver_stop
        sleep 3
        turnserver_start
}

run_rc_command "$1"

設定はこんな感じ。

# vi /usr/local/etc/jitsi/jicofo/jicofo.conf
tls-listening-port=5349
listening-ip=192.168.1.180
use-auth-secret
static-auth-secret=TURNSERVER_SECRET
realm=turn.midgen.asia
cert=/usr/local/etc/letsencrypt/live/turn.midgen.asia/fullchain.pem
pkey=/usr/local/etc/letsencrypt/live/turn.midgen.asia/privkey.pem
log-file=/var/log/turnserver.log
pidfile="/var/run/turnserver.pid"
no-cli

config.js

フロント側のファイルです。こんな感じです。

var config = {
    hosts: {
        domain: 'jitsi.midgen.asia',
        authdomain: 'auth.jitsi.midgen.asia',
        focus: 'focus.jitsi.midgen.asia',
        muc: 'conference.jitsi.midgen.asia',
    },
    bosh: '//jitsi.midgen.asia/http-bind',
    clientNode: 'http://jitsi.org/jitsimeet',
    focusUserJid: 'focus@auth.jitsi.midgen.asia',
    testing: {
        p2pTestMode: false
    },
    webrtcIceUdpDisable: false,
    webrtcIceTcpDisable: false,
    enableNoAudioDetection: true,
    enableNoisyMicDetection: true,
    desktopSharingChromeExtId: null,
    desktopSharingChromeSources: [ 'screen', 'window', 'tab' ],
    desktopSharingChromeMinExtVersion: '0.1',
    channelLastN: -1,
    useIPv6: true,
    openBridgeChannel: true,
    useNicks: false,
    enableWelcomePage: true,
    defaultLanguage: 'ja',
    enableUserRolesBasedOnToken: false,
    p2p: {
        enabled: true,
        useStunTurn: true,
        stunServers: [
            { urls: 'stun:jitsi.midgen.asia:5349' }
        ],
        preferH264: true
    },
};

以上です。もし不明点があったらわかる範囲でお答えします。

That’s all. If you have any questions, ask me.

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください