OpenSSLを用いてサーバー証明書を作ってhttps通信

# サーバー証明書とは

そのサーバの実在証明や、通信内容の暗号化に使用するものである。
正規の認証局を通さず、自分自身のサーバーで発行したサーバー証明書。
今回は自宅内のサーバーとhttps通信したいだけなので問題ない。

# なぜこれを行うのか

iPhoneアプリでセンサーの許可を出すためにはhttpsで暗号化されている必要がある。
hostingサービスを使えばよいが、外部に公開されてしまう。
そこでlocal環境でhttpsを使えるようにすればよいと考えた。

# インストール
```
sudo apt update
```
パッケージリストを更新している。
```
sudo apt install openssl
```
OpenSSLをインストール。
```
openssl version
```
インストールできているか確認

# 鍵を作成
```
openssl genrsa -des3 -out 秘密鍵のパス 2048
```

openssl
OpenSSLのコマンドラインツールを使うことを示す。

genrsa
RSA方式で秘密鍵を生成するコマンド。

-des3
DES3 (トリプルDES) で鍵を暗号化。
生成される秘密鍵自体にパスワード保護をかける。

-out 秘密鍵のパス
生成した秘密鍵をファイルに保存します。
秘密鍵のパスの部分に、保存先のパスやファイル名を指定する。

2048
鍵の長さを指定します。
2048ビットの鍵を生成します。
一般的に「2048ビット以上」が推奨されている。

コマンド入力後、以下のように秘密鍵のパスワードを要求されるので適当なパスワードを入力。
```
Enter pass phrase for 秘密鍵のパス:
Verifying - Enter pass phrase for 秘密鍵のパス:
```

# CSRを作成
```
openssl req -new -key 秘密鍵のパス -out CSRのパス
```
SSL証明書署名要求 (CSR: Certificate Signing Request) を作成するためのもの。CSRは証明書を発行してもらうために必要なファイル。

req
証明書関連の操作を行うOpenSSLサブコマンド。

-new
新しいCSRを作成。

コマンドを実行すると、以下のような入力を求められる。
これらの情報はSSL証明書に反映されるため、正確に入力すること。

入力例
```
Country Name (2 letter code) [XX]: JP
State or Province Name (full name) []: Tokyo
Locality Name (eg, city) [Default City]: Shibuya
Organization Name (eg, company) [Default Company Ltd]: Example Inc.
Organizational Unit Name (eg, section) []: IT Department
Common Name (eg, server FQDN or YOUR name) []: www.example.com
Email Address []: admin@example.com
```
Country Name
→ 国コード (日本ならJP)
State or Province Name
→ 都道府県名 (例: Tokyo)
Locality Name
→ 市区町村名 (例: Shibuya)
Organization Name
→ 会社名や団体名 (例: Example Inc.)
Organizational Unit Name
→ 部署名 (例: IT Department)
Common Name (CN)
→ 証明書を発行するドメイン名 (例: example.com)
※これが最も重要。
Email Address
→ 管理者のメールアドレス。省略可能。

```
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```

これらの項目は必須ではないため、そのままEnterを押して空欄のままで大丈夫。

なぜ空欄で良いのか？
チャレンジパスワードは古い慣習で、現在の証明書発行プロセスでは使われていないらしい。
空欄のままにしておくことで、不要なトラブルを防ぐことが出来るらしい。

# サーバ証明書の作成

本来ならば、CSRを認証局に提出してサーバー証明書を作成してもらうのですが、今回はオレオレ証明書なので自作。
自己署名証明書 (Self-Signed Certificate) を生成。

```
openssl x509 -in CSRのパス -days 365 -req -signkey 秘密鍵のパス -out 作成するサーバ証明書のパス
```

x509
証明書を管理・表示するためのOpenSSLのサブコマンド。
証明書の生成や表示に使う。

-in CSRのパス
先ほど作成したCSRファイルを指定。

-days 365
証明書の有効期間を設定します。この場合は365日。
必要に応じて -days 730 (2年) などに変更可能。

-req
CSRから証明書を生成することを示す。

-signkey 秘密鍵のパス
証明書に署名するための秘密鍵を指定。

-out 作成するサーバ証明書のパス
生成される証明書の保存先を指定。

### 実行例
```
openssl x509 -in /etc/nginx/certs/nginx_server.csr -days 365 -req -signkey /etc/nginx/certs/nginx_server_key.pem -out /etc/nginx/certs/nginx_server.crt
```
```
Enter pass phrase for nginx_server_key.pem:
```
と出るのでパスワードを入力

