Open8

NginxでSSLリバースプロキシを構成する(Let'sEncrypt)

Shion TanakaShion Tanaka

目的

Nginxを使ってSSLリバースプロキシを構成し、バックエンドのWebアプリケーションにHTTPS接続ができるようにする

認証局

無料で使えるということで Let's Encryptを使用。今後ZeroSSLなんかも検討したい。

https://zenn.dev/mattn/articles/b2c4c92c9116b1

環境

  • OS: CentOS Stream 8
  • Nginx: v1.14.1
  • certbot 1.12.0
  • ホスト:AWS EC2
Shion TanakaShion Tanaka

Let's Encrypt

ドキュメント
https://letsencrypt.org/docs/

使用方法おすすめ

Getting Startedに記載。
https://letsencrypt.org/getting-started/

シェルアクセスができる場合

We recommend that most people with shell access use the Certbot ACME client.

(日本語)シェルアクセスができるほとんどの人には、Certbot という ACME クライアントを使うのがおすすめです。

ということでCertbotを使う方法について調べる

Shion TanakaShion Tanaka

Certbot

https://certbot.eff.org/

ドキュメント

https://certbot.eff.org/docs/intro.html

CertbotとLet's Encryptを組み合わせて使う

Certbot and Let’s Encrypt can automate away the pain and let you turn on and manage HTTPS with simple commands. Using Certbot and Let’s Encrypt is free, so there’s no need to arrange payment.

インタラクティブガイドを使用することを推奨

How you use Certbot depends on the configuration of your web server. The best way to get started is to use our interactive guide. It generates instructions based on your configuration settings. In most cases, you’ll need root or administrator access to your web server to run Certbot.

CertbotはWebサーバー上で実行すること

Certbot is meant to be run directly on your web server, not on your personal computer.

CertbotはACMEプロトコルを使用しタスクを自動化する

Certbot is a fully-featured, extensible client for the Let’s Encrypt CA (or any other CA that speaks the ACME protocol) that can automate the tasks of obtaining certificates and configuring webservers to use them. This client runs on Unix-based operating systems.

Shion TanakaShion Tanaka

CentOS StreamにCertbotをインストールする

AppStreamにはCertbotはないので3rdのリポジトリからインストール

EPEL - Fedora Project Wiki
https://fedoraproject.org/wiki/EPEL

EPEL 8 / x86_64のパッケージリスト
https://ftp.yz.yamagata-u.ac.jp/pub/linux/fedora-projects/epel/8/Everything/x86_64/Packages/c/

EPELの有効化

RHEL/CentOS 8の場合

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

on RHEL 8 it is required to also enable the codeready-builder-for-rhel-8-*-rpms repository since EPEL packages may depend on packages from it:

# ARCH=$( /bin/arch )
# subscription-manager repos --enable "codeready-builder-for-rhel-8-${ARCH}-rpms"

Certbotのインストール

# dnf info certbot
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.

Extra Packages for Enterprise Linux Modular 8 - x86_64                                                          513 kB/s | 550 kB     00:01    
Extra Packages for Enterprise Linux 8 - x86_64                                                                  8.3 MB/s | 8.9 MB     00:01    
利用可能なパッケージ
名前         : certbot
バージョン   : 1.12.0
リリース     : 1.el8
Arch         : noarch
サイズ       : 50 k
ソース       : certbot-1.12.0-1.el8.src.rpm
リポジトリー : epel
概要         : A free, automated certificate authority client
URL          : https://pypi.python.org/pypi/certbot
ライセンス   : ASL 2.0
説明         : certbot is a free, automated certificate authority that aims
             : to lower the barriers to entry for encrypting all HTTP traffic on the internet.
# dnf install certbot
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.

メタデータの期限切れの最終確認: 0:02:16 時間前の 2021年02月26日 01時10分34秒 に実施しました。
依存関係が解決しました。
================================================================================================================================================
 パッケージ                              アーキテクチャー     バージョン                                          リポジトリー            サイズ
================================================================================================================================================
インストール:
 certbot                                 noarch               1.12.0-1.el8                                        epel                     50 k
依存関係のインストール:
 python3-acme                            noarch               1.12.0-1.el8                                        epel                     88 k
 python3-certbot                         noarch               1.12.0-1.el8                                        epel                    390 k
 python3-configargparse                  noarch               0.14.0-6.el8                                        epel                     36 k
 python3-distro                          noarch               1.4.0-2.module_el8.4.0+666+456f5f48                 appstream                37 k
 python3-josepy                          noarch               1.6.0-1.el8                                         epel                     96 k
 python3-ndg_httpsclient                 noarch               0.5.1-4.el8                                         epel                     53 k
 python3-parsedatetime                   noarch               2.5-1.el8                                           epel                     79 k
 python3-pyOpenSSL                       noarch               19.0.0-1.el8                                        appstream               103 k
 python3-pyasn1                          noarch               0.3.7-6.el8                                         appstream               126 k
 python3-pyrfc3339                       noarch               1.1-1.el8                                           epel                     19 k
 python3-requests-toolbelt               noarch               0.9.1-4.el8                                         epel                     91 k
 python3-zope-component                  noarch               4.3.0-8.el8                                         epel                    313 k
 python3-zope-event                      noarch               4.2.0-12.el8                                        epel                    210 k
 python3-zope-interface                  x86_64               4.6.0-1.el8                                         epel                    158 k
弱い依存関係のインストール:
 python-josepy-doc                       noarch               1.6.0-1.el8                                         epel                     22 k

トランザクションの概要
================================================================================================================================================
インストール  16 パッケージ

ダウンロードサイズの合計: 1.8 M
インストール後のサイズ: 7.1 M
これでよろしいですか? [y/N]: 

Certbotコマンドの動作確認

# certbot --version
certbot 1.12.0
# certbot --help

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:

obtain, install, and renew certificates:
    (default) run   Obtain & install a certificate in your current webserver
    certonly        Obtain or renew a certificate, but do not install it
    renew           Renew all previously obtained certificates that are near
expiry
    enhance         Add security enhancements to your existing configuration
   -d DOMAINS       Comma-separated list of domains to obtain a certificate for

  (the certbot apache plugin is not installed)
  --standalone      Run a standalone webserver for authentication
  (the certbot nginx plugin is not installed)
  --webroot         Place files in a server's webroot folder for authentication
  --manual          Obtain certificates interactively, or using shell script
hooks

   -n               Run non-interactively
  --test-cert       Obtain a test certificate from a staging server
  --dry-run         Test "renew" or "certonly" without saving any certificates
to disk

manage certificates:
    certificates    Display information about certificates you have from Certbot
    revoke          Revoke a certificate (supply --cert-name or --cert-path)
    delete          Delete a certificate (supply --cert-name)

manage your account:
    register        Create an ACME account
    unregister      Deactivate an ACME account
    update_account  Update an ACME account
  --agree-tos       Agree to the ACME server's Subscriber Agreement
   -m EMAIL         Email address for important account notifications

More detailed help:

  -h, --help [TOPIC]    print this message, or detailed help on a topic;
                        the available TOPICS are:

   all, automation, commands, paths, security, testing, or any of the
   subcommands or plugins (certonly, renew, install, register, nginx,
   apache, standalone, webroot, etc.)
  -h all                print a detailed help page including all topics
  --version             print the version number
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Shion TanakaShion Tanaka

python3-certbot-nginxがインストールできない

CentOS Forumでの報告
https://forums.centos.org/viewtopic.php?f=54&t=77134

BugzillaでのIssue
https://bugzilla.redhat.com/show_bug.cgi?id=1931256

エラーログ

# dnf install python3-certbot-nginx
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.

メタデータの期限切れの最終確認: 0:13:59 時間前の 2021年02月26日 01時10分34秒 に実施しました。
エラー: 
 問題: conflicting requests
  - nothing provides python3.6dist(pyparsing) >= 2.2.0 needed by python3-certbot-nginx-1.12.0-1.el8.noarch
(インストール不可のパッケージをスキップするには、'--skip-broken' を追加してみてください または、'--nobest' を追加して、最適候補のパッケージのみを使用しないでください)
Shion TanakaShion Tanaka

証明書の作成

今回はスタンドアローンモードで実行して、サーバー上に生成されたファイルが自動で配置される方法を採用。

Certbotコマンド実行

スタンドアローンモードで実行。--cert-nameには任意で名前をつける。申請するドメイン名が無難。

# certbot certonly --cert-name <domain name>

TCP 80ポートのチェックでエラー

ウィザード内でサーバーの存在チェックにTCP 80へのアクセスが行われる。一時的にポートの開放が必要。
Certbot自体が一時的にTCP 80の待ち受けウェブサーバーを立てる模様。

下記はポートチェックに失敗したログ

# certbot certonly --cert-name <domain name>
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): <Your Email Address>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
Account registered.
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): <domain name>
Requesting a certificate for <domain name>
Performing the following challenges:
http-01 challenge for <domain name>
Waiting for verification...
Challenge failed for domain <domain name>
http-01 challenge for <domain name>
Cleaning up challenges
Some challenges have failed.

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: <domain name>
   Type:   connection
   Detail: Fetching
   http://<domain name>/.well-known/acme-challenge/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:
   Timeout during connect (likely firewall problem)

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address. Additionally, please check that
   your computer has a publicly routable IP address and that no
   firewalls are preventing the server from communicating with the
   client. If you're using the webroot plugin, you should also verify
   that you are serving files from the webroot path you provided.

