2018年6月20日水曜日

Let's EncryptをNginxで使用する

目的

自宅にSSL接続が行えるWebServerが必要になったので用意


構成

ドメイン(https://test.yoshio.me)が使えるようにする

WebサーバはNginx

サーバーとなるのはRaspberry pi3B


準備

必要なソフトのインストール

$cd certbotを置きたいパス
$sudo apt-get install git
$git clone https://github.com/certbot/certbot
$cd certbot

証明書取得

Certbotをスタンドアロンモードで使用しWebサーバー無しで証明書を取得

$./certbot-auto certonly --standalone -t

足りないパッケージが出るため、yを押して承認



2020/06/13追記

コンパイルを省略する為にスクリプトが別箇所からバイナリを取ってくるらしく必要なライブラリがハッシュが違うと言ってくる

THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
    pycparser==2.19 from https://www.piwheels.org/simple/pycparser/pycparser-2.19-py2.py3-none-any.whl#sha256=bc15573b7c6edd24407526dbbc7a0bd33d80d8af44231c37f58d73f56ff9cab6 (from -r /tmp/tmp.ULi7aj6FeV/letsencrypt-auto-requirements.txt (line 115)):
        Expected sha256 a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
             Got        bc15573b7c6edd24407526dbbc7a0bd33d80d8af44231c37f58d73f56ff9cab6

    zope.component==4.6 from https://www.piwheels.org/simple/zope-component/zope.component-4.6-py2.py3-none-any.whl#sha256=74f55521dec189c08d98341edce929eba6bb2404662d1878f1b289af46f6f6a5 (from -r /tmp/tmp.ULi7aj6FeV/letsencrypt-auto-requirements.txt (line 137)):
        Expected sha256 ec2afc5bbe611dcace98bb39822c122d44743d635dafc7315b9aef25097db9e6
             Got        74f55521dec189c08d98341edce929eba6bb2404662d1878f1b289af46f6f6a5

修正方法は多くあり、apt-get install certbot

もしくはcertbot-autoを開き、Expected sha256を得られる値に書き換える



Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): xxx@xxx.xxxx

Emailアドレスを入れろ(お知らせとセキュリティ情報に使用)と言われるので、とりあえず入れる

-------------------------------------------------------------------------------
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-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A

-------------------------------------------------------------------------------
Would you be willing 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
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): test.yoshio.me

一つ目がサービスの利用規約に同意しろ、二つ目が入力したメルアドにお知らせを送っていいかです

Cleaning up challenges
Problem binding to port 80: Could not bind to IPv4 or IPv6.

もしも既にport80が何かに使われていると上記のようなメッセージが出ますので素直にサーバーを止めます

Timeout during connect (likely firewall problem)

このエラーは80番ポートを開けていない時に出ます。80番と443番を開けておきましょう

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

Congratulations!と出たら成功です、

期限は3ヶ月なので2018-09-18まで有効の証明書を/etc/letsencrypt/live/test.yoshio.me/以下に手に入れました

Nginx設定(SSLでアクセス出来るかテスト)

nginx設定変更

設定を書き換えて、とりあえず証明書を使ってSSLを実現します

$vim /etc/nginx/sites-enabled/default

SSLを見るようにする

listen [::]:80 default_server;
#追加
listen 443 ssl;

証明書の参照

server_name _;
#追加
ssl_certificate /etc/letsencrypt/live/test.yoshio.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test.yoshio.me/privkey.pem;

本変更で完了です nginxを起動させます

$sudo /etc/init.d/nginx start

注意点

引っかかったところとしては、SSLはポート443だが、80しか開けていなかったためアクセスできないエラーに陥った


Nginx設定(証明書自動更新準備)


webrootを使った更新

-wで設定するファイルはlet's encryptがアクセスして来る箇所になる模様、あとでnginxの設定値を変えてアクセスを許可する

sudo mkdir /var/www/letsencrypt
./certbot-auto certonly --webroot -w /var/www/letsencrypt -d test.yoshio.me --agree-tos --force-renewal -n

実行後のログで下記のようなことが出たら成功です


Requesting to rerun ./certbot-auto with root privileges...
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for test.yoshio.me
Using the webroot path /var/www/letsencrypt for all unmatched domains.
Waiting for verification...
Cleaning up challenges

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

80番ポートをLet's Encrypt専用にする

/etc/nginx/sites-enabled/defaultを書き換えます

server {
    listen 80 default_server;
 listen [::]:80 default_server;
  
   location ^~ /.well-known {
  root /var/www/letsencrypt;
    }
 
    location / {
  return 301 https://$host$request_uri;
 }
}
server {
    listen 443 ssl;
 
 root /var/www/html;
 
 index index.html;
 
 server_name _;
 ssl_certificate /var/letsencrypt/live/test.yoshio.me/fullchain.pem;
 ssl_certificate_key /var/letsencrypt/live/test.yoshio.me/privkey.pem;
 
     location / {
     try_files $url $url/ =404;
 }
}

証明書リニューアルテスト

コマンドを叩いてテストして見る、以下のようなログが出たら完了

$./certbot-auto renew --force-renewal

Requesting to rerun ./certbot-auto with root privileges...
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/test.yoshio.me.conf
-------------------------------------------------------------------------------
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for test.yoshio.me
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/test.yoshio.me/fullchain.pem
-------------------------------------------------------------------------------
Plugins selected: Authenticator webroot, Installer None

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

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/test.yoshio.me/fullchain.pem (success)
-------------------------------------------------------------------------------

Cronを使っての自動実行

設定ファイルを用意

意味は毎月24日の朝6時に上でやったコマンドを実行してねということです

$sudo vim /etc/cron.d/letencrypt
00 06 24 * * /usr/local/certbot/certbot-auto renew --force-renewal

cronに読み込み

$sudo crontab letencrypt
$sudo crontab -l
00 06 24 * * /usr/local/certbot/certbot-auto renew --force-renewal && /etc/init.d/nginx reload

上記だと24日の朝6時という時間帯オンリーなので、本来はスクリプトに飛ばしてばらけた時間にアクセスするべきだと思う


以上!


追記(2020/06/13)

Go言語でひとまずSSLを試す方法

なお、sudoでgoを使う場合は、sudo「コマンドが見つかりません」PATHが初期化されているときの対処法を参照してroot権限で443ポートが使えるようにする

$ cat web.go 
package main

import (
  "fmt"
  "net/http"
  "log"
)

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, World")
}

func main() {
  var crtPath = "/etc/letsencrypt/live/Your Domain/fullchain.pem";
  var keyPath = "/etc/letsencrypt/live/Your Domain/privkey.pem";
  http.HandleFunc("/", handler)
  log.Fatal(http.ListenAndServeTLS(":443", crtPath, keyPath, nil))
}