Files
360_player/Dockerfile
T
JianMiauandClaude Opus 5 0a3c548e0b 移除 nginx 容器,改由 Node 直接終結 TLS,合併成單一容器
摘要:
拿掉 360-player-web(nginx)服務與 docker/nginx/,改在 server.js 用
node:https 直接提供 HTTPS,部署從兩個容器變成一個。

根本原因:
先前為了 TLS 而多開一個 nginx 容器。分開的主因是「憑證續期時能 reload
而不重啟 app」——重啟會殺掉正在跑的 ffmpeg 轉檔,一部 4K 360 影片動輒數小時。
但 Node 的 https.Server 本來就有 setSecureContext(),可以熱換憑證不重啟行程,
這個理由不成立,多一個容器只是多一層維護成本。

影響:
- 需維護額外的 nginx 映像檔與 entrypoint.sh
- 影片經反向代理多一跳,且必須小心處理 proxy_buffering 與 SSE 逾時,
  設錯會讓 Range 串流被寫進暫存檔、或讓轉檔進度停止更新

修法:
- server.js 新增 TLS:讀取 SSL_CERT_DIR 的憑證,以 fs.watch 監看該資料夾,
  檔案變動時 debounce 1 秒後呼叫 setSecureContext() 熱套用
- 中介憑證串進 cert 而非 ca:Node 只送出 cert 的內容,ca 是驗證對方用的
  信任庫、不會送給瀏覽器,放錯會導致憑證鏈不完整
- 串接前正規化 PEM(去 CRLF、補結尾換行),沿用原 nginx entrypoint 的處理
- config.json 新增 httpsPort(預設 0 = 停用)與 certDir,本機開發不需憑證;
  憑證讀不到時退回只提供 HTTP 並印警告,不讓服務起不來
- docker-compose.yml 併回單一服務,憑證改掛 /certs;Dockerfile 補上
  HTTPS_PORT、SSL_CERT_DIR,EXPOSE 改為 8443
- 刪除 docker/nginx/

驗證(實機執行,非僅靜態檢查):
- 以 SSL_CERT_DIR=/volume1/docker/certs 啟動,log 顯示
  「HTTPS:jianmiau.tk — 14 天後到期」,https 的 /api/config 回 200
- openssl s_client 確認送出完整三層憑證鏈
  (jianmiau.tk → Let's Encrypt YR2 → ISRG Root YR)
- HTTPS 上的 Range 請求正常:檔頭與中段各取一段皆回 206 且長度正確
- 熱換測試:換上 CN=hotswap-test.local 的自簽憑證後,log 出現
  「憑證已重新載入」,s_client 讀到新 CN,且行程 PID 與啟動時間不變

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 15:09:56 +08:00

34 lines
985 B
Docker
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
FROM node:22-alpine
# ffmpeg / ffprobe:偵測 360 metadata 與轉檔。
# intel-media-driver / libva-intel-driverNAS 有 Intel 內顯並把 /dev/dri 掛進來時,可用 VAAPI 硬體轉檔。
# tini:正確回收 ffmpeg 子程序、把 docker stop 的 SIGTERM 轉給 node。
RUN apk add --no-cache ffmpeg intel-media-driver libva-intel-driver tini
WORKDIR /app
ENV NODE_ENV=production \
PORT=8360 \
HTTPS_PORT=8443 \
HOST=0.0.0.0 \
VIDEO_DIR=/videos \
CACHE_DIR=/cache \
SSL_CERT_DIR=/certs
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY server.js config.json ./
COPY lib ./lib
COPY public ./public
VOLUME ["/videos", "/cache"]
EXPOSE 8443
# HEALTHCHECK 走容器內的 HTTP,不受憑證影響(8360 不對外開)。
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget -qO- http://127.0.0.1:8360/api/config >/dev/null || exit 1
ENTRYPOINT ["tini", "--"]
CMD ["node", "server.js"]