TCP 80のポートチェックに成功し、SSL証明書が生成された場合

ポートチェックに成功し、ウィザードが正常に終了した場合のログ

# certbot certonly --cert-name <domain name>
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Plugins selected: Authenticator standalone, Installer None
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): <domain name>
Requesting a certificate for <domain name>
Performing the following challenges:
http-01 challenge for <domain name>
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/<domain name>/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/<domain name>/privkey.pem
   Your certificate will expire on 2021-05-27. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - 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

生成されたファイル群

# tree /etc/letsencrypt/
/etc/letsencrypt/
├── accounts
│   └── acme-v02.api.letsencrypt.org
│       └── directory
│           └── xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
│               ├── meta.json
│               ├── private_key.json
│               └── regr.json
├── archive
│   └── <domain name>
│       ├── cert1.pem
│       ├── chain1.pem
│       ├── fullchain1.pem
│       └── privkey1.pem
├── csr
│   ├── 0000_csr-certbot.pem
│   ├── 0001_csr-certbot.pem
│   └── 0002_csr-certbot.pem
├── keys
│   ├── 0000_key-certbot.pem
│   ├── 0001_key-certbot.pem
│   └── 0002_key-certbot.pem
├── live
│   ├── README
│   └── <domain name>
│       ├── README
│       ├── cert.pem -> ../../archive/<domain name>/cert1.pem
│       ├── chain.pem -> ../../archive/<domain name>/chain1.pem
│       ├── fullchain.pem -> ../../archive/<domain name>/fullchain1.pem
│       └── privkey.pem -> ../../archive/<domain name>/privkey1.pem
├── renewal
│   └── <domain name>.conf
└── renewal-hooks
    ├── deploy
    ├── post
    └── pre
Shion TanakaShion Tanaka

NGINXの設定

NGINXのドキュメント
https://docs.nginx.com/nginx/admin-guide/

NGINXのインストール

# dnf install nginx

nginx.conf修正

デフォルトのサーバー部分をコメントアウト

/etc/nginx/nginx.conf
#    server {
#        listen       443 ssl http2 default_server;
#        listen       [::]:443 ssl http2 default_server;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        location / {
#        }
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

リバースプロキシ向けNGINXコンフィグ

下記を参考
https://docs.rocket.chat/installation/manual-installation/configuring-ssl-reverse-proxy

/etc/nginx/conf.d/ に配置

default.conf
# Upstreams
upstream backend {
    server localhost:3000;
}

# HTTPS Server
server {
    listen 443;
    server_name <domain name>;

    # You can increase the limit if your need to.
    client_max_body_size 200M;

    error_log /var/log/nginx/rocketchat.access.log;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/<domain name>/cert.pem;
    ssl_certificate_key /etc/letsencrypt/live/<domain name>/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # don’t use SSLv3 ref: POODLE

    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;
    }
}
  • ドキュメントからの変更点はssl_certificatessl_certificate部分
    • Certbotで作成したファイルを直接指定
  • server_nameは使用するホスト名を設定