HUNTER×HUNTER『軍儀』のwebブラウザ版アプリを公開した。

これはリリースノートではなく、アプリ公開までを振り返る雑記。
リリースノートは別途公開しようかな。

[1] - HUNTER×HUNTER『軍儀』について(https://store.universal-music.co.jp/s/hunter-gungi/)

雑記

2024年9月末。
お友達がうちへ遊びにきた際に軍儀を遊んだ。「『軍儀』を作って販売しますよ〜」というアナウンスを受けてすぐ予約していたボードゲームだ。以前から何回か遊んでいて、軍儀って結構おもしろいな〜とは思っていたんだけど、2人向け以上のボードゲームは買っても相手がなかなか見つからないためホコリをかぶりがちだ。
だからこのとき、軍儀を出したらおともだち二人が興味を示してくれて嬉しかった。
「(オンラインで遊べるように)お前アプリ作れよ」と言われる程度にはおともだちにも気に入ってもらえたようだった。
でもこの言葉には乗らない。頑張ってアプリを作ってもどうせそこまで遊んでもらえないからだ。今楽しくても、どうせ帰りの新幹線に乗っている間にこの熱は冷めるだろう。
アプリを作る労力に報酬が見合わない。
この時点でスマホアプリなら公開されてたしね。スマホのアプリをインストールするのは手間だが、本当に遊びたいのであればそれで遊ぶだろう。

さて1週間後。
実家に帰ると親が大画面でYoutubeを見ていた。10月5日の藤井聡太竜王の対局解説動画であった。この解説がAIを用いて盤面の優劣を可視化しており、これと最近遊んだ軍儀がふと結びついた。
対戦相手がいないのであれば、軍儀AIを作ればいいのではないか?
早速将棋AIについて調べ、とりあえず将棋AIの本を注文した。([2] - 強い将棋ソフトの創りかた Pythonで実装するディープラーニング将棋AI, https://www.e-hon.ne.jp/bec/SA/Detail?refShinCode=0100000000000034286292)

機械学習にはデータが必要だ。棋譜生成プログラムを用意する必要がある(軍儀だから儀譜だろうか)。
将棋とは違い、質の良い棋譜は望めない。ランダム生成するしかないだろう。
将棋の機械学習について調べながら、軍儀を実行するプログラムを作る。
将棋の機械学習についてと、軍儀プログラムの作成と、加えてプログラムの出来上がった範囲で棋譜の生成を並行して行っていく。
棋譜はデータの形式が変わるなどで使えない可能性もあるが、その時は捨てれば良い。ゴミデータでも作っておいたほうがいいだろう……。(結局捨てた。)

Githubに久しぶりに草が生えた。振り返ると3週間程度かけてこれを作っていたようだ。

そしてこれは頓挫する。
軍儀プログラム自体はおおむね完成していたのだが、インターフェースがないのだった。
つまり、AIとAIを取り持つサーバがない。
他にも、機械学習が面倒そうだなとかいう気持ちも高まっていたような気がするし、細々問題があったようななかったような気がする。
インターフェースがないなら作れば?という話でしかないのだが、とにかくこのインターフェースがない問題にあたって、面倒になってやめた。

さて10月末、11月、12月クリスマスと別のことにかまけていたところの年末である。
自分は毎年、年始は山形の祖父母の家で過ごす。祖父母の家では食事は美味しいし親戚の顔も見れて楽しいしそっちで遊ぶおともだちもいるのだが、基本的にやることがなく、ヒマを持て余している。

ノートパソコンとNintendo Switchくらいしか持っていくものはないし……とそこで軍儀が再び鎌首をもたげてきた。
インターフェースを作って公開すれば、もしかして軍儀を遊ぶ人間が棋譜を生み出してくれるのではないか。
そもそも人類はスマホアプリなんかインストールしたくないんだよ。ゲームはWebブラウザで遊べる、それに越したことはないのだ。

こうして12月末の休暇に入ってから年明けの6日まで、祖父母の家のこたつで横になりながらずーっと軍儀のインターフェースを作っていた。
Javascriptのことはほぼわからないし、DOMも概念しかわからない。
多分……Websocket?を使うんですよね?みたいな状態から始まったので、正月中には全く完成しなかったが、休み明けも仕事後にこれを作り続けた。

通信のプロトコルはUSI(Universal Shogi Interface)プロトコルを参考にした。
([3] - USIプロトコルとは, http://shogidokoro.starfree.jp/usi.html, 将棋所)

とはいえ年末年始で、作っている間はあまりAIを自分が作ることは頭になかった。
どうやったら競技人口が増えるかな?といったことの方に意識が向かっていた。
メルエム(HUNTER×HUNTERに出てくる軍儀を打つキャラクター)を面白おかしく出せばバズらないかな……とか。
人間が増えれば棋譜も増えるし、なんならAIも誰かが勝手にやると思うし……そのためにAI利用者が使いやすいインターフェースにしなきゃ……でも人口を増やすためには面白メルエム(最強軍儀AI)を作ってバズらなきゃ……みたいなことばかり考えていた気がする。

1月13日にはとりあえずgithubにpushしており、ここで大まかな骨組みは完成していたようだ。
ローカルサーバで動かしていて情報がコードに載っていたりゴミファイル管理が面倒だったので、大体出来上がるまではpushしていなかった。

10月時点ではPythonだった軍儀プログラムも、Javascriptに書き換わった。
しかし10月時点で軍儀のロジック部分を作っていなかったらかなり難しかっただろう。Javascriptだけならまだしも、WebsocketとDOMを勉強しながらゲーム部分を作ろうとしたらかなり苦しいことになっていたと思う。

バグや見た目やデバグ用のprintを消したり、人間が遊びやすいような調整を行って、ローカルでそれなりに遊べるようになった。(『謀』はこれを書いている今も未実装)。

1月14日。
さてではインターネットに公開……ってどうやるんだっけ?
たっけえドメインは持ってるけど、ほぼ使っていないので記憶がない。
AWSのアカウントを作り、EC2? route 53は関係ない? お金ってどれくらいかかるの?もう払いたくないんですけど?とか思いながらAWSと格闘すること3日。

やっとインターネットに公開できた。

プログラミングとかはともかく、この格闘の経験が浅くて苦しかった。
ここ数日は、「もう(プログラムは)できてるのにつながらない、もうできてるのに……」と言いながら床についていた。

長くなったが、このDNSとかとの格闘について、次回のために記録を残しておきたくてこの雑記を書き始めた。

ということで本題。


作成したWebブラウザアプリ(Python サーバ)をAWS EC2 + Nginx + 外部で取得した独自ドメインで公開する。

やりたいこと

  1. HTTPサーバをたてる
  2. HTTPサーバとは別に、アプリケーションサーバをたてる。
  3. HTTPサーバは、通常通りクライアントからのHTTPサクセスをさばく。
  4. アプリケーションサーバは、クライアントサイドのJavascriptからのWebsocket通信をさばく。
  5. 上記を自分のドメインで公開する。
4番以外は期待通りできた。
試行錯誤しながら、クライアントから直接Websocket通信を受け取るのが面倒だなというかんじになってきたので、3~4を
  • HTTPサーバは、Websocket通信を受け取ったらアプリケーションサーバにプロキシする。
  • アプリケーションサーバは、HTTPサーバからプロキシされたWebsocket通信をさばく。
に変更した。

AWS EC2 でインスタンスをたてる

AWSって、勝手にお金取られるんだろうなと思ってる。
AWSでドメインとるとしたら何が取れるんだろう?と思って取得可能なTLDを確認したいだけなのにアカウント登録しなきゃいけないし、アカウント登録の段階でクレジットカードを登録させられてすごく嫌。

でも今回は経験と思ってAWS EC2を使った。


EC2インスタンスを立てる(Ubuntu)

EC2インスタンスってなんだよ?
リナックスのサーバをたてる、みたいなニュアンスで今は理解してる。
好きなOSを選んでEC2インスタンスをたてると、EC2インスタンスにsshできる。
せっかくAWS使うんだしAWS Linux使ってみるか〜と思ったけどPython3.12にpipがインストールできなくてやめた。OpenSSLのバージョンが1.0.1しか使えないことに問題があるっぽい。Python3.10以降はpipモジュールにOpenSSL v1.1.1以上(?)が必要らしい。この情報に辿り着くのに1.5日くらいかけた。
頑張ればなんとかできるんだろうけど、俺は軍儀を作ってへとへとなんだ。Python3.12で素直にpipできないならいらないよ。余計な手間をとらせやがって。
AWS Linux インスタンスを削除して、Ubuntuでインスタンスを再作成した。

参考:[4] - 【AWS】EC2を使って、WEBサイトを公開する流れ, (https://zenn.dev/grazie/articles/20c05aa22738b5) ぐらじえ: 2025/01/07

テラタームのGUIが出てくる手前まで参考。sshのGUI出てきた瞬間目閉じてるから。


EC2インスタンスのIPアドレスを固定する(Elastic IP)

EC2インスタンスは立ち上げただけだとIPアドレスが固定でない。
再起動などでIPアドレスが変わってしまうらしい。
AWSのホームから「EC2 > サイドメニュー:ネットワーク & セキュリティ:Elastic IP 」へ移動する。
「Elastic IP アドレスを割り振る」ボタンで固定IPを取得して、取得したIPと立ち上げたEC2インスタンスを紐づける。

参考:なにかを見てElastic IPにたどり着いたんだけど何を参考にしたのかわからなくなった。(でもこれは画面に従うだけで簡単だった。)


AWSって、よくわかんないけどアクセス過多で料金請求が爆上がりするんですよね?

コストをそんなにかけたくない。どうせ軍儀やるやつなんかおらん。
まちがって人口が増えて突然今月50万払えみたいな状況になっても対応できない。
EC2は最初の1年無料枠があるそうなので、それを使う。
それでも上限はあるはずだから、料金がかかるならインスタンスを停止させたい。
IAMポリシー、IAMロール、Budgetsを使って設定できるらしい。

参考:[5] - 【AWS】予算を設定し、超えた場合にEC2インスタンスを停止させる方法, (https://itechblog.hatenablog.com/entry/2021/03/31/2021-03-31-232653/) itechblog : 2025/01/17

これ規定の料金到達でインスタンスを停止させるだけなのにめちゃくちゃ複雑で「複雑すぎるだろ!」って画面につっこんでしまった。
予算に応じてサーバを止めたいだけなのに複雑すぎます。
上のブログに割と早く辿りつけたおかげで、すこし安心してAWS触れるようになった。
AWSって、なんだかよくわからないうちに突然お金請求してきそうで怖いからそーっと触ってたんだよね。


独自ドメインとEC2インスタンスを紐づける

さて、ドメインはあるけどこれとEC2ってどうやって結びつけんの?
これを書いている今もよくわかっていない。
分野入門時によくやる、ガチャガチャやってなんだか上手くいったけどなんで上手くいったのかわけわかってない状態。

参考:
[6] - [AWS]ドメインの登録方法, (https://qiita.com/kono-hiroki/items/154e3ff96f7f63dc62cf) @kono-hiroki : 20250117
[7] - AWS Route53 親ドメインを移行しないでEC2にサブドメイン設定, (https://qiita.com/ntm718/items/c01fa4fc47d21893974e) @ntm718(Natsume) : 20250117
[8] - 【AWS】Route53の設定(初心者用), (https://qiita.com/ponponpoko/items/a60dab676addeb040e9e) @ponponpoko(Takeshi Sakiyama) : 20250117

話それるけど、AWSの情報いっぱいあってしかもカス情報の割合が低くて驚いてるんだよね。
ただqiitaは結構記事が消えてて、「この記事は移転しました(有料外部サイト)」みたいな、スターだけ稼いで検索結果には出るけど情報は見せません、みたいなやつにはムカついている。
タイトルにも書いておけよ、「【記事移転】【有料化】」ってよ。
OSS精神の押し付けでこんなこと言ってるけど、「有料のAWS資料を参考に記事を書きました」みたいな人もいて、かなり助かってる。有料記事も別に嘘の量産カス記事ではなく有料化できる程度の内容だったことを思うとAWS周辺は記事の質がなんか高い印象がある。

またそれとは別に、AWS側がUIをコロコロ変えるみたいでサービスの内容は変わらないのに記事の通りに作業を進めるために該当のボタンを探さなきゃいけなかったりする。
そんなに気軽にUIを変えるのは良くないと思うんだけど……。


AWS Route 53の設定

[6] はけっこう親切でよかった。ただ自分はお名前.comつかってなくて自分におきかえられないことと、サブドメインでやりたいんだけどやり方が合ってるのかわからなかった。
そもそもRoute 53てなによ? ドメインを取得するやつ? じゃあいらないです持ってるので、と思ってRoute 53の記事は回避してたんだけど、Route 53はその名前の通りルーティング系をやってるサービスっぽい。
EC2と独自ドメインと結びつけるのにもRoute 53を使う。
Route 53でホストゾーンを作成して、自分のドメインと紐付けた。結局サブドメインでも大丈夫[7]だった。

[7] ホストゾーンを作成したら、ホストゾーンにEC2、それから独自ドメインをそれぞれ紐づける。

まずEC2。
ホストゾーンから「レコードを作成」。「シンプルルーティング」を探して、EC2に紐づけたElastic IPを設定する。
これができた時点でEC2にHTTPサーバが立っていれば、「レコードをテストする > レスポンスを取得する」で指定したElastic IPのアドレスが応答されるっぽい。
自分はEC2たてたらもうHTTPサーバもたってるのかな?とか甘えてたんだけど、IPアドレスが返ってこずにEC2でHTTPサーバをたてるのに苦戦した。

次に独自ドメイン。
ホストゾーンにNSレコード(例:ns-1234.awsdns-56.org)が4つほどあるので、これをDNSに紐づける。
高いお金払ってるのに知らなかったんだけど、Google domains がサービス終了してたらしい(2023)
え? じゃあ私は誰にお金を払ってるの? 払ってないの?
と思ったら、Squarespaceという企業に移管されていたらしい。いつの間にか料金が1.5倍になっている。このドメインに依存し切る前に、もっと安いドメイン探してそっちに移行しようかなあ……。

このSquarespaceについては誰も画像も記事も書いておらず、DNSについても教科書しか読んだことないレベルの人間には設定を探すのは難しかった。
「Squarespace ログイン > ドメイン > (独自ドメイン選択)> DNS > DNS設定 > カスタムレコード > レコードを追加」
から、サブドメイン「gungi」を追加する。
NSレコード4つ分、「gungi」を追加した。

また、(多分)どの記事にも書いてなかったけど、
「Squarespace ログイン > ドメイン > (独自ドメイン選択)> DNS > ネームサーバの登録 > ホストレコードを追加」から「gungi」とElastic IPを紐づけるレコードを追加した。
これに意味があるのかないのかはわからない。今動いてるし怖いからそのままにしている。

なかなか上手くいかなくてsshしたりnginxガチャガチャしたりしたから上の手順通りだったかは定かではない。

[8] に nslookupで確認しようって書いてあったから、ローカルからnslookupを打って、どうやらDNS設定はうまくいったようだと判断した。


HTTPサーバを立ち上げる(Nginx)

EC2インスタンスにsshして、Nginxを立ち上げる。
nginxのインストールはどうやったのか覚えてない。最初から入ってた?
かなり簡単だったと思う。Ubuntuだからね。

最初は、やっぱApacheかな〜と思ったんだけど、確かこれは何かでつまづいてインストールがうまくいかなかった気がする。
粘らずApacheはやめて、せっかくだし使ったことないNginxを使ってみることにした。

参考:[9] - Ubuntu 20.04にNginxをインストールする方法, (https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04-ja) Erin Glass : 2025/01/17

``$ sudo apt install nginx ``したら勝手にnginx立ち上がるっぽい。

web FireWall の ufs の話があるけど一旦パス。
AWSだし大丈夫でしょ、みたいな気持ちと、AWSだからまずいかも、みたいな気持ちがある。


Nginxのconfファイルを編集する。

Nginxのconfファイルをいじるのがまた難しくて、結構悩んだ。
DNSとかも並行してたんだけど、DNSが解決してることがわかるまでは何ができてて何ができてないのかわからなかった。
ひとまず、``$ sudo systemctl restart nginx '' がなにも言わずに完了すれば問題ないっぽいということがわかった。

nginxのconfの記事についてはあまり相性のいいものは見つからず、色々情報を整合するとこういうことだろうな、というのを探ることになった。(公式ドキュメントを読めるほどまだ詳しくないので)。

/etc/nginx/nginx.conf が設定ファイルであり、/etc/nginx/conf.d/ 配下にも.confファイルが置けるっぽく、これがよくわからない。
サービスによってポートを分けたいとか要求があり、さらにそのサービスごとに設定ファイルを作れるよ、みたいな感じで、nginx起動時に複数のconfファイルを読み込む……のかな?
nginx.confが大元で、conf.d配下にサービスごとに分けたconfファイルを置く……?

今回はひとつのWebサービスしか予定はないので、nginx.confファイルを直接編集する。

これもまた記事によって、設定ファイルを全部書いてくれないので困った。
よく ``server {...`` から始まるconfファイルが記事中で紹介されているんだけど、これは設定ファイルの一部で(それともconf.d配下の設定ファイルなのか?)、これを間に受けて設定ファイルを書くと nginxが起動できなくなる。

正しくはなんかもっと書くことがあり、特に編集したい箇所が ``server{...`` の部分っぽい。

基本的にはnginx インストール時のサンプルを真面目に編集した方がよい。


HTTPS 通信を行うために、証明書を取得する

nginx.confだけを編集していてもHTTPS接続ができるようになるわけではない。
Let’s EncryptにSSL証明書を発行してもらう。

参考:
[10] - nginxでhttpsサイトを公開しよう!,  (https://qiita.com/Kuroi_Cc/items/ec2e9b9e20b268f0d155) @Kuroi_Cc(Kuroi_Cc) : 20250117
[11] - Nginxで403 Forbiddenエラーの解決策(Rails+AWS+Nginx+Unicorn環境) , (https://qiita.com/shuhei_takada/items/3bc56e8ab78212a2abcc) ,@shuhei_takada(Shuhei Takada) : 20250117 

[10] この記事はかなり好き。
説明に過不足がなくて、文章も平易なので読みやすい。内容も初心者に親切でそれでいてくどくなくて、自分にはかなり丁度よかった。
でもこれだけだとうまくいかなかった。nginxのconfがうまくできていないからだ。

nginx.confの '' location /.well-known/acme-challenge/ {..'' 内に、SSL証明書を保存する場所を指定していたんだけど、これがうまく公開できていなかったらしい。
外部からアクセスできないので、SSL証明書を保存できないよ、みたいなエラーが発生していた。(エラー内容のメモ消えた)。

指定したファイルパスに問題があるっぽいな、というのは[11]の記事であたりをつけた(気がする)。
userのホームディレクトリ配下で公開しようとしていたのをやめて、/var/www/配下に設定し直した。
権限は701って言ってるけど、655にしたらうまくいった。

[10]に戻って、SSL証明書の取得が成功することを確認!
再度 confファイルを編集。

index.htmlも /var/www/ 配下にして独自ドメインにアクセスするとindex.htmlが応答されるようになった。

他にもつまづいたところ結構あった気がするけど、だいたいこれでHTTPサーバは完了(完了してない)。


アプリケーションサーバを立ち上げる(Websocketsサーバ)

こんなサーバいらないと思うんだけど、HTTPサーバでアプリケーションをさばくのは難しそうだからアプリケーションサーバそのまま使いたい。
Websocket受け付けるところはPythonで書いてるし。

でもPythonの''websockets.serve()''って、実行するだけで勝手にwwwに公開されるのか?

結論としては、wwwに公開されるのかはよくわからないが、何も考えずにアクセスするのも難しいっぽいから、HTTPサーバから転送しようという判断になった。

当初の予定では、クライアントがwebsocket通信に特定のポートを使う予定だったんだけどこれはやめた。普通に443で接続する。代わりに、URLパスに''ws''を追加することでフラグとした。'HTTPサーバは、'https://gungi.2410.dev/ws'' にアクセスが来たら、アプリケーションサーバの特定のポートにリクエストを転送する。
アプリケーションサーバは127.0.0.1のローカル内だけにポートを開く。

これで期待通り動くようになった。


後回しにしていたファイアウォール

この記事を書いていて、[9]を見返したらufwをインストールしていることを思い出した。
というか[9]にしたがってもufw立ち上がってないんだよね。なんだよいらねーじゃんと思って無視していたが、ファイアウォールのないサーバを今も公開しつづけているのか?

参考:[12] - iptablesが難しいためufwでWEBサーバーのファイアウォール設定,  (https://qiita.com/shimakaze_soft/items/c3cce2bfb7d584e1fbce) @shimakaze_soft(shimakaze soft) : 2025/01/17

でももう面倒だな、やらないよりましか……と思って 22 LIMIT まで設定した[12]。


アプリケーションサーバの自動起動設定(TODO)

いまのところ、HTTPサーバはEC2と共に立っているけど(?)アプリケーションサーバは手動で立ち上げている。
''$ python3 server.py > log &''とかでもいいんだけど、これが死んだ時に勝手に再起動するようなshellを用意したい。

したいなあ、と思っている。

とりあえず&起動で様子見かな……。

参考/リンク(再掲)

[1] - HUNTER×HUNTER『軍儀』について(https://store.universal-music.co.jp/s/hunter-gungi/): 2025/01/17
[2] - 強い将棋ソフトの創りかた Pythonで実装するディープラーニング将棋AI, (https://www.e-hon.ne.jp/bec/SA/Detail?refShinCode=0100000000000034286292)  山岡忠夫, 加納邦彦 : 2025/01/17
[3] - USIプロトコルとは, http://shogidokoro.starfree.jp/usi.html, 将棋所: 2025/01/17
[4] - 【AWS】EC2を使って、WEBサイトを公開する流れ, (https://zenn.dev/grazie/articles/20c05aa22738b5) ぐらじえ: 2025/01/07
[5] - 【AWS】予算を設定し、超えた場合にEC2インスタンスを停止させる方法, (https://itechblog.hatenablog.com/entry/2021/03/31/2021-03-31-232653/) itechblog : 2025/01/17
[6] - [AWS]ドメインの登録方法, (https://qiita.com/kono-hiroki/items/154e3ff96f7f63dc62cf) @kono-hiroki : 2025/01/17
[7] - AWS Route53 親ドメインを移行しないでEC2にサブドメイン設定, (https://qiita.com/ntm718/items/c01fa4fc47d21893974e) @ntm718(Natsume) : 2025/01/17
[8] - 【AWS】Route53の設定(初心者用), (https://qiita.com/ponponpoko/items/a60dab676addeb040e9e) @ponponpoko(Takeshi Sakiyama) : 2025/01/17
[9] - Ubuntu 20.04にNginxをインストールする方法, (https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04-ja) Erin Glass : 2025/01/17
[10] - nginxでhttpsサイトを公開しよう!,  (https://qiita.com/Kuroi_Cc/items/ec2e9b9e20b268f0d155) @Kuroi_Cc(Kuroi_Cc) : 20250117
[11] - Nginxで403 Forbiddenエラーの解決策(Rails+AWS+Nginx+Unicorn環境) , (https://qiita.com/shuhei_takada/items/3bc56e8ab78212a2abcc) ,@shuhei_takada(Shuhei Takada) : 2025/01/17
 [12] - iptablesが難しいためufwでWEBサーバーのファイアウォール設定,  (https://qiita.com/shimakaze_soft/items/c3cce2bfb7d584e1fbce) @shimakaze_soft(shimakaze soft) : 2025/01/17

この参考リンク手動でぽちぽち管理してるらしいです。



コメント