at backyard

Color my life with the chaos of trouble.

Oracle CloudのVMインスタンスにnginxでwebサーバを建ててプロキシする。SSL化もする。

備忘録。

内容はタイトルの通りで、

  • Oracle CloudのVMインスタンス上でnginxをインストールしてWebサーバをたてる。
  • nginxの後ろに控えているアプリにプロキシする
  • ついでにLet's Encryptを用いてSSL化もする(httpsでアクセスできるようにする)

という内容です。

目次

Oracle Linux上にnginxをインストールして動かす

公式ドキュメントを参考にする

docs.oracle.com

まずはnginxのインストール

sudo dnf install -y nginx

nginxサービスの有効化

sudo systemctl enable --now nginx.service

このサービスはデフォルトで80ポートでリクエストを受け付けるwebサーバを起動する。 ただ現状はファイアウォールで弾かれると思うので、public IPを叩いてもwebサーバの画面は表示されない。

正常に動いているのかサービスの状態を確認するには下記のコマンドを実行する。
(正常に起動していれば、それっぽいログが表示されているはず)

sudo systemctl status nginx

Oracle cloud側で設定できる custom firewall profileOracle Cloud Infrastructure instance を利用している場合、80ポートを開く必要がある。
今回の場合OCI(Oracle Cloud Infrastructure)のVMインスタンス上で作業しているので、これに該当する。

よって、下記のコマンドを実行して、nginxサービスのファイアウォールポートを有効にしてやる。

# httpトラフィックを許可
sudo firewall-cmd --add-service=http --permanent

# リロード
sudo firewall-cmd --reload

そして http://<IP_address>/ にアクセスしてみる。...が、私の環境ではこれでも開かない。
何かを忘れている気がしたが、そうだ、そもそもVMインスタンス自体のIngress Rules上で80ポートを許可していなかった。
というわけで Ingress Rules に80ポートのアクセスを受け付けるようにする。

これで再びアクセスすると、nginxが表示される。

f:id:shinshin86:20220316071937p:plain
Oracle仕様の赤い画面

nginxを使って後ろで動くアプリをプロキシする

nginxの後ろでは3000ポートでリッスンしているサーバがいる。こいつにリクエストを流したい。
nginxを触るのは久しぶりでもう忘れてきてしまっているが、とりあえず調べながら必要最低限の設定だけ書きます。

設定ファイル作成

/etc/nginx/conf.d/default.conf というファイルを作成して、ここにプロキシの設定を記載する。

ちなみにこれは /etc/nginx/nginx.conf 内の設定ファイルで下記のように記述されているため、conf.dディレクトリ内に設定ファイルを置くことで読み込まれている。
(デフォルトでこの記述はあるので、特にこちら側で記述を追加する必要はない)

