Gift history
Please access after login.


Wait a moment...

Symbolテストネットノードを建ててみた (v0.10.x Hippo on Ubuntu Server 18.04)

9998
10
2020-09-27 01:05:16
0.00 mXYM
(0)

「またノード構築記事を書いたんですか」というくらいにまた書きました。

ようやく待望のファイナライズ対応版が v0.10.x としてリリースされ、周辺ツールも整備されました。

現時点の情報では、これでメインネットとして稼働させるための仕様はすべて盛り込まれたことになります。

さらに今回は Symbol Bootstrap というツールが仲間に加わったので、今回はそれを使用したセットアップです。

なお、タイトルには Ubuntu Server 18.04 とありますが、

Node.js と Docker / Docker Compose がインストールできれば、

CentOS や他のディストリビューションでも同じような作業で動かせると思います。

なお、個人的になるべく手間が少なく、かつ効果的・効率的な構築を目指した手順です。

これが正解ということではないので、必要に応じて作業手順を変更したり、異なる構成をしてみてください。

※この記事は、ツールのアップデートがまだまだ入っているので都度加筆修正を行っています。

 

ちなみに参考までに、これまでに書いた記事です。

必要なソフトウェアのインストール

Ubuntu 18.04 に SSH でログインをしており、

root の権限に昇格している状態を前提とし、手順を示していきます。

手間を省くため root で作業しちゃえばいいじゃん、とちょっと手抜きなスタンスでいきます。

この辺は各自のスタンスにおまかせします。

AWS EC2、ConoHa、WebArena Indio、Time4VPS 等お好きな VPS レンタルサービスをご利用ください。

推奨スペックとしては CPU: 2コア / メモリ: 4GB / ディスク: 20GB となっています。

各項目がこれよりも高いスペックを用意してください。

下回っている場合、安定してノードを維持できない可能性があります。

Symbol Bootstrap とは

色々な用途 (プライベート/パブリック、Peer / API) Symbol ノードの設定ファイルを生成するツールです。

また、設定の生成だけでなく、コンテナの起動・停止なども提供します。

これまでは symbol-testnet-bootstrap という設定一式を使用して築城していました。

symbol-bootstrap の登場により、こちらはこれ以上更新されないかもしれません。

この設定一式を生成するツールだと考えてくれればよいです。

以降の内容はほとんど公式ドキュメントの手順と同じです。

現時点ではまだ日本語化されていませんが、元情報も確認してみてください。

コマンド入力サンプルの注釈

  • # で始まる行はコマンドの入力です。
  • それ以外はターミナルへの出力です。

Node.js/ npm をインストール

Symbol Bootstrap の動作には Node.js / npm が必要です。

そのままインストールすると古い Node.js がインストールされるので、ここでは最新版の 14.x 系が入るようにしています。

# curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
# apt-get install -y nodejs
# npm install -g npm@latest # <- ついでにnpmを最新版にアップデート

インストールが済んだらバージョンを確認してみます。

# node -v
v14.15.0
# npm -v
6.14.8

インストールできたかをバージョンを表示して確認してください。

Symbol Bootstrap をインストール

# npm install -g symbol-bootstrap@0.2.0
# symbol-bootstrap -v
symbol-bootstrap/0.2.0 linux-x64 node-v14.15.0

インストールして、バージョンを確認してみます。

ここでは、v0.2.0 を使用していますが、今後記事の更新でより新しいバージョンを使用するかもしれません。

Docker / Docker Compose のインストール

ここら辺は、以前の記事と同じなので、コマンドだけ貼っておきます。

# Install docker
apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update -y && apt-get install -y docker-ce docker-ce-cli containerd.io

# Install docker-compose
curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

他のディストリビューション OS を利用する場合は、その OS のインストール方法に従ってください。

Docker コンテナログファイルの設定

デフォルトの設定の場合、コンテナのログが延々と記録され続けてしまい、

長く動かしているとログファイルが容量を喰ってしまいます。

ログの出力先を journald に変更することで「docker logs」と「journald」で参照できるようにします。

Ubuntu 18.04 であれば journald へ渡したログ出力は、

いい感じに(古いログを消して)容量を調整してくれるはずなので、

ログでサーバが埋まってしまうことを防止できます。

# echo '{"log-driver":"journald","log-opts":{"tag":"docker/{{.ImageName}}/{{.Name}}"}}' > /etc/docker/daemon.json
# systemctl restart docker

※ 「/」を「/」に置き換えてください。nemlog で保存ができない問題の回避です。

「docker-compose.yml」に設定をもたせることもできますが、

どうせ Symbol ノードのためだけのサーバなのでグローバル設定を変えてしまいました。

「/etc/docker/daemon.json」というファイルで docker の設定を変更できます。

ファイルを作ったら、docker を再起動して反映しておきます。

 

コンテナのログを参照したい場合は、

# journalctl -f CONTAINER_NAME=api-node

「journalctl」コマンドで「CONTAINER_NAME」でコンテナ名を指定することでコンテナのログが表示できます。

または「target/docker」に移動して、

# docker-compose logs -f api-node

とすることでも表示できます。お好みの方法で参照してください。

(コンテナが動き出してから流れるので、以後の操作を行った後に試してみてください)

 

ここまでで、実行環境のインストールは完了です。

カスタム設定ファイルの作成

設定ファイルを配置する場所を今回は「/opt/symbol-bootstrap」とします。

以後、このディレクトリがカレントディレクトリである前提とします。

# mkdir -p /opt/symbol-bootstrap
# cd /opt/symbol-bootstrap

symbol-bootstrap を使って設定を生成しますが、その前に、流し込む設定を作成します。

カスタムプリセットを読み込ませて、デフォルト値を変更します。

「my-preset.yml」として次のようなファイルを作成します。

nodes:
    -
        friendlyName: niz-dual-1
gateways:
    -
        throttlingBurst: 80
        throttlingRate: 40

フレンドリーネーム(「niz-dual-1」の部分はお好きな名前にしてください)の変更、

APIゲートウェイの同時接続数上限(デフォルトは35)や秒間リクエスト数上限(デフォルトは20)を増やしてみました。

このあたりの設定はお好みでどうぞ。

設定ファイルの作成

テストネット向けの DUAL ノード (Peer+API) の設定にこの設定を流し込んで、ファイル群を生成します。

