TOMIFULL

Blog

2026.08.24セキュリティ

Zoom録画の自動保存を作ってBasic認証でハマった4点。500エラーの原因はパスワードファイルの権限でした

Zoom講座の録画を、自動でサーバーへ保存してNotionに記録する仕組みを作りました。

仕組み自体は半日で組めたのですが、Basic認証まわりで4つつまずきました。 どれも検索してもすぐには出てこなかったので、原因と直し方を残しておきます。

エックスサーバーでの話ですが、Apacheを使う共有レンタルサーバーなら同じことが起きます。

作ったもの

月に2回オンライン講座をやっていて、終わるたびに同じ手作業が発生していました。録画をダウンロードし、サーバーに上げ、資料を用意し、一覧にリンクを貼る。1回30分ほどですが、「あとでやろう」が積み上がります。

そこでこう組みました。

Zoom(クラウド録画)
   ↓ 新しい録画を探して自動ダウンロード
レンタルサーバー(Basic認証つきのフォルダ)
   ↓ 動画リンクと資料リンクを書き込み
Notion(一覧データベース)

毎朝1回動き、新しい録画がなければ何もせず終わります。会議名で対象を判定するので、講座以外の録画は拾いません。

使った部品は3つだけです。

やること 使ったもの
録画の一覧取得とダウンロード Zoom API(Server-to-Server OAuth)
サーバーへの転送 scp
一覧に1行追加 Notion API

追加のライブラリは入れず、Python標準ライブラリとssh/scpだけで動いています。Zoomのアプリ作成もNotionのインテグレーション発行も無料でした。追加費用はゼロです。

ここまでは半日で組めました。つまずいたのは、この先の「限定公開」です。

配布先は受講者だけなので、置き場所にはBasic認証をかけます。この設定で4回ハマりました。

つまずき1:認証情報を送った瞬間だけ500になる

設定を入れて、ブラウザで開くとパスワードを聞かれる。ここまでは正常でした。

IDとパスワードを入力した瞬間、500 Internal Server Error。

何度入れ直しても同じ。パスワードが合っているかどうかに関係なく500になります。

原因は.htpasswdの権限でした。

-rw-------  .htpasswd   ← 所有者だけが読める。これがダメ

秘密の情報だから厳しくしよう、と600にしていました。ところがWebサーバーのプロセスは別のユーザーとして動いているため、このファイルを開けません。開けないので処理が失敗し、500になります。

chmod 644 /home/ユーザー名/example.com/.htpasswd

644にしたら解決しました。

「誰でも読める設定にして大丈夫なのか」と思うところですが、次の2つを満たしていれば問題ありません。

  • 公開領域(public_html)の外に置く
  • 中身は暗号化されたハッシュで、パスワードそのものではない

念のため、URLから読めないことも確認しておきます。

curl -o /dev/null -w "%{http_code}\n" https://example.com/.htpasswd
# 403 か 404 が返ればOK

エックスサーバーの管理画面が作るアクセス制限ファイルも644です。

つまずき2:401が返っても、守られているとは限らない

これが一番こわい落とし穴でした。

設定を確認するとき、こうやっていました。

curl -o /dev/null -w "%{http_code}\n" https://example.com/secret/
# 401 → よし、認証がかかっている

これでは分かりません。

「パスワードを入力してください」という401の応答は、パスワードファイルを1バイトも読まずに返せます。ファイルを読みにいくのは、利用者が「このIDとパスワードで入ります」と送ってきた瞬間だけです。

つまり、こうなります。

確認のしかた 返るもの 分かること
認証情報を送らない 401 壊れていても401。何も分からない
間違ったパスワードを送る 401なら正常/500なら異常 ここで初めて実態が見える
正しいパスワードを送る 200 利用者が本当に入れるか

3つ全部やって、はじめて「かかっている」と言えます。

U=https://example.com/secret/
curl -o /dev/null -w "認証なし: %{http_code}\n" "$U"
curl -o /dev/null -w "誤PW:    %{http_code}\n" -u "user:wrong-password" "$U"
curl -o /dev/null -w "正PW:    %{http_code}\n" -u "user:正しいパスワード" "$U"

期待する結果は 401 / 401 / 200 です。真ん中が500なら、設定が壊れています。

さらに大事なのが、守りたいファイルそのもののURLを叩くこと。 フォルダのトップだけ確認して安心すると、1階層下が無防備でも気づけません。

curl -o /dev/null -w "%{http_code}\n" -r 0-100 "$U/video.mp4"

動画やPDFなど、実際に守りたいファイルを名指しで確認してください。