### 実行結果
```
Signature ok
subject=/C=JP/ST=tokyo/L=hoge/O=company/OU=sales/CN=www.test.com
```

生成された証明書の確認
```
openssl x509 作成するサーバ証明書のパス -text -noout
```
これでテスト環境やローカル開発環境でhttpsが使えるようになった。
イントラネットや個人サーバーで一時的にSSLを有効化。
本番環境では正式な認証局(CA)に証明書を発行してもらう必要がある。

# Webサーバの立ち上げ


nginxのインストール

```
sudo apt update
sudo apt install nginx
```
nginxの設定
```
sudo nano /etc/nginx/sites-available/default
```

パスフレーズ付きの秘密鍵からパスフレーズを削除し、パスフレーズなしの新しい秘密鍵を作成する
```
sudo openssl rsa -in [上でつけた秘密鍵のパス] -out [上でつけた秘密鍵のパス]
```
例
```
sudo openssl rsa -in /etc/nginx/certs/nginx_server_key.pem -out /etc/nginx/certs/nginx_server_key_nopass.pem
```
nginxのdefault設定ファイルを編集
```
sudo nano /etc/nginx/sites-available/default
```
以下に変更
例
```
# HTTPサーバー設定 (ポート80)
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # ドキュメントルートとインデックスファイルの設定
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    # サーバー名 (デフォルトサーバー)
    server_name _;

    # HTTPからHTTPSへのリダイレクト
    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPSサーバー設定 (ポート443)
server {
    listen 443 ssl;
    server_name www.yamada.com;

    # SSL設定 (証明書と秘密鍵のパス)
    ssl_certificate /etc/nginx/certs/nginx_server.crt;
    ssl_certificate_key /etc/nginx/certs/nginx_server_key.pem;
    ssl_password_file /etc/nginx/certs/nginx_passphrase.txt;

    # SSL/TLSプロトコルと暗号スイートの設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # ドキュメントルートとインデックスファイルの設定
    root /var/www/html;
    index index.html;

    # ルートパスの設定
    location / {
        try_files $uri $uri/ =404;
    }
}

# コメントアウトされたPHP設定 (必要に応じて有効化)
# location ~ \.php$ {
#     include snippets/fastcgi-php.conf;
#     fastcgi_pass unix:/run/php/php7.4-fpm.sock;
#     # fastcgi_pass 127.0.0.1:9000;
# }
```
標準では反応してくれなかったので、index.htmlに変更
```
sudo mv /var/www/html/index.nginx-debian.html /var/www/html/index.html
```
nginxの起動
```
sudo systemctl reload nginx
```

アクセス
```
https://192.168.x.x/
```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955514/35e0aedd-eda3-ece3-1f13-0abf4894f1ad.png)
こう表示されますが、自分で作成したので当たり前です。

# 実際に使おう

## windows編
1. 証明書ファイル (.crt) をエクスポート
Nginxの証明書が nginx_server.crt であることを確認する。
証明書をWindowsにコピーまたはダウンロード。
ファイル名例: nginx_server.crt
2. 証明書のインストール
1. 証明書をダブルクリック
.crt ファイルをダブルクリックする。
2. 「証明書のインストール」を選択
「証明書のインストール」ウィザードが開く。
3. ローカルコンピュータまたはユーザーの証明書ストアを選択
「現在のユーザー」または「ローカルコンピュータ」のどちらかを選択。
現在のユーザー: 自分だけが証明書を信頼する。
ローカルコンピュータ: PC全体で証明書が信頼される。（推奨）
「次へ」をクリック。
4. 証明書ストアの選択
「証明書をすべて次のストアに配置する」を選択する。
「参照」から 信頼されたルート証明機関 を選択する。
重要: 信頼されたルート証明機関 にインストールしないと、「セキュリティ保護なし」のエラーが出続る。
3. インストール完了と確認
インストール完了後、ブラウザを再起動し、HTTPSサイトにアクセスして確認する。

こうなれば完成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955514/e5fcfdca-1f24-efa5-39fd-b4af08a205dc.png)

## スマホ編

iPhoneやAndroidにも同様に証明書を送信し、インストール後「完全に信頼する証明書」として有効化。

iPhone:
設定 → 一般 → VPNとデバイス管理 → 証明書を信頼

Android:
設定 → セキュリティ → 証明書のインストール