# symbol-bootstrap config -p testnet -a dual -c my-preset.yml
                            _               _           _                       _           _                          
  ___   _   _   _ __ ___   | |__     ___   | |         | |__     ___     ___   | |_   ___  | |_   _ __    __ _   _ __  
 / __| | | | | | '_ ` _ \  | '_ \   / _ \  | |  _____  | '_ \   / _ \   / _ \  | __| / __| | __| | '__|  / _` | | '_ \ 
 \__ \ | |_| | | | | | | | | |_) | | (_) | | | |_____| | |_) | | (_) | | (_) | | |_  \__ \ | |_  | |    | (_| | | |_) |
 |___/  \__, | |_| |_| |_| |_.__/   \___/  |_|         |_.__/   \___/   \___/   \__| |___/  \__| |_|     \__,_| | .__/ 
        |___/                                                                                                   |_|    
2020-09-26T15:40:23.808Z info [SYSTEM_LOG]     Generating config from preset testnet
2020-09-26T15:40:23.810Z info [SYSTEM_LOG]     Assembly preset dual
2020-09-26T15:40:23.985Z info [SYSTEM_LOG]     User for docker resolved: 0:0

2020-09-26T15:40:23.987Z info [SYSTEM_LOG]     Running image using Exec: symbolplatform/symbol-server:tools-gcc-0.10.0.3 bash -c cd /data && bash createCertificate.sh
2020-09-26T15:41:41.817Z info [SYSTEM_LOG]     Certificate for node api-node created
2020-09-26T15:41:41.955Z info [SYSTEM_LOG]     Non-voting node api-node.
2020-09-26T15:41:41.987Z info [SYSTEM_LOG]     Configuration generated.

「symbol-bootstrap config -p testnet -a dual -c my-preset.yml」を実行します。

実行すると「target」というディレクトリが生成され、

その中に起動時に読み込まれる各種設定とそのディレクトリも生成されます。

「-p testnet」はテストネットのプリセット設定で設定を生成します。

指定しないとプライベートネットワーク用の設定が生成されてしまいます。

「-a dual」は Peer + API を構成するオプションです。

他にも「peer」と「api」を指定でき、目的に合わせたノード構成を指定するものです。

「-c」オプションでカスタムプリセットを読み込みます。

testnetのプリセット値をこのカスタム値が上書きします。

friendlyName = niz-dual-1

実行したら「target/nodes/api-node/userconfig/resources/config-node.properties」を

エディタで開き「friendlyName」の項目に反映されているか確認してみてください。

カスタムプリセットについてのガイドも参照しておくと、いろいろできることが伺えると思います。

上記に載っていない箇所について、プリセットのファイルはここにあるので、

これを参考にどうやってカスタムプリセットを書けばいいかの参考にしてください。

*.mustache ファイルにも変数名が埋め込まれているので、ここも参考になります。

docker-compose.yml の生成

config オプションはあくまで設定ファイルを生成するだけなので、コンテナ起動設定は含まれません。

次に、compose オプションを使います。

# symbol-bootstrap compose
                            _               _           _                       _           _                          
  ___   _   _   _ __ ___   | |__     ___   | |         | |__     ___     ___   | |_   ___  | |_   _ __    __ _   _ __  
 / __| | | | | | '_ ` _ \  | '_ \   / _ \  | |  _____  | '_ \   / _ \   / _ \  | __| / __| | __| | '__|  / _` | | '_ \ 
 \__ \ | |_| | | | | | | | | |_) | | (_) | | | |_____| | |_) | | (_) | | (_) | | |_  \__ \ | |_  | |    | (_| | | |_) |
 |___/  \__, | |_| |_| |_| |_.__/   \___/  |_|         |_.__/   \___/   \___/   \__| |___/  \__| |_|     \__,_| | .__/ 
        |___/                                                                                                   |_|    
2020-09-26T15:43:55.201Z info [SYSTEM_LOG]     User for docker resolved: 0:0

2020-09-26T15:43:55.203Z info [SYSTEM_LOG]     creating docker-compose.yml from last used profile.
2020-09-26T15:43:55.209Z info [SYSTEM_LOG]     docker-compose.yml file created /opt/symbol-bootstrap/target/docker/docker-compose.yml

「target/docker/docker-compose.yml」が生成されました。

こちらも編集する必要はないかと思いますが、必要があれば編集してください。

バグ回避

Symbol Bootstrap v0.2.0 により生成されるファイルにバグがあり、

「api-broker」コンテナのダウンが頻発する問題があるようです。

「target/docker/mongo/mongors.sh」を開いて、

ファイルの先頭あたりにある「set -e」の行を削除してください。

このような内容のファイルがあるはずなので、修正してください。

sed -i.bak '/set -e/d' target/docker/mongo/mongors.sh

sed で修正するなら、こんな感じで一発です。

コンテナの起動と停止

では、いよいよ起動です。「run」オプションを実行します。

「-d」スイッチは daemon モードで、コンソールを抜けても動き続けてもらうためのスイッチです。

