VPSのRailsに独自ドメインを適用し、SSL(https)化する(CentOS 8.2 / Nginx)

VPSのRailsに独自ドメインを適用し、SSL(https)化する(CentOS 8.2 / Nginx)

September 4, 2020

CentOS(8.2)と Nginx の環境を前提としています。作業開始時点は「http://IP アドレス」を入力すると Rails のアプリが表示されるようになっている状態が前提です。

なお、私の環境としては、前回投稿した以下の記事から連続して作業している状態です。そのため、前回の記事を参考に環境構築した方がいれば、本記事もまずうまくいくのではないでしょうか。

ConoHa VPS(CentOS 8.2)に Rails 6 + PostgreSQL + Nginx + Unicorn + Capistrano でデプロイする

ただし、前回の記事と直接的な繋がりはないため、本記事の作業だけを独立して実施しても大丈夫です。

また、お名前ドットコムですでに独自ドメインを取得している想定で書いています(どこのレジストラから取得していてもあまり関係はないですが)。

ではさっそく、以下手順です。

1.独自ドメインを適用する #

1 − 1.お名前ドットコムの DNS 設定を変更する #

お名前ドットコムの DNS レコード設定のページで以下2つを追加。例としてドメインを example.com にしている。

HOST NAME       | TYPE  | TTL  | VALUE
--------------- | ----- | ---- | -----------------------------------
example.com     |   A   | 3600 | サーバの IP アドレス(xxx.xxx.xxx.xxx)
www.example.com | CNAME | 3600 | example.com

上記実施後、レコード設定は下記となっているはず。

HOST NAME       | TYPE  |  TTL  | VALUE
--------------- | ----- | ----- | ----------------------------------
example.com     |  NS   | 86400 | 01.dnsv.jp
example.com     |  NS   | 86400 | 02.dnsv.jp
example.com     |  NS   | 86400 | 03.dnsv.jp
example.com     |  NS   | 86400 | 04.dnsv.jp
example.com     |  A    | 3600  | サーバの IP アドレス(xxx.xxx.xxx.xxx)
www.example.com | CNAME | 3600  | example.com

設定が反映され次第、example.com および www.example.com にアクセスすると、サーバにアクセスしに行くように変わっている。

しかし、この状態で example.com にアクセスしてみると、Nginx のページが表示されてしまう。Nignx の設定も変更する必要がある。

*メモ:DNS 設定について #

HOST NAME       | TYPE  | TTL  | VALUE
--------------- | ----- | ---- | ----------------------------------
example.com     |   A   | 3600 | サーバの IP アドレス(xxx.xxx.xxx.xxx)
www.example.com | CNAME | 3600 | example.com

上記が意味しているのは、

  • example.com の IP アドレスは xxx.xxx.xxx.xxx
  • www.example.comexample.com の別名

ということで、つまりどちらを入力しても xxx.xxx.xxx.xxx にアクセスするようになる。

ここで、CNAME(別名)の設定を使わずに、

HOST NAME       | TYPE | TTL  | VALUE
--------------- | ---- | ---- | ---------------------------------
example.com     |  A   | 3600 | サーバの IP アドレス(xxx.xxx.xxx.xxx)
www.example.com |  A   | 3600 | サーバの IP アドレス(xxx.xxx.xxx.xxx)

上記としても動きは全く同じになるが、意味合い上、CNAME を使って設定するのが良い。

1 − 2.Nginx の設定を変更する #

サーバに接続し root ユーザにスイッチした後、以下で設定ファイルを開く。

vim /etc/nginx/conf.d/アプリケーション名.conf

下記のような感じになっているはず。

upstream unicorn_アプリケーション名 {
  server unix:/var/www/アプリケーション名/current/tmp/sockets/unicorn.sock;
}
server {
  listen 80;
  server_name サーバのIPアドレス;
  root /var/www/アプリケーション名/current/public;
  access_log /var/log/nginx/アプリケーション名_access.log;
  error_log /var/log/nginx/アプリケーション名_error.log;
  location / {
    try_files $uri @unicorn;
  }
  location @unicorn {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://unicorn_アプリケーション名;
  }
}

