まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2022/04

昨夜(2022/04/15 午前零時ごろ)、Oracle Cloud からメールがあり、利用しているサーバーインスタンスのパブリック IP アドレスに関する障害(?)があった、とのことでした:
2022041500


ツイッターでも同様のメールを受け取った人がいるようで、どうやら自分のインスタンスだけの問題ではなさそうでした:
2022041501


というわけで、Oracle Cloud でインスタンスを使っている人は念のため一度自分のインスタンスが無事かどうか確認してみることをオススメします。現象としてはインスタンスのパブリック IP アドレスが使えなくなっている、というものなので、SSH などを経由した外部からのアクセスができなくなっています。Oracle Cloud のダッシュボードにログインして、アタッチされたパブリック IP アドレスが見えているかどうかを確認するのがよいと思いました。自分のように使えなくなっている場合は、サーバーインスタンスの Public IP address 欄が表示されなくなっています:
2022041501


その場合の対応方法(パブリック IP アドレスを再設定する方法)もメールで案内されていましたが、残念ながら全て英語でした。わかりにくい人もいると思うので、以下に自分が行った対処をスクリーンショットと併せて紹介します。

まず上記画面(Oracle Cloud ダッシュボードにログインして、サーバーインスタンスを選択した画面)を下までスクロールして、"Attached VNICs" を選択します:
2022041502


設定されている仮想 NIC の一覧が表示されます(普通は1つ)。対象の NIC の名前部分を選択します:
2022041503


インスタンスの仮想 NIC の情報が表示されます:
2022041504


この画面をまた下までスクロールして、"IPv4 Addresses" を選択します:
2022041505


(パブリック IP アドレスが消えてしまった)IP v4 アドレスの一覧が表示されます(ここも普通は1つ)。表の一番右のメニューボタン(縦に点3つ)から "Edit" を選択します:
2022041506


パブリック IP が "No public IP" になっているので、ここを "Ephemeral public IP" に選択し直します。またオプションでその下のフィールドにパブリック IP アドレスの名前をつけることができます。最後に "Update" ボタンを押して保存します:
2022041507


元の画面に戻り、新しいパブリック IP アドレスが付与されていることを確認します:
2022041508


これで新しい IP アドレスで SSH などから外部接続できるように元通りになりました。

同じように困っている方の手助けになれば。

最近のブログでは独自ドメインを扱うネタが多くなっています(これとか、これとか)。この背景としては旧 Google Apps(現 Google Workspace)の無料版が廃止になって、猶予期間の終了が迫り、これまで取得したドメインの運用を Google Apps に任せていたことに起因して、無料または安価な代替運用先を探していることにありました。ただ(自分的に優先順位の高かった)独自ドメインのメールサーバーについてはある程度対応できたと思っています。

上述のように独自ドメインのメール環境についてはある程度解決しました。次は独自ドメインウェブサイトの問題です。独自ドメインのウェブサイトやウェブサービスを Google Apps を使わずに用意する方法です。まあ、ホスト名だけであれば DNS の CNAME 設定だけでなんとかなるのですが、問題になるのは SSL を使いたいケース(つまり https で始まる URL で独自ドメインのウェブサイトを公開したいケース)です。

これも手間を惜しまないのであれば、Let's Encrypt などで独自ドメインの証明書を無料で取得・更新できます。その証明書を使ってサービスを公開すれば https 対応はできます。ただ、これはこれで(アプリケーション側で証明書を意識するのも)面倒だし、もし証明書の更新を忘れてしまうとサービスが見えなくなってしまったり、証明書を更新した際の再起動なども行う必要があるので、手順としても(コマンドラインで作業するなど)面倒だったりします。独自ドメインのウェブサイトを運用する上でここを(できれば無料、または安価で)どうにかできないだろうか、という課題があります。

そして本ブログエントリはこの部分を
 ・アプリケーションは無料の Heroku で公開して、
 ・無料の Cloudflare で SSL 対応した独自ドメイン名でアクセスできるようにする
という構成を実現するための手順を紹介します。


【アプリケーションを Heroku で公開する】
対象のウェブアプリケーションを Heroku で公開します。アカウントを所有していない場合はサインアップします。

ここでは特別な設定はほぼ不要ですが、1点だけ。Heroku で独自ドメインを使うには、有料版を利用するか、クレジットカードを登録する形で無料枠を使う必要がある点に注意してください。Heroku 自体はクレジットカードを登録せずに無料範囲内で利用することができ、その範囲内でウェブアプリケーションを公開することもできますが、この後独自ドメインを使う場合は無料で使う場合であってもクレジットカードを登録する必要がある、という意味です。

Heroku は GitHub と連携してアプリケーションをデプロイしますが、ここを CLI で手動で行ってもいいし、Git コミットをハンドリングして自動デプロイにしても構いません。いずれかの方法でアプリケーションを Heroku にデプロイしてください。なお後者の方法については過去にこのブログでも紹介したことがあるので、よかったら参考にしてください:
Heroku のパイプラインで GitHub コミット時に自動デプロイする


以下では dotnsf-www.herokuapp.com というホスト名で Heroku 上でアプリケーションが稼働しているものとして説明を続けます。Heroku 上で独自ドメイン向けの設定を行う必要もありますが、 Cloudflare 側での設定をまず先に済ませてから Heroku 上での設定を行います。