# symbol-bootstrap run -d
                            _               _           _                       _           _                          
  ___   _   _   _ __ ___   | |__     ___   | |         | |__     ___     ___   | |_   ___  | |_   _ __    __ _   _ __  
 / __| | | | | | '_ ` _ \  | '_ \   / _ \  | |  _____  | '_ \   / _ \   / _ \  | __| / __| | __| | '__|  / _` | | '_ \ 
 \__ \ | |_| | | | | | | | | |_) | | (_) | | | |_____| | |_) | | (_) | | (_) | | |_  \__ \ | |_  | |    | (_| | | |_) |
 |___/  \__, | |_| |_| |_| |_.__/   \___/  |_|         |_.__/   \___/   \___/   \__| |___/  \__| |_|     \__,_| | .__/ 
        |___/                                                                                                   |_|    
2020-10-17T09:21:06.274Z info     Pulling image mongo:4.2.6-bionic
2020-10-17T09:21:06.284Z info     Spawn command: docker pull mongo:4.2.6-bionic
2020-10-17T09:21:06.286Z info     Pulling image symbolplatform/symbol-server:gcc-0.10.0.3
2020-10-17T09:21:06.291Z info     Spawn command: docker pull symbolplatform/symbol-server:gcc-0.10.0.3
2020-10-17T09:21:06.292Z info     Pulling image symbolplatform/symbol-rest:2.1.0
2020-10-17T09:21:06.299Z info     Spawn command: docker pull symbolplatform/symbol-rest:2.1.0
2020-10-17T09:21:11.226Z info     2.1.0:
2020-10-17T09:21:11.228Z info     Pulling from symbolplatform/symbol-rest
Digest: sha256:5aa54ce2a911befc7441e233a01414bbeca57777b1b6634f3b4a83fb63c84cda
Status: Image is up to date for symbolplatform/symbol-rest:2.1.0
docker.io/symbolplatform/symbol-rest:2.1.0
2020-10-17T09:21:11.235Z info     Image pulled: docker.io/symbolplatform/symbol-rest:2.1.0
2020-10-17T09:21:11.238Z info     4.2.6-bionic: Pulling from library/mongo
2020-10-17T09:21:11.246Z info     gcc-0.10.0.3: Pulling from symbolplatform/symbol-server
Digest: sha256:6ad8417c1567cc07f834b389d953e0b5c4c7fb75a841671488b4ae93408e21ab
Status: Image is up to date for symbolplatform/symbol-server:gcc-0.10.0.3
docker.io/symbolplatform/symbol-server:gcc-0.10.0.3
2020-10-17T09:21:11.247Z info     Image pulled: docker.io/symbolplatform/symbol-server:gcc-0.10.0.3
2020-10-17T09:21:12.066Z info     Digest: sha256:a89b09e8bc3153c5c87c52e36a7b6f992ee874c5329cc631e5d9542bf1cbfe31
2020-10-17T09:21:12.068Z info     Status: Image is up to date for mongo:4.2.6-bionic
2020-10-17T09:21:12.072Z info     docker.io/library/mongo:4.2.6-bionic
2020-10-17T09:21:12.073Z info     Image pulled: docker.io/library/mongo:4.2.6-bionic
2020-10-17T09:21:12.078Z info     Spawn command: docker-compose -f target/docker/docker-compose.yml up --remove-orphans --detach
Creating network "docker_default" with the default driver
Creating db ...
.
.
.
Creating rest-gateway ... done
Creating api-node     ... done

イメージのダウンロードが始まり、コンテナが起動します。

「healthCheck」オプションでコンテナの起動を確認できます。

「Network is running!」と表示されれば正常に起動しています。

# symbol-bootstrap healthCheck
                            _               _           _                       _           _                          
  ___   _   _   _ __ ___   | |__     ___   | |         | |__     ___     ___   | |_   ___  | |_   _ __    __ _   _ __  
 / __| | | | | | '_ ` _ \  | '_ \   / _ \  | |  _____  | '_ \   / _ \   / _ \  | __| / __| | __| | '__|  / _` | | '_ \ 
 \__ \ | |_| | | | | | | | | |_) | | (_) | | | |_____| | |_) | | (_) | | (_) | | |_  \__ \ | |_  | |    | (_| | | |_) |
 |___/  \__, | |_| |_| |_| |_.__/   \___/  |_|         |_.__/   \___/   \___/   \__| |___/  \__| |_|     \__,_| | .__/ 
        |___/                                                                                                   |_|    
2020-10-17T09:19:17.789Z info     Container db is running
2020-10-17T09:19:17.836Z info     Container api-node is running
2020-10-17T09:19:17.892Z info     Container api-broker is running
2020-10-17T09:19:17.894Z info     Container rest-gateway is running
2020-10-17T09:19:18.004Z info     Container api-broker port 7902 -> 7902 is open
2020-10-17T09:19:18.004Z info     Container rest-gateway port 3000 -> 3000 is open
2020-10-17T09:19:18.085Z info     Testing http://localhost:3000/node/health
2020-10-17T09:19:18.144Z info     Container api-node port 7900 -> 7900 is open
2020-10-17T09:19:20.357Z info     Rest http://localhost:3000/node/health is up and running...
2020-10-17T09:19:20.359Z info     Network is running!

これで http://__YOUR_IP_ADDRESS__:3000 にアクセスできるようになります。

APIゲートウェイの疎通確認として、curlでレスポンスを得てみましょう。

# curl http://localhost:3000/node/info
{"version":0,"publicKey":"AC867836091338860122FA2E43F88BA6E2A903B52D290BCFE615A8314E5969C8","networkGenerationHashSeed":"6C1B92391CCB41C96478471C2634C111D9E989DECD66130C0430B5B8D20117CD","roles":3,"port":7900,"networkIdentifier":152,"host":"","friendlyName":"niz-dual-1"}

チェーン高 (height) が高くなっていけば同期もできています。

# curl http://localhost:3000/chain/info
{"height":"2675","scoreHigh":"0","scoreLow":"43525657971130062","latestFinalizedBlock":{"finalizationEpoch":1,"finalizationPoint":1,"height":"1","hash":"63D564EC1B46DDF972660DA9ADA48E5A7C4F1579A28F5CB2D15B8F2DC1392B87"}}

ひとまず、ここまでできれば立ち上げは成功です!お疲れさまでした。

外部からもレスポンスを取得できるかどうか確認するために、

利用しているVPSサービスで割り当てられたIPアドレスでもアクセスしてみてください。

ブラウザでアクセスできれば十分です。

 

symbol-bootstrap はこのような感じで使用します。

今回は Dual ノードの設定を使用しましたが、Peer ノードやプライベートネットのプリセット設定もあるので、

必要に応じて使い分けてみてください。

今後はこのツールでネットワーク設定を生成して、ネットワークを立ち上げるというのが、

主流のやり方になるとおもわれます。

少し待つと、こちらのリストにも載ってくるので確認してみてください。

ただし、ノードリストに載るのは時間がかかる場合があるので、ひとまず後回しでも良いです。

立ち上がったことを確認したら、一旦停止してみましょう。