上記の server_name の IP アドレスを、下記の通り example.com に変更する。

server_name example.com;

変更後、設定ファイルに問題ないかをテスト。

nginx -t

問題なければ、Nginx を再起動する。

systemctl restart nginx

その後、http://example.com にアクセスすると、アプリのページが表示されるようになっている。

ここで、http://IPアドレス でアクセスすると、先ほどまではアプリが表示されていたのが、今度は Nginx のページが表示されるようになっている。これは、先の設定ファイルを書き換えたことで、IP アドレスの記載がなくなった結果。

もう一度、Nginx の設定ファイルに手を加え、下記の動きを実現するように変更する。

  • example.com にアクセスすると example.com のページが開く
  • www.example.com にアクセスすると(301 リダイレクトで) example.com のページが開く
  • IPアドレス にアクセスすると(301 リダイレクトで) example.com のページが開く

つまり、 (www 無しの)example.com にすべて片寄せするという動き。

再度ファイルを開き、

vim /etc/nginx/conf.d/アプリケーション名.conf

下記の通り設定ファイルの server 部分を更新する。

server {
  listen 80;
  server_name example.com;
  root /var/www/アプリケーション名/current/public;
  access_log /var/log/nginx/アプリケーション名_access.log;
  error_log /var/log/nginx/アプリケーション名_error.log;
  location / {
    try_files $uri @unicorn;
  }
  location @unicorn {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://unicorn_アプリケーション名;
  }
}
server {
  listen 80;
  server_name www.example.com サーバのIPアドレス;
  return 301 http://example.com$request_uri;
}

server の記述をもう一つ追加し、server_name には、www.example.com および サーバのIP アドレス を併記(両者の間には半角スペースを入れること)、そして 301 リダイレクトで example.com に向けている。

$request_uri というのはその時のページを指している変数で、例えば、 www.example.com/blogs にアクセスしたら、 example.com/blogs にリダイレクトしている。

変更後、忘れずに設定内容テスト、問題なければ Nginx を再起動。

nginx -t
systemctl restart nginx

これでドメインでアクセスできるようにする設定は終わり。

2.SSL(https)化する #

2 − 1.https 接続を許可する(443 番ポートを開放) #

https を許可するために、443 番ポートを開放する。

まず、firewalld の設定状況を確認してみる。

firewall-cmd --list-all

services: cockpit dhcpv6-client http ssh となっていることを確認。http と ssh が許可されている。

下記を実行。

firewall-cmd --add-service=https --permanent

firewalld をリロードして設定反映。

firewall-cmd --reload

変更確認のため再び実行。

firewall-cmd --list-all

services: cockpit dhcpv6-client http https ssh となっており、https が追加されている。

2 − 2.Certbot をインストールする #

Certbot は、Let’s Encrypt での SSL 証明書から設定までを自動で行ってくれるツール。

Certbot と、Nginx で Certbot を使う時に必要なプラグインをインストール。

dnf -y install certbot python3-certbot-nginx

インストールできたか確認。

certbot --version

certbot 1.7.0 などと表示されれば OK.

2 − 3.SSL 証明書の取得と設定を行う #

Certbot を使って SSL 証明書の取得と設定を行う。

certbot --nginx

対話形式で設定内容に関する質問をされるので回答する。下記に質問内容と回答例をすべて載せておく。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): xxxxxxxx@gmail.com #メールアドレスを入力

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: (A)gree/(C)ancel: A #A(同意)を選択

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N # N(いいえ)を選択

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: example.com
2: www.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1 # exmaple.jpをHTTPS化
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/conf.d/アプリケーション名.conf
Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/アプリケーション名.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2020-XX-XX. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