【Cloudflare で独自ドメインの設定をする】
次に Cloudflare 側の設定を行います。アカウントを取得していない場合は Cloudflare の無料プランでサインアップし、所有している独自ドメインを登録します。なお以下では独自ドメイン(pi314.jp というドメインを使う例を紹介します)は取得済みで、そのドメインの DNS 管理を Cloudflare にさせる前提で紹介します。

独自ドメインを登録した後、まずは "SSL" のメニューを選択して、「暗号化モード」が「フル」に設定されていることを確認します。もし異なる設定になっている場合は「フル」に変更します。この設定にすることで利用者のブラウザから、Cloudflare を経由して(今回の場合は Heroku 上の)アプリケーション・サーバーまでの全ての経路の通信を暗号化することができるようになります。また独自ドメインの SSL 証明書の更新も自動化されます:
2022040801


そして "DNS" メニューを選択して DNS の設定を行います。今回は上述の dotnsf-www.herokuapp.com というサーバーを www.pi314.jp という名前で公開できるよう設定します。「レコードを追加」と書かれたボタンをクリックします:
2022040802


追加するレコードは以下のようにして「保存」ボタンをクリックします:
 タイプ: CNAME
 名前: www (www.pi314.jp という名前で公開する、という設定です)
 ターゲット: dotnsf-www.herokuapp.com
 プロキシ: ON(プロキシ済み、と表示されます)
2022040803


入力した内容が DNS 画面に表示されるようになります。これで https://www.pi314.jp/ という URL にアクセスがあると、https://dotnsf-www.herokuapp.com/ に(利用者から見えない所で)転送されてページが表示できるようになります。また Cloudflare を使っているので、セキュリティプロキシも有効になっています:
2022040804



【heroku 側のアプリケーションを再設定する】
これでアプリケーションの独自ドメイン利用ができる・・・わけではありません。最後に SSL を使えるように実際には dotnsf-www.herokuapp.com 上で動いているアプリケーションが www.pi314.jp というホスト名でアクセスされる可能性があることを予め認識させておく必要があります。そのためには Heroku の CLI を使って(CLI でログイン後に)以下のコマンドを実行※します:
$ heroku domains:add www.pi314.jp --app dotnsf-www

※このコマンドを実行するには heroku を有料サービスで使うか、または無料利用であってもクレジットカードを登録しておく必要があります。


このコマンドを実行後、しばらく(数分)待ってからウェブブラウザで https://www.pi314.jp/ にアクセスすると、https://dotnsf-www.herokuapp.com/ の画面が https://www.pi314.jp/ というホスト名で表示できることが確認できます。


以上、Heroku も Cloudflare も有償サービスを使わないのであれば、この方法でも無料の範囲内で独自ドメインでウェブアプリケーションを公開することができそうです。



タイトルの通りです。例えば以下のような独自定義関数があったとします:
// n 未満の素数を配列で取得する関数
function pnum( n ){
  var results = [];

  for( var i = 2; i < n; i ++ ){
    var b = true;
    for( var j = 2; j < i && b; j ++ ){
      b = i % j;
    }
    if( b ){
      results.push( i );
    }
  }

  return results;
}

関数名は pnum() 、パラメータを1つ受け取り、その値未満の素数配列を返す、という内容です。関数の処理内容はもっと複雑でも構いません。

例えば上記内容を pnum.js というファイルで保存した場合、同じフォルダにある HTML ファイルから以下のように使うことができます:
<script src="./pnum.js"></script>
<script>
var results = pnum( 1000 );  // 1000 未満の素数の配列
</script>

では同じファイルの同じ関数を Node.js からも使いたくなった場合はどうすればいいでしょう? あるいは逆に Node.js から require や import で使える JavaScript ファイルをブラウザから読み込んで使いたい場合はどうすればいいでしょう? これが今日のブログテーマです。


答えはシンプルなんですが、まず Node.js から使う場合は、このようにクラス化して、クラスを export するのが定番的なやり方だと思っています:
class MyClass {
  constructor(){
  }

  pnum( n ){
    var results = [];

    for( var i = 2; i < n; i ++ ){
      var b = true;
      for( var j = 2; j < i && b; j ++ ){
        b = i % j;
      }
      if( b ){
        results.push( i );
      }
    }

    return results;
  }
}

module.exports = MyClass;

この上の内容を myclass.js という名前で保存したとすると、Node.js の呼び出し元からは以下のようにして利用することができます:
var MyClass = require( './myclass' );
var myClass = new MyClass(); var results = myClass.pnum( 1000 );

では同じ myclass.js をブラウザの JavaScript から <script> タグで使えばいいのでは・・・ と思いますが、その場合は myclass.js の最終行である module.exports = MyClass; の所でエラーになります(module が定義されていないからです)。

そこでこのエラーを回避するために以下のようにします。module が object として定義済みである場合のみ最終行を実行するようにします:
class MyClass {
  constructor(){
  }

  pnum( n ){
    var results = [];

    for( var i = 2; i < n; i ++ ){
      var b = true;
      for( var j = 2; j < i && b; j ++ ){
        b = i % j;
      }
      if( b ){
        results.push( i );
      }
    }

    return results;
  }
}

if( typeof module === 'object' ){
  module.exports = MyClass;
}

こうしておくとブラウザ側も Node.js と同様に実行することができます:
<script src="./myclass.js"></script>
<script>
var myClass = new MyClass();
var results = myClass.pnum( 1000 );
</script>

要は「クラス化して、module が object として定義済みであればクラスをエクスポート指定」することで Node.js からもブラウザ JavaScript からも共通利用できるようになります。




 

このページのトップヘ