include /etc/nginx/conf.d/*.conf;

プロキシの設定を書く

次にプロキシ設定。

sudo vim /etc/nginx/conf.d/default.conf

Vimで開き下記の内容を記述する。

server{
        listen 80;
        server_name test.example.com(実際のURLは異なりますが、便宜上これを入れています);

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        location / {
                proxy_pass http://localhost:3000;
        }
}

これでnginxを再起動する。

sudo systemctl restart nginx

nginxで13: Permission deniedのエラーが出てしまう

指定したアドレスにアクセスすると、502エラーになる

下記のように権限周りを変更してみたが、だめだった。

sudo usermod -a -G opc nginx
chmod 710 /home/opc

一度落ち着いてログを見てみる。

sudo tail /var/log/nginx/error.log

すると下記のようなログが出ている。

connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstream...

権限周り?と思い、いろいろしらべていたところ、下記のブログに辿り着く。

itips.krsw.biz

qiita.com

どうやらSELinuxの機能によりこの問題が発生しているよう。

sudo setsebool httpd_can_network_connect on -P
sudo systemctl restart nginx

これで無事に行けました。

httpsで通信できるようにする

実運用では https 通信を行うことになるので、次はhttps通信ができるようにする。

最初に打った firewall-cmdhttps 通信も許可するようにまずは設定する。

# httpsトラフィックを許可
sudo firewall-cmd --permanent --zone=public --add-service=https

# リロード
sudo firewall-cmd --reload

今回SSL化するのに無料で利用できるLet’s Encryptを使う。

certbotのインストール

Let's Encryptのクライアントであるcertbotをインストールしていく。 ぐぐると色々と情報が出てくるが、どうやら現在certbotはsnapでインストールすることを強く推奨されているらしい。
(古い情報を参照して設定しようとすると、以前は存在していたコマンドがなくなっていたりして結局うまく行かないので注意)

下記の公式情報を参照して、Oracle Linuxにインストールしていく。

certbot.eff.org

ここで余談だが、Oracle LinuxOracleによるRed Hat Enterprise Linux (RHEL) をベースとしたLinuxディストリビューションである。そのため snapd をインストールする際に参照するページはRed Hat Enterprise Linux 向けのページを見ていくことになる。
あと一応実行した自身のversionも下記に記載しておく。
(最初、CentOSのドキュメントを参考にしていて、うまく snapd がインストールできなかったので注意。snapdのドキュメントで見るべきはRed Hat Enterprise Linux のほう)

# 自身のOracle Linuxの環境
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.5 (Ootpa)

※参照したsnapdのインストールドキュメント

snapcraft.io

まずは epel のインストール。

sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

sudo dnf upgrade

次に snapdのインストール

sudo dnf install snapd

# スナップ通信ソケットを管理するsystemdユニットを有効化
sudo systemctl enable --now snapd.socket

# 従来のsnapをサポートするには以下のようにシンボリックリンクを貼る。
# 従来のsnapサポートが必須なのかよく分からないが、ドキュメントに書かれているのでとりあえずやったという感じです...
sudo ln -s /var/lib/snapd/snap /snap

一旦ここでログアウトする必要がある。
Oracle Cloud上で行っている場合は、一旦接続を切って再度sshで接続してログインする。
再度ログイン後、下記のコマンドを実施。

# snapの最新バージョンを取得
# 上で最新が入っているので不要かと思ったけど実行すると何やら取得しているっぽい
sudo snap install core; sudo snap refresh core

なお、apt、dnf、yum などの OS パッケージマネージャを使用して Certbot パッケージをインストールしている場合は、Certbot スナップをインストールする前にそれらを削除して、certbot コマンドを実行するときに OS パッケージマネージャからのインストールではなく、スナップが使用されるようにする必要があるとのことだが、ここについては今回インストール自体が初めてなので気にしていない。

そしてようやく certbot のインストール

sudo snap install --classic certbot

下記のコマンドを叩いて実行されることを確認。これで完了。

sudo ln -s /snap/bin/certbot /usr/bin/certbot

certbot --help

nginxで使うためのSSL証明書を発行する

というわけで、ようやくSSL証明書の発行に移る。

sudo certbot --nginx

これをやるとCLIインタラクティブな状態になって色々聞かれる。

  • 緊急連絡用のメールアドレスを聞かれる(証明書の更新が迫るとメールが来るらしいので、管理者のアドレスを入力)
  • 利用規約を承諾するか?(内容をチェックしてからYes)
  • 電子フロンティア財団にメールアドレスを提供するか?(これは別に提供しなくて問題ない)
  • どのドメインhttpsにするか?(nginxで既に設定済みの場合は、そのURLが表示されている)

これらに対して回答を行うことでSSL証明書が生成される。

ここまでやるとnginx側の設定ファイルにもSSL設定に関する内容が追記されている。
(該当箇所にはmanaged by Certbot とコメントあり。)

ちなみにこの時点で実際にアクセスしてみると https化されている。 あとは443でアクセスできるように、VMインスタンス自体のIngress Rules上で443ポートを許可してやる。

ちなみにhttpでアクセスしても https にリダイレクトされるように設定してくれている。

なお、もっと手作業でやりたい人は下記のコマンドを使うらしい。
(例えば今回のようにインタラクティブに設定したくない人、スクリプトで自動化している人などはこういうのを使うのか?あまり中身を見ていないのでここについては想像です)

sudo certbot certonly --nginx

自動更新をONにする

Certbotには、証明書が期限切れになる前に自動的に更新するcronジョブまたはsystemdタイマーが付属している。
設定を変更しない限り、Certbot を再度実行する必要はないらしい。

このコマンドを実行することで、証明書の自動更新をテストすることができる。

sudo certbot renew --dry-run

結果が問題なさそうであればOK。

なお、certbotrenewコマンドは以下のいずれかに格納されているらしい。

/etc/crontab/
/etc/cron.*/*
systemctl list-timers

というわけで、Let's Encryptを用いたhttps化については以上。

振り返ってみるとそこまでの量はないものの、意外と最初躓いたりして思った以上に疲れました。