# symbol-bootstrap stop
                            _               _           _                       _           _
  ___   _   _   _ __ ___   | |__     ___   | |         | |__     ___     ___   | |_   ___  | |_   _ __    __ _   _ __
 / __| | | | | | '_ ` _ \  | '_ \   / _ \  | |  _____  | '_ \   / _ \   / _ \  | __| / __| | __| | '__|  / _` | | '_ \
 \__ \ | |_| | | | | | | | | |_) | | (_) | | | |_____| | |_) | | (_) | | (_) | | |_  \__ \ | |_  | |    | (_| | | |_) |
 |___/  \__, | |_| |_| |_| |_.__/   \___/  |_|         |_.__/   \___/   \___/   \__| |___/  \__| |_|     \__,_| | .__/
        |___/                                                                                                   |_|
2020-10-02T15:45:07.187Z info [SYSTEM_LOG]     running: docker-compose -f target/docker/docker-compose.yml down
Stopping rest-gateway ... done
Stopping api-node     ... done
Stopping db           ... done
Stopping api-broker   ... done
Removing api-node     ...
Removing db           ...
Removing rest-gateway ... done
Removing network docker_default

「stop」オプションを実行すると、立ち上がっていたコンテナをすべて停止し、削除されます。

コンテナは削除されますが、同期したブロックデータはサーバ上のストレージに保存されて残るので、

次回以降もデータを引き継いで実行できます。

 

なお、「config」->「compose」->「run」とコマンドを実行しましたが、

これは「symbol-bootstrap start -p testnet -a dual -c my-preset.yml」とすることと同じ意味になります。

(start はすでに設定ファイルや docker-compose ファイルが存在していれば何もしません)

# symbol-bootstrap start -p testnet -a dual -d -c my-preset.yml

Systemd 自動起動設定

「symbol-bootstrap start -d」でノードコンテナ群は立ち上がりますが、

これだけではサーバの再起動時に手動で立ち上げ直さなければなりません。

systemctlを使用してサービス化の設定をします。

「/etc/systemd/system/symbol-platform.service」に以下のような内容のファイルを作成します。

[Unit]
Description=Symbol Platform Daemon
After=docker.service
[Service]
Type=simple
WorkingDirectory=/opt/symbol-bootstrap
ExecStartPre=/usr/bin/symbol-bootstrap stop
ExecStartPre=-/bin/rm target/nodes/api-node/data/server.lock
ExecStartPre=-/bin/rm target/nodes/api-node/data/broker.lock
ExecStart=/usr/bin/symbol-bootstrap start
ExecStop=/usr/bin/symbol-bootstrap stop
TimeoutStartSec=180
TimeoutStopSec=120
Restart=on-failure
RestartSec=60
PrivateTmp=true
[Install]
WantedBy=default.target

起動時にロックファイルが残ってしまい、起動できない場合の対策を入れてあります。

(server.lock と broker.lock を削除する行)

これらは異常終了した場合に残る可能性があるもので、本来ならその原因を突き止めたほうがよいです。

調査が必要な場合には、この行を削除してください。

ファイルを作成したら、次のコマンドで読み込み、サービス登録を行います。

# systemctl daemon-reload
# systemctl enable symbol-platform

サーバを再起動してから API を叩いて確認してみましょう。

再ログインして「healthCheck」を実行してみてもよいです。

立ち上がっていることを確認してみてください。

 

サービスとして登録したので、以後は systemctl 経由でノードを開始 / 停止します。

# systemctl start symbol-platform
# systemctl stop symbol-platform
# systemctl restart symbol-platform

起動、停止、再起動はこのように実行できます。

Dockerによる自動起動(補足)

dockerデーモンにOSの起動時にコンテナを立ち上げさせる設定をすることもできます。

docker-compose.yml のサービス設定に「restart: "always"」と追記すれば、

OS起動後、dockerサービスが立ち上がり、設定したコンテナを立ち上げてくれます。

ただ、この方法だけでは、起動はよくても、OSの終了時にうまく停止できないようで、

「api-broker.lock」ロックファイルが残ってしまい、次回の起動に失敗してしまいます。

停止時には「symbol-bootstrap stop」を適切に動かすためにも systemctl を使用しています。

 

これについては、何らかの理由でコンテナが異常終了した場合にも起こりうることなので、

起動しない場合は、トラブルシューティングに項を参照してください。

ドメイン設定 / HTTPS 対応

昨今は常時 SSL が主流で、Web サイトを簡単にデプロイできるサービスでも HTTPS 接続を提供しています。

HTTPS のサイトからノードへ HTTP 接続を行うと、ブラウザ側で警告が出たり、場合によってはアプリケーションが正常に動作しない可能性があります。

そういった環境での利用を想定した、HTTPS 接続の提供をセットアップします。

ドメインの取得

ドメインとは「nemlog.nem.social」や「yahoo.co.jp」などのWebサイトのアドレスの前の方の部分です。

細かい説明は「ドメイン名」などで検索してもらえばいいと思いますが、

いまのところ、あなたのノードへは「203.138.197.152」のような数字の羅列にしか見えない、

IPアドレスでしか接続できません。

どうせ築城したならば、自分の名前を持ってアクセスして欲しいですよね。(ですよね。

そのためにはまず、ドメイン名を取得します。

取得したドメイン名とIPアドレスを紐付けることで、名前からIPアドレスを参照できるので、

結果として名前でノードにアクセスできる状態になります。

また、HTTPS でのアクセスのためにもドメイン名を使用します。

ドメイン名はドメイン管理会社に利用料を支払って取得したりするのですが、

ここでは無料で取得できる freenom を利用させてもらいます。

Freenomでドメイン取得〜設定

なにはともあれ、サイトにアクセスします。

取得したい名前を入力してボタンを押します。

今回は「symbol-platform-ab1ayas7」を取得します。

(使い捨てるつもりなので、かぶらないようにランダムな文字列を付け足した名前です)

 

何種類かドメインが選べるので、お好きなものを選んでください。

今回は「.ml」にしました。

「選択」にして、「チェックアウト」を押下してください。

 

「Period」で有効期限を選択できます。

ここでは「6 Months」にしましたが、12ヶ月までは無料です。

 

チェックアウトの確認です。

Google のアカウントでログインしてもよいですが、抵抗があるならメールアドレスを入力してください。

「Veridy My Email Address」を押下します。

 

メールアドレスが送られてくるので確認してください。

確認リンクを踏みます。

登録フォームへ遷移するので、必要な項目を入力します。

赤いところだけで大丈夫です。

注文が確定しました。

「Click here to go to your Client Area」を押下します。

ログインを促されるので、先程のメールアドレスとフォームに入力したパスワードでログインします。

「Services」->「My Domains」を開きます。

先程取得した名前でドメインがあるはずです。

「Manage Domain」を押下します。

「Manage Freenom DNS」を押下します。

フォームが表示されるので「Target」にノードのIPアドレスを入力します。

サブドメインを設定したい場合は「Name」に入力します。

ここまで設定したら、しばらく待ちます。早ければ数分、遅ければ数日かかる可能性があります

反映されれば、上記のようなアドレスでアクセスできるようになります。

どちらも同じIPアドレスへ紐付けているので、同じ結果が返ってきますが、

複数の城を立ち上げた場合は、適宜名前をつけてあげるとよいでしょう。

HTTPS 対応 (https-portal コンテナ設定追記)

「target/docker/docker-compose.yml」を開いて、以下を追記してください。

yaml形式なので「https-portal:」の部分を「services:」以下の階層に定義してください。

    https-portal:
        container_name: https-portal
        image: steveltn/https-portal:1
        ports:
            - "80:80"
            - "3001:443"
        volumes:
            - ./ssl-certs:/var/lib/https-portal
        environment:
            WEBSOCKET: 'true'
            STAGE: production
            DOMAINS: 'symbol-platform-ab1ayas7.ml -> http://rest-gateway:3000'
        depends_on:
            - rest-gateway
        restart: 'on-failure:2'

ドメイン名はもちろんあなたが取得したもので置き換えてください。

HTTPS の接続ポートとして公開するポートは「3001」としました。

(- "3001:443" の左側の部分で指定)

これはなにか決まりがあるわけではないので、今後推奨ポートが設定されることがあるかもしれません。

Host の設定変更

ドメインを「target/nodes/api-node/userconfig/resources/config-node.properties」に設定することで、

テストネット一覧のサイトにドメイン名で表示されるようになります。

(サイト側の仕様なので、今後変更になる可能性があります)

host = symbol-platform-ab1ayas7.ml

friendlyNameの上にあるhostにドメイン名を設定します。

コンテナ群の再起動

設定が済んだらコンテナ群を再起動しましょう。

# systemctl restart symbol-platform

起動して、証明書の設定などが完了すると以下のようなアドレスでアクセスできるようになります。

また、しばらく(1時間くらいあれば反映されると思いますが、サイト側仕様が不明なので気長に)待って、

こちらにも反映されていることを確認してみてください。

ここまでやると、 IP / DNS にはドメイン名、Height の下に https という表示がでます。

https の表示はおそらくですが、host にドメイン名を設定してあり、ポート 3001 で https を疎通している場合、

サイト側のクローリングに拾われて、このように表示してくれているようです。

height などが正常に表示されない場合は、ホスト名の設定が間違っている可能性があるので見直してください。

 

お疲れさまでした!

これで、HTTPS対応まで完了しました。

なお、ムームードメインやお名前ドットコムで取得したドメイン名を使う場合も、

同じ用な設定画面があると思いますので、サービス側で同様に設定すればよいです。

  • API ノードの構築
  • ドメインネーム割り当て
  • HTTPS 接続設定
  • サービス化

色々やりましたが、ほとんどの知識は Symbol で無くても通用する技術なので、

ここで得た知識を外でも生かしてもらえれば幸いです。

 

メインネットでは「symbol-bootstrap config -p mainnet -a dual」のように、

プリセットの設定を変えるくらいで、それ以外の作業は大体同じになるはずです。

(それまでにまた色々と機能が追加されて、操作も変化しそうですが、大筋はこんな感じになるかと)

コンテナ単体がダウンした場合の自動復帰

コンテナに高負荷がかかった場合(主に api-node コンテナで頻発する)に、停止してしまう場合があります。

ここまでの設定では、個別にコンテナが停止してしまった場合に、うまく復帰できません。

主な原因は前述している、強制終了時にロックファイルが残ってしまっていることが原因です。

あまり docker-compose.yml を編集したくなかったのと、作業を切り分けたかったので、

「monit」というソフトを使用して、クラスタが正しく動作していない場合に、再起動するようにしてみました。

ロックファイルの削除は前述の通り「symbol-platform.service」に起動時の処理に記述しています。

monit のインストール

# apt-get install -y monit

「/etc/monit/conf.d/symbol-platform」として以下のファイルを作成します。

check host localhost with address localhost
    group symbol-platform
    start program = "/bin/systemctl start symbol-platform"
    stop  program = "/bin/systemctl stop  symbol-platform"
    if failed port 3000 protocol http
        and request /node/health with content = '"apiNode":"up","db":"up"'
        and within 1 cycles
        then restart
    if failed port 7900 within 1 cycles
        then restart
    if failed port 7902 within 1 cycles
        then restart

設定の内容としては、各ポートの応答が無かった場合に再起動をさせています。

次のコマンドでサービスを再起動させます。

# systemctl restart monit

※ 「/」を「/」に置き換えてください。nemlog で保存ができない問題の回避です。

再起動されることを試してみる

念の為、コンテナが単体で終了した場合にクラスタが再起動されるかどうかを確認します。

# docker stats

このコマンドで、動いているコンテナの一覧が表示されます。

CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
8ec5e89d5304        https-portal        0.00%               4.637MiB / 1.946GiB   0.23%               27.9kB / 11.1kB     14.2MB / 57.3kB     10
2d8f7dd27e8c        api-node            3.94%               265.4MiB / 1.946GiB   13.32%              65.7MB / 81.9MB     406MB / 159MB       47
467360bf59a2        rest-gateway        0.00%               30.46MiB / 1.946GiB   1.53%               739kB / 864kB       46.4MB / 0B         22
81560dfa3590        db                  0.65%               585.1MiB / 1.946GiB   29.36%              24.7MB / 1.8MB      4.22GB / 416MB      51
d66fff2c6fde        api-broker          0.50%               5.781MiB / 1.946GiB   0.29%               1.43MB / 24.4MB     25.2MB / 0B         14

このような表示がでるので、様子を見てみましょう。(終了するには「Ctrl+c」です)

もう一つターミナルを開いて、api-node コンテナを強制終了させます。

# docker kill api-node

これにより、ロックファイルが残った状態でコンテナが終了した状態を再現できます。

(再起動される前に、target/nodes/api-node/data/ にロックファイルがあるかを見てみてください)

api-node コンテナが停止したので、一覧から消えます。

その後、しばらく経つと再起動に入るので、他のコンテナも停止します。

すべてのコンテナが消えた後に、起動が始まり、また上記のようにコンテナ5つが稼働し始めます。

本来であれば、ダウンしてしまった理由などを調査して、再発しないようにすべきところですが、

ギリギリのスペックだったりすると、高負荷が原因でダウンしているだけだったりもするので、

それを乗り切って、ノードの稼働を維持するというスタンスの方法となります。

セキュリティについて

サーバの運用で付き物なのが、セキュリティです。

当たり前ですが、自分以外(または自分が許可していない)の人物に勝手にアクセスされては困ります。

今はテストネットなので、最悪の場合、秘密鍵は諦められますが、メインネットとなればそうは行きません。

というか、アクセスされた時点で資産が抜かれてしまうでしょう。

また、自分がレンタルしている VPS 上にマイニングツールや不正アクセスツールを仕込まれて、

踏み台にされ、罪をなすりつけられるという可能性もあります。

今回の記事ではログインまわりについて省略しているので、

前回記事の「ssh 接続ポートの変更」を取り入れるとよいでしょう。

(これは簡単な割に効果が高いです。

世の中の攻撃のほとんどはbotによるもので、ありがちな設定のサーバは狙われやすいです)

他にも、国内や特定のIPアドレス範囲からのログインに限定したり、

ブルートフォース攻撃対策などもやりだすときりがないのですが、

なるべく簡単に導入できて効果が高い方法を盛り込んで行く予定です。

さらに、実際に長く運用するとなると、ディスク容量や不正侵入監視などの対応もあったほうがよいです。

これらもメインネット公開が近づいてきたら、実践的な内容を盛り込む予定です。

my-preset へ設定を保持する

すでに見てきたとおり、プリセットとなるファイルに、上書きする形で設定を流し込んでいました。

生成されたファイルを直接編集して、ノードを再起動して読み込ませても良いのですが、

基本的には、my-preset.yml 経由で設定を流し込むほうが、

symbol-bootstrap をアップデートした際に、設定ファイルを再作成する必要があるに都合がよいです。

 

「host」の設定に、直接「target/nodes/api-node/userconfig/resources/config-node.properties」を編集しましたが、この値を「my-preset.yml」にも書き込みます。

また「target/addresses.yml」に書き込まれた秘密鍵も持ち越すために書き込みます。

 

すでに作成している「my-preset.yml」に追記してください。

nodes:
    -
        host: symbol-platform-ab1ayas7.ml
        friendlyName: niz-dual-1
        signingPrivateKey: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
        vrfPrivateKey: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
gateways:
    -
        throttlingBurst: 80
        throttlingRate: 40

 

「target/addresses.yml」から持ってくる秘密鍵は「signing」と「vrf」のものです。

以下の例でいうと、「cccc...」と「eeee...」の鍵です。

networkType: 152
nemesisGenerationHashSeed: 6C1B92391CCB41C96478471C2634C111D9E989DECD66130C0430B5B8D20117CD
nodes:
    -
        name: api-node
        friendlyName: niz-dual-1
        roles: 'Peer,Api'
        ssl:
            privateKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            publicKey: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
        signing:
            privateKey: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
            publicKey: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
            address: TAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXI
        vrf:
            privateKey: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
            publicKey: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            address: TBXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXI
gateways:
    -
        privateKey: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
        publicKey: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
        address: TCXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXI

 

設定を作り直すために「symbol-bootstrap config -r」のように「-r(リセット)」スイッチを使った場合、

これらの鍵は新しく生成されて、異なるものになってしまいます。

「my-preset.yml」に自分用の設定を保持して、育てていくとよいでしょう。

今後、symbol-bootstrap がアップデートされた際は、育てたファイルを読み込ませて使用してください。

構成レポート

ノードの構成情報を CSV / RST 形式で出力する機能です。

有志でノードを建てる分にはそれほど設定を変えないでしょうから、

基本的にはあまり活躍する機会はないかもしれません。

# symbol-bootstrap report
2020-10-04T02:06:22.987Z info [SYSTEM_LOG]     Deleting folder target/report
2020-10-04T02:06:23.065Z info [SYSTEM_LOG]     Report file target/report/api-node-config.csv created
2020-10-04T02:06:23.066Z info [SYSTEM_LOG]     Report file target/report/api-node-config.rst created

api-node-config.csv と api-node-config.rst というファイルが出力されます。

config-database.properties
database
databaseUri; mongodb://db:27017
databaseName; catapult
maxWriterThreads; 8

plugins
catapult.mongo.plugins.accountlink; true
catapult.mongo.plugins.aggregate; true
catapult.mongo.plugins.lockhash; true
catapult.mongo.plugins.locksecret; true
catapult.mongo.plugins.metadata; true
catapult.mongo.plugins.mosaic; true
catapult.mongo.plugins.multisig; true
catapult.mongo.plugins.namespace; true
catapult.mongo.plugins.restrictionaccount; true
catapult.mongo.plugins.restrictionmosaic; true
catapult.mongo.plugins.transfer; true
.
.
.

このようなファイルが出力されます。

トラブルシューティング

「start -d」時にエラーで終わってしまう

2020-10-03T01:37:38.747Z warn [SYSTEM_LOG]     Network is NOT up and running YET: request to http://localhost:3000/node/health failed, reason: connect ECONNREFUSED 127.0.0.1:3000
Error: Network did NOT start!!!

コンテナ群の起動時に、APIノードの起動チェックが走ります。

イメージのダウンロードやビルドに時間がかかっている場合、

起動チェックがタイムアウトしてしまい、そのまま終了してしまいます。

「--timeout 600000」(10分)などタイムアウトを長めに設定してみてください。

(symbol-bootstrap v0.1.2 以降であれば起動チェックが無くなったので必要ありません)

api-broker / api-node が起動しない

コンテナのロックファイルが停止時に削除されずに残ってしまい、起動に失敗することがあります。

「target/nodes/api-node/data/」にある「broker.lock」または「server.lock」を手動で削除して、

起動してみてください。

頻繁にコンテナが停止し、ロックファイルが残っている

メモリ不足でコンテナプロセスが docker または Linux システムによって停止させられている可能性があります。

公式ドキュメントではメモリ 4GB 以上を推奨としています。

ただし、次の項のスワップメモリを作ることで回避できる可能性があります。

メモリをケチったせいで遅い・コンテナが止まる

推奨スペックとしては CPU: 2コア / メモリ: 4GB / ディスク: 20GB となっています。

Dual (Peer+API) ノードの場合はもう少し高くしたほうが良いかもしれません。

スペックが低めのサーバを借りると、最新ブロックへの同期の処理がいつまで経っても

追いつかなかったり、同期が進まないということが起こります。

同期が済んで、最新ブロック待ちの状態になると、低スペックでも比較的安定するようです。

(ただし、急激なトランザクション増加や高負荷がかかった場合はダウンしたり、遅延が発生するかもしれません)

そこで、スワップメモリをディスク上に作成し、足りないメモリを補うことで、回避する方法があります。

 

以下のコマンドでスワップメモリが作成されます。

ディスク上にメモリ用領域を作成するので、ディスク容量を消費します。

ここでは 4GB 分のメモリ領域を確保しています。

# fallocate -l 4G /var/swapfile
# chmod 600 /var/swapfile
# mkswap /var/swapfile
# swapon /var/swapfile
# echo '/var/swapfile none swap defaults 0 0' >> /etc/fstab

※ 最終行の「/」を「/」に置き換えてください。nemlog で保存ができない問題の回避です。

削除する場合は次の手順でおこなってください。

# swapoff /var/swapfile
# rm /var/swapfile
# sed -i '/\/var\/swapfile/d' /etc/fstab

※ 最終行の「/」を「/」に置き換えてください。nemlog で保存ができない問題の回避です。

なお、スワップメモリはディスク上に作るため、ディスクの速度に依存します。

HDD で試していないのですが、おそらくは遅すぎて結局追いつかないと思われます。

物理メモリよりは遅いにしても、SSD であれば効果がでるようです。

とはいえ、スペック不足であることには変わりないので、あくまで参考程度のテクニックです。

どうしてもエラーがでてうまく動かない

# symbol-bootstrap resetData

こちらはブロックデータを初期化するコマンドです。

ロックファイルなども削除し、起動する直前の状態に戻します。

 

# symbol-bootstrap clean

それでも、どうにもうまく行かない場合は完全にすべて削除してみましょう。

生成した設定ファイルや同期済みブロックデータなどすべてを削除します。

ここからやり直してみましょう。

AllNodes で建てる

暗号通貨ノードホスティングサービスの Allnodes でも最新版 0.10.0.3 でノードが建てられるようになっていました。

こちらはお金さえチャージして2クリックで立ち上がり、維持も手間いらずです。

ただし、現状では FriendlyName の変更はできるものの、それ以外の設定はいじれないようです。

なお、2020年12月1日 まで 15% オフのプロモコードがあるそうです!

コードは「TESTSYMBOL」です。

ぜひ活用してみてください。

Allnodes は非常に安定していて、特に面倒を見る必要もないので、

メインネットでノードを立ち上げようと考えている人は試しに使ってみてはいかがでしょうか。

ローカルハーベスティング

みんな大好きハーベスティングですが、NEM1 同様、ローカルハーベスティングがあります。

また、今回はファイナライズの機能のために、投票ノードという役割も存在します。

これらはある程度のインポータンスを獲得していないと、そのアカウントで機能してくれないので、

ある程度の xym を保有する必要があります。

検証用として、50,000,000 xym ほど譲り受けました。

検証に必要な方は Twitter でもコメントでも、とりあえず連絡ください。

まとめ

各コマンドの説明があるので、細かい使い方はここを参照してみると良さそうです。

テストネットに対応した修正が入ったウォレットがリリースされています。

0.13.1以降をインストールして、自分で立ち上げたノードにアクセスしたり、トランザクションを投げてみたりしてみましょう。

テストネットしばきはもうちょっと周辺ツールの更新やノードが出揃ってきたあたりで、

お知らせしようと思っています。

それまではノードを建ててみたり、公開中のウォレットで操作を練習してみたりして素振りなどでお楽しみください。

 

nem開発公式の各ノードや蛇口、エクスプローラーのリンクはこちらでまとめてもらっているので、

ぜひ参照してみてください。

 

Writer
しれっとめちゃくちゃ重要なことを書いたりしています。

Comment
Login required to post comment
Loading...
https://symbol-sakura-16.next-web-technology.com:3001,https://symbol.harvest-monitor.com:3001,https://hideyoshi-node.net:3001,https://harvest-01.symbol.farm:3001,https://criptian-xym-node.net:3001,https://35665.xym.stir-hosyu.com:3001,https://yuna.keshet.finance:3001,https://cryptocat-xym-node.com:3001,https://misaki-xym.com:3001,https://ik1-305-12844.vs.sakura.ne.jp:3001,https://17107.xym.stir-hosyu.com:3001,https://23639.xym.stir-hosyu.com:3001,https://sym-main-01.opening-line.jp:3001,https://sym-main-02.opening-line.jp:3001,https://sym-main-03.opening-line.jp:3001,https://sym-main-04.opening-line.jp:3001,https://sym-main-05.opening-line.jp:3001,https://sym-main-06.opening-line.jp:3001,https://sym-main-07.opening-line.jp:3001,https://sym-main-08.opening-line.jp:3001,https://sym-main-09.opening-line.jp:3001,https://sym-main-10.opening-line.jp:3001,https://symbol-node-01.kokichi.tokyo:3001,https://50038.xym.stir-hosyu.com:3001,https://27423.xym.stir-hosyu.com:3001,https://angel.vistiel-arch.jp:3001,https://xym.stakeme.tokyo:3001,https://00-symbol-node.yagiyoshi.com:3001,
6BED913FA20223F8,051FAEC15105C808,73019335A785A3AE,5289A9B0DBB7EB25,6B245EAF1302E444,2C4A4893229DD0A9,63509D495CAD7B80,481D74291A71FD1F,009388A38C91A8B2,4E94920841641B77,027C6AD49DE2C9F9,29FCA5D3092205EC,56085AD9FCE150AC,7D47EE5423795E68,1FCD7C6B47C7AC5C,34F165131675B97B,2277A3D3C939E3BD,1BEE7E51C52B9E4C,7DE0FA227D5C284A,69C715D2F4E80338,5CF9D768B02E51EA,5B96E6496754C18E,35584939456EE19C,430AB6F115D709C5,202FC8C6762F1286,1DA6F5986C56CAB4,77F0C0918BDDCA75,05D935AB3DBBBDA7,3AB05B7B3373067F,383EEBD409479BDD,282E5F730EEF0F3C,108AFF21E54B77EB,0C4AAE8E82E054FD,18964001EF89D687,15BDE2DDF36FE763,01E2769C92FFB187,427C7F0474B2170B,3F2EEE17968715D5,6C0AFBA20EEBF08B,22975F2097F16D15,2A30D04FF35E8641,03ACEC4F51A71804,5235C4249928922B,2BFEB24F70B91041,741320E728843965,7C4E97850A863208,0586FF7E5ED1C680,606432C50BDE4EB5,15A6AD5E5ED6AC0E,59932634EDBF2A21,5E4F05ED77C64434,71C79278A325FF67,616EC15DE7D641A0,25C2DAB4FE687CBE,3D78B91922741293,5DC4B8DCDC4D3098,2693037B1881D5FA,178FE008F5DCE797,174A93DA9B651FBD,128B2CD071838D3E,1F5630200C5A6025,43449FF761B3DD67,4B20F46C289CA548,35DBA0A70A96615F,78CE44A425CD4514,37179FDE046FE7F2,1739E47C99BAF114,0F3B4A0F2E58703B,3C41561BE3DF7461,2AF0FBFEBF29231F,74CD75720BA4F553,1A5229DC90802C6C,0D2888CD0CBB78EE,2558F02FE439C78F,5DDD07C51EC896A7,437B094116B91BF3,6C9E7CFE33220C8F,38E1C92F412FCA96,2FB263845F59AF82,28C3C38B84138804,659821D4511185A7,7C6095DA82D3E981,70ADA95932385F9F,0BE6C51AD316BF2B,78E6ED1B6C05FD98,39534A8DFD9C0F1E,1BAF1FE1AAF90CD0,6782B8D9162D0C12,5EF22919F6EA15F7,04A3F3F5C088626A,7484B044AC8EF734,305B0ECE763A1E81,08738DB598D0BA37,6F4018163AC51F88,46650CE0C72739A8,0208FCB9186781E5,4E685399C9F8C991,77DB7D348B042A18,578ED7B270B43E64,0B34212023AA5139,479CEDAEE6FAC642,4266458B86437B4B,1F7022D092066B94,0CA28E24CB575AA6,4DCC3C025CDC0BB8,1BD05266C7410EE1,45C46BC710C187AF,7CC2C672543CA102,555BA3719D30D3B9,75C4079CCCCF3E82,66C98D947EAC56FB,1C041AB88A8D222B,79C13E9FE7DA49AB,54D872B5DB378F52,5C97B2414157B039,31E7A64CFF778586,1DFD11EEDA4662C4,18506C180280D8AB,02E95DB8811B3F7A,2D289599AF071703,17EA80052AF590B0,5239AE78AA9011CC,6B6511925501765B,2730974F2D11E9FA,08AB4E53E95E417E,1D0DD379C8C4BA49,26EE7E07E1255FAB,015FABE3F602FA91,366D7D6540335156,2D1E8E73B9F09391,043694AD272BCEBA,064335A213099492,3C40AE05D9758591,71C4BCA24A2FA6C1,20170ABD32244B78,74EBE4C9FD9C3BC8,713583F712D574FA,7C05BBBD486CF544,634D5A328A659C41,2DA0EC8CA32B7CE6,4D0ECC9F6F70D67D,7426EE72B3DFD620,3C3E58B64A8CD43C,5007CF79DF192FB2,1531F39F1B0AA8C3,5D1E928E7902404F,74599424DE012A19,52F96AC0043B02D8,0C694031CFC22C84,03D6EE58174D16DD,054B071E97323D54,2B58942A0A9D3908,7FE10DF86F32776F,1A08F9B88AE4CCF9,03CB7A99E6F6F65A,2F0BAAAD886013B2,7D8FF6C570E909C3,237ACBD2073D7C22,29498519D19B27CF,03E85F9F15A92D27,62B4F899B6DADDFF,6649A6F82740775E,1FA7CAD8017C3045,5FFB7126DD87CC5B,07039874D46F8B44,3391DD8105AD0C82,56C97E544EA9C149,6103DBFFA022249B,41E9771D99FF96A5,65CF7BE26FC7BF56,789063B9FDA7D02B,3EE026A17E4D1895,44B13D3F4EEB8AC9,248AAD9D9E2C1984,0CEDE2DEDDB4832F,5DFE51E2C6617CA4,4FAE3B092339A328,03B7E30D264E586B,3B5B8D2389EEB8C9,0058930348E8DA39,43C44AE173D50661,16E0B9B56763A2A6,43B05E6CCD87A765,33276E3A53106C11,24F35BCEA31E9AFB,49320DB27BA10BF5,01B69528B052EFA3,21C3025E1B2B9D3C,613FFCD9027A73D9,79A5BC34AE8B6314,35BFF98EA19690D4,156CDDD2D6791814,6E4E5A6C8F1ECA31,21BCF4CD26C307FF,15F6E07EAC6D5186,71A24162BA611651,0EDC8542160D8DAA,771BAE5451E881A8,1E47CA21337876B5,7688DC299D77C545,1166391DB32354A4,6A0AF7328EBBE113,38E48122C0FC8BCF,484874B2C669D6E1,4EF142A5D00BDA63,0508049897379E24,50B28C0858AE222C,75F2674CEE45E919,2F0DC3D306469BF9,5A86884742F89C7F,78F0F31776134860,1576EB985E541EA9,17D9C6FCB4FAB2A0,6B2E9EAF2632AEC8,007050CE9F59E77C,5D88028B3A9E633A,554191B46C16E4C4,5A0E1268E65E99F2,41A67647778AEA4D,7EADDBC2119EADA0,3D4235EB6FC9247D,5D25658948613563,5629D816678CF8FC,48A147A7F34C0131,46DF1D828736AFE1,748D83A906C897E4,0708BF363BA9595A,58384D5F0D793C09,531A0934DE43FBAC,1C4EEB7AD6B44AF4,383B57EBD5272C12,41F8077951D07ADF,0F52B4D356FDA824,1FE0805A112A03DF,38E8FFDFCD6510FF,0F65746CB1D7AD53,1E9E3010A1412DDB,7401A59C5DBD66A4,5FDC6383C702EC40,3B97B8CA49739205,5A799437D541B2DA,187E2C0B8F401ED9,0ACA1FDDEB9F6A07,4F2DC8BA863044C6,7D2383791D91CD04,54ACEAF1E8632DF1,7B9DC57CC154B2E0,0B7766A119D5E4B5,49D82E72E99EB836,509A58B6FDFFC197,0C1058BB20787615,581B528745FE0F3B,28D1C21EDE70206A,23A72A2876482029,22EB02FCBC661527,5A8F12439B09B33E,5FF7741F1AE008DE,220DE9C58B8E0E71,5D9D5C6BFE968E2C,3F0B0C29CFD04713,11B52399E03C7E5C,14ABF8C934D15151,7290BAEF5C9CF307,6A44EB5C0F8ED639,255AC0628631B47B,7ADA0B238BB2E29D,05E545728E183EFA,73908A9FF9A309BE,7542C49F2737C4DE,6BE5318AED3E68DB,581F8B63FDF26797,6936D8BB20F4668A,410ECE9587841E7F,149C29AC78DA6465,2181451A49AB930A,7930B6BDAED90925,311AD92AC357CFD7,14340B796150DF92,4D4C35DA96550436,1B5CF0365D451EED,7691E0E6C687B9C0,76D453D709EEE2ED,22AE5C6526EBDE2B,