つまずき3:ハッシュ形式で弾かれることがある

500の原因を探る過程で、ハッシュ形式も疑いました。結果としては権限が原因でしたが、環境によってはこちらが原因になります。

htpasswd -nbB user password   # bcrypt。環境によっては検証できない
htpasswd -nbm user password   # APR1-MD5。共有サーバーで無難

-B(bcrypt)はセキュリティ的には強いのですが、サーバー側のApacheが対応していないと検証に失敗します。共有レンタルサーバーでは-mが安全です。

ただし、症状は権限のときと同じ「認証情報を送ると500」です。まず権限を確認してから、形式を疑ってください。 私は順番を逆にして遠回りしました。

つまずき4:ファイルを差し替えた瞬間だけエラーになる

パスワードを変更するとき、.htpasswdを上書き転送していました。

転送には数秒かかります。その数秒間、ファイルは不完全な状態です。 ちょうどそのタイミングでアクセスがあると500になります。

別名で送ってからmvで置き換えると、切り替わりが一瞬で済みます。

scp .htpasswd server:/path/.htpasswd.new
ssh server "chmod 644 /path/.htpasswd.new && mv -f /path/.htpasswd.new /path/.htpasswd"

同じファイルシステム内のmvは、中身をコピーせず名前を差し替えるだけなので、途中経過が存在しません。設定ファイルの更新では基本にしておくと安心です。

おまけ:シェルスクリプトが黙って止まる

Basic認証とは別件ですが、同じ作業中にハマったので書いておきます。

パスワードを自動生成する処理で、スクリプトがエラーも出さずに途中で終了しました。

set -euo pipefail
PASS=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16)
echo "できた: $PASS"   # ここまで到達しない

headが16文字取った時点で終了すると、まだ書き込もうとしているtrにSIGPIPEが送られます。trの終了コードは141になり、pipefailとset -eの組み合わせでスクリプト全体が止まります。

正常な動作が異常終了として扱われるわけです。パイプを使わない方法に変えると解決します。

PASS=$(python3 -c "
import secrets, string
pool = string.ascii_letters + string.digits
print(''.join(secrets.choice(pool) for _ in range(16)))
")

set -euo pipefailは安全のために付けるものですが、こういう副作用があります。

Notionの記事を配布用HTMLに変換するときの注意

もう1つ、実用的な話を。

教科書はNotionで書いて、それを配布用のHTMLに変換しています。ここで注意が要るのが画像です。

Notion APIが返す画像URLは1時間ほどで期限切れになります。 そのままHTMLに埋め込むと、翌日には全部表示されなくなります。

対策は、変換時に画像を手元へダウンロードして、相対パスで貼り直すことです。ファイル名はブロックIDから生成すると、同じ画像に毎回同じ名前がついて差分が出ません。

stem = hashlib.sha1(block["id"].encode()).hexdigest()[:12]
name = f"img-{stem}.png"

設計として学んだこと

技術的な話とは別に、作り方の教訓が1つありました。

手順を飛ばせる作りにしない。

「保護をかける」→「ファイルを置く」という順番で運用するつもりでも、順番を守るかどうかを人間の注意力に任せていると、いつか飛びます。急いでいるとき、疲れているとき、割り込みが入ったとき。

いまは、保護の設定ファイルが存在しなければアップロード処理が止まるようにしています。手順書に書くのではなく、飛ばせない仕組みにするのが確実でした。

同じ考えで、作業のたびに前述の3つの確認(401/401/200)が自動で走るようにしています。チェックリストは飛ばせますが、自動で走るテストは飛ばせません。

まとめ

エックスサーバーでBasic認証がうまくいかないときの確認順序です。

  1. .htpasswdの権限は644か(600だと500になる)
  2. 置き場所は公開領域の外か。URLから叩いて403か404を確認
  3. ハッシュ形式はhtpasswd -nbm(APR1-MD5)か
  4. 差し替えは別名転送+mvになっているか
  5. 間違ったパスワードを送って401が返るか(500なら未解決)
  6. 守りたいファイルのURLを直接叩いても401か

5番と6番を省くと、「かかっているつもり」のまま運用が始まります。ここだけは必ず確認してください。


TOMIFULLでは、AIを使った業務自動化の設計と、公開前の安全確認を支援しています。 「作ったけれど、これで本当に大丈夫なのか分からない」という段階のご相談も歓迎します。

読んで気になったことは、そのまま診断・相談してみませんか。

Contact

ご検討の段階に合わせて、3つの入口をご用意しました。

AI適正診断登録不要・数分メールで相談2営業日以内に返信