全国オンライン対応受付 平日 9:00-18:00
お問い合わせ

開発記録 / simpleRec制作記 / Vol.22 simpleRec制作記 Vol.1

記事 03

Docker + Nginx + Let's Encrypt——EC2上の本番環境構築

FastAPIの認証処理がpasslibで書いてある。ログインしようとすると失敗する。ライブラリのバージョン問題だった。passlibとbcryptの最新版の間に、互換性の問題が起きていた。

2026-06-07 公開

パスワードが検証できなかった。

FastAPIの認証処理がpasslibで書いてある。ログインしようとすると失敗する。ライブラリのバージョン問題だった。passlibとbcryptの最新版の間に、互換性の問題が起きていた。

本番環境の構築はこういうことが起きる。


なぜDockerを使うのか

EC2に直接Pythonをインストールしてデプロイする方法もある。設定は単純だ。

しかし既存のEC2インスタンスにはDXゲーム・orderocr・その施工会社など複数のサービスが同居している。Pythonのバージョン・ライブラリのバージョンがぶつかるリスクがある。

simpleRecは別の専用インスタンス(ap-southeast-2・シドニー)に置くことにした。AWS Rekognitionをシドニーリージョンで使うため、同じリージョンのEC2から呼ぶことでレイテンシを最小化する。

Dockerコンテナにすることで、依存関係の分離と環境の再現性が得られる。ローカルで動けば本番でも動く。


docker-compose.yml

version: '3.8'
services:
  app:
    build: .
    container_name: simplerec-app
    ports:
      - '8080:8080'
    environment:
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
    volumes:
      - ./backend/service_account.json:/app/service_account.json:ro
    restart: always

GoogleスプレッドシートへのアクセスにはGoogle Cloudのサービスアカウントキー(service_account.json)が必要だ。コンテナにボリュームマウントして渡す。.gitignoreに追加してリポジトリには含めない。


nginxの設定

nginxはEC2に直接インストールして、Dockerコンテナの8080番ポートへのリバースプロキシとして動く。

server {
    listen 443 ssl;
    server_name app.simplerec.jp;

    ssl_certificate     /etc/letsencrypt/live/app.simplerec.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.simplerec.jp/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_ignore_client_abort on;
        client_max_body_size 10M;
    }
}

server {
    listen 80;
    server_name app.simplerec.jp;
    return 301 https://$host$request_uri;
}

proxy_ignore_client_abort onはVIGIカメラのfire-and-forget(接続後即切断)に対応するための設定だ。client_max_body_size 10Mは画像アップロードのため。


Let's Encryptで即HTTPS化

カメラがHTTPSでWebhookを送るため、HTTPS対応は必須だ。

apt install certbot python3-certbot-nginx
certbot --nginx -d app.simplerec.jp

certbotのnginxプラグインを使うと、Let's Encryptの証明書取得とnginxの設定更新が自動で行われる。証明書は90日で期限が切れるが、certbot renewをcrontabで自動実行することで更新される。


passlibとbcryptの互換性問題

本題のパスワード問題に戻る。

passlibはFastAPIのチュートリアルでよく使われるパスワードハッシュライブラリだ。しかしpasslib 1.7.xと最新版のbcryptの間に互換性の問題がある。起動時に警告が出て、パスワード検証が失敗するケースがあった。

passlibを使わずにbcryptライブラリを直接使うように変更した。

import bcrypt

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()

def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode(), hashed.encode())

passlibの抽象化レイヤーが不要になる。直接使うことでライブラリの互換性問題が消えた。シンプルな実装の方が、余分なレイヤーによる問題を避けられる。


Google Workspace組織ポリシーの問題

Google Cloudでサービスアカウントキーを作成しようとしたとき、「iam.disableServiceAccountKeyCreation」というポリシーでキー作成がブロックされた。法人のGoogle Workspaceアカウント(itoh@simplesystem.co.jp)に組織ポリシーが適用されていたためだ。

個人のGmailでGoogle Cloudプロジェクトを作成してサービスアカウントキーを取得した。Google Sheetsのスプレッドシートにはそのサービスアカウントを「編集者」として招待することで、法人アカウントのスプレッドシートにアクセスできるようにした。

組織ポリシーという見えない壁が、設定の途中で突然現れた。ツールと環境の組み合わせによって生じる問題は、作ってみるまで分からないことがある。


本番運用の現状

VIGIカメラからのWebhookを受けて、AWS Rekognitionで顔認識し、LINEに通知するという一連のフローが動作確認済みだ。開発者本人の顔を99%の信頼度で認識した。

次のフェーズは実際のテナント(店舗)への導入テストだ。環境は整っている。あとは実際に使ってもらってフィードバックを受ける。


*シンプルシステム株式会社 代表 伊藤勝彦*