証明書を取得、設定できていることを確認する。以下を実行。

certbot certificates

example.com ドメインの証明書情報が表示されれば OK.

これで HTTPS で接続できるようになった。 https://example.com でアクセスできることを確認する。

また証明書の期限は3ヶ月間のため、そのままだと3ヶ月後に失効する。クーロンのジョブを追加し、定期的に証明書を自動更新させることで実質的に永続利用できるようにする。以下を実行。

echo "0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null

クーロンが設定されたことを確認するため、ファイルの内容を出力。

cat /etc/crontab

出力結果の最後に、 「0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q」 があることを確認。

クーロンのデーモンを再起動して設定を反映しておく。

systemctl restart crond

最後に、確認のためドライラン(=テスト)を実施してみる。

certbot renew --dry-run

結果の中に、「Congratulations, all renewals succeeded.」と書いてあれば OK.

2 − 4.Nginx の設定を変更する #

ここで、Nginx の設定ファイルを確認する。

vim /etc/nginx/conf.d/アプリケーション名.conf

そうすると、内容のうち server 部分が自動的に変わっていることが確認できる。これは Certbot が更新したため。以下は更新された後の例。

server {
  server_name example.com;
  root /var/www/アプリケーション名/current/public;
  access_log /var/log/nginx/アプリケーション名_access.log;
  error_log /var/log/nginx/アプリケーション名_error.log;
  location / {
    try_files $uri @unicorn;
  }
  location @unicorn {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://unicorn_アプリケーション名;
  }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
  listen 80;
  server_name www.example.com サーバのIPアドレス;
  return 301 https://example.com$request_uri;
}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  listen 80;
  server_name example.com;
    return 404; # managed by Certbot


}

ただし、上記のままだと、 https://www.example.com や、 https://IPアドレス 、でアクセスされた時にリダイレクトできていなかったり、インデントや記述位置をきれいに整えたかったりするので、以下の形に再整備した。

なお、「listen 443 ssl;」と1行で書くのと、「listen 443;」「ssl on;」と2行で書くのは同じ意味。

server {
  listen 443;
  ssl on;
  server_name example.com;
  root /var/www/アプリケーション名/current/public;
  access_log /var/log/nginx/アプリケーション名_access.log;
  error_log /var/log/nginx/アプリケーション名_error.log;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
  location / {
    try_files $uri @unicorn;
  }
  location @unicorn {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://unicorn_アプリケーション名;
  }
}
server {
  listen 443;
  server_name www.example.com サーバのIPアドレス;
  return 301 https://example.com$request_uri;
}
server {
  listen 80;
  server_name example.com www.example.com サーバのIPアドレス;
  return 301 https://example.com$request_uri;
}

これで、以下の場合は全て、 https://example.com に 301 リダイレクトされるようになった。

  • https://www.example.com
  • https://IPアドレス
  • http://example.com
  • http://www.example.com
  • http://IPアドレス

設定を反映させるため、忘れずにテスト&Nginx を再起動させておく。

nginx -t
systemctl restart nginx

3.参考 #

Rails の config/environments/production.rb には以下のオプションがある。

# config.force_ssl = true

デフォルトでは、上記の通りコメントアウトされているはず。

このオプションのコメントアウトを解除して有効にすると、アプリに http でアクセスされた時には https にリダイレクトさせることができるようになる。つまり、Nginx で設定した内容と同じことが実現できるということ。

ただし、本来こういった処理は Web サーバ(Nginx)にて捌くものだと思うので、今回のように Web サーバを使っている場合は、上記の Rails 機能は利用せず、Web サーバ側で対処しておく。

以上 #

無事にこれで終わり。

次は、サブドメインを使用して1つのサーバ内で複数の Rails アプリを運用する方法に取り組みたい。

*追記

次の記事を作成しました。

VPS でサブドメインを適用し、複数の Rails アプリを運用する(CentOS 8.2 / Nginx)