這個 Nginx proxy 安裝在 TAMS 主機上,統一處理 HTTPS/WSS,並依網域將流量送往 TAMS、HMI 與 rosbridge。
| 網址 | 目的地 |
|---|---|
https://tams.hospital.internal | TAMS frontend、backend、Swagger、Socket.IO |
https://hmi-amr701.hospital.internal | HMI frontend、backend、Swagger、Socket.IO |
wss://amr701.hospital.internal | AMR rosbridge |
以下命令都從 PolyMedX workspace 根目錄執行。
前置條件
- Docker 與 Docker Compose 已啟動。
- TAMS 主機可連到 AMR 的
5173、3000、9090。 - 主機的
80、443尚未被其他程式占用;測試時也可改用8080、8443。 - TAMS backend 與 frontend 使用同一個
tams-network。
建立設定
make edge-init這會建立 workspace-config/edge-proxy/.env;若檔案已存在則保留原檔,不會覆寫。
開發環境範例:
SSL_BASE_DOMAIN=hospital.internal
TAMS_DOMAIN=tams.hospital.internal
HMI_DOMAIN=hmi-amr701.hospital.internal
AMR_DOMAIN=amr701.hospital.internal
TAMS_APP_UPSTREAM=frontend:80
TAMS_API_UPSTREAM=backend:3000
TAMS_API_PREFIX=/api
AMR_IP=172.18.35.29
HMI_APP_UPSTREAM=${AMR_IP}:5173
HMI_API_UPSTREAM=${AMR_IP}:3000
ROS_BRIDGE_UPSTREAM=${AMR_IP}:9090
SELF_SIGNED=true
HSTS_MAX_AGE=0
HTTP_PORT=80
HTTPS_PORT=443注意:
- 本機開發 Compose 的 backend 通常使用
backend:3000。 - 正式 Compose 的 backend 使用
backend:9000。 TAMS_API_PREFIX必須與 backend 的DEFAULT_API_ROUTER_PREFIX相同。- 容器中的
localhost是容器自己;主機上的服務要使用host.docker.internal:<port>。
設定測試網域
不需要先購買網域。假設 TAMS 主機 IP 是 192.168.1.100,在每台測試用戶端的 /etc/hosts 加入:
192.168.1.100 tams.hospital.internal
192.168.1.100 hmi-amr701.hospital.internal
192.168.1.100 amr701.hospital.internal三個名稱可以指向同一個 IP;Nginx 會根據 hostname 決定 upstream。不要只使用 https://192.168.1.100,否則無法區分 TAMS、HMI 與 rosbridge。
只用 curl 測試時,可以不修改 /etc/hosts:
curl -k \
--resolve tams.hospital.internal:443:192.168.1.100 \
https://tams.hospital.internal/啟動 upstream 服務
開發環境:
make build-up
make ps正式環境:
make prod-build-up
make prod-ps另外確認 HMI frontend、HMI backend 與 rosbridge 已在 AMR 上啟動。
檢查 Docker network:
docker network inspect tams-networkTAMS backend、frontend 與 nginx-ssl 最終都應連到 tams-network。
驗證設定
make edge-config
make edge-validateedge-config:檢查 Compose 展開結果。edge-validate:建置 image、產生 Nginx 設定並執行nginx -t。
edge-validate 不要求 upstream 已在線;它會在語法檢查時暫時使用 loopback IP。
啟動 edge proxy
make edge-build-up
make edge-ps
make edge-logs正常啟動後測試:
make edge-smoke從另一台電腦測試 proxy:
EDGE_PROXY_HOST=192.168.1.100 make edge-smokeSmoke test 會檢查:
- HTTP 是否轉址到 HTTPS。
- TAMS 與 HMI frontend。
- TAMS API 是否錯誤落入 SPA。
- Socket.IO polling handshake。
- rosbridge WSS upgrade。
信任開發憑證
SELF_SIGNED=true 產生的是開發憑證。瀏覽器出現 ERR_CERT_AUTHORITY_INVALID 是正常現象;憑證必須安裝在開啟網頁的用戶端,而不只是 TAMS 主機。
macOS 先確認憑證:
openssl x509 \
-in workspace-config/edge-proxy/certs/server.crt \
-noout -subject -issuer -dates -ext subjectAltName -fingerprint -sha256確認是自己產生的憑證後,加入 System Keychain:
sudo security add-trusted-cert \
-d \
-r trustRoot \
-k /Library/Keychains/System.keychain \
workspace-config/edge-proxy/certs/server.crt完全關閉並重新開啟 Chrome,再訪問:
https://tams.hospital.internal不要在不確定來源時信任憑證。正式環境應使用醫院內部 CA 或可信任 CA 簽發的憑證。
常用命令
| 命令 | 用途 |
|---|---|
make edge-init | 安全建立 .env |
make edge-config | 展開 Compose 設定 |
make edge-validate | 建置並執行 nginx -t |
make edge-build | 只建置 image,不啟動服務 |
make edge-up | 啟動既有 image |
make edge-build-up | 建置並啟動 |
make edge-restart | 重新啟動 |
make edge-down | 停止並移除 container |
make edge-ps | 查看狀態 |
make edge-logs | 持續顯示 nginx-ssl log |
make edge-logs SERVICE=<服務名稱> | 持續顯示指定服務的 log |
make edge-smoke | 測試 proxy 與 upstream 路由 |
若正式設定放在 workspace 外:
make edge-validate EDGE_ENV=/etc/polymedx/edge-proxy.env
make edge-build-up EDGE_ENV=/etc/polymedx/edge-proxy.env常見問題
host not found in upstream "backend"
表示 Nginx 無法透過 Docker DNS 找到 backend。依序檢查:
make ps
docker network inspect tams-network
make edge-config
make edge-restart
make edge-logs確認 backend 已啟動並加入 tams-network。若 backend 在主機上,改用:
TAMS_API_UPSTREAM=host.docker.internal:9000若 backend 在另一台主機,使用可達 IP:
TAMS_API_UPSTREAM=192.168.1.20:9000502 Bad Gateway
DNS 已解析,但 upstream 沒有回應。檢查 IP、port、防火牆以及服務實際監聽位置。開發環境常見原因是把 backend:3000 誤設為 backend:9000。
ERR_CERT_AUTHORITY_INVALID
網域通常沒有問題,而是用戶端尚未信任 self-signed certificate。依「信任開發憑證」章節安裝,或改用醫院 CA 憑證。
正式環境
Sectigo 憑證檢查結果
目前取得的三個檔案是一組完整、可用的 Sectigo 憑證材料:
| 檔案 | 內容 |
|---|---|
STAR_csh.org.tw.crt | *.csh.org.tw 網站憑證,共 1 張 |
SOV-Bundle.crt | Intermediate CA 與 Root CA,共 2 張 |
STAR_csh.org.tw.key | 與網站憑證匹配的 private key |
完整憑證鏈已通過驗證,鏈結如下:
*.csh.org.tw
↓
Sectigo RSA Organization Validation Secure Server CA
↓
USERTrust RSA Certification Authority網站憑證有效期限至 2026-10-02,應在到期前完成換發與部署。這是公開 CA 憑證;主流作業系統與瀏覽器通常已信任 USERTrust Root CA,不需要像 self-signed certificate 一樣手動安裝 Root CA。
修正 private key 權限
若三個原始檔案目前都是 666(-rw-rw-rw-),代表同一台主機的其他使用者可以讀取或修改 private key,必須先修正:
chmod 600 STAR_csh.org.tw.key
chmod 644 STAR_csh.org.tw.crt
chmod 644 SOV-Bundle.crtSTAR_csh.org.tw.key 沒有 passphrase 時尤其依賴檔案權限保護。不要將 private key、憑證或 .env 提交到 Git,也不要把 private key 的內容貼到 log、工單或聊天訊息。
建立 Nginx full chain
SOV-Bundle.crt 同時包含 Intermediate CA 與 Root CA。Nginx 提供給用戶端的 server.crt 一般只需要依序包含:
網站憑證 + Intermediate CA不需要把 Root CA 一併送出。先從 bundle 取出第一張 Intermediate CA:
awk '
/-----BEGIN CERTIFICATE-----/ { count++ }
count == 1 { print }
/-----END CERTIFICATE-----/ && count == 1 { exit }
' SOV-Bundle.crt > sectigo-intermediate.crt建立 Nginx 使用的 full chain,並複製 private key:
cat STAR_csh.org.tw.crt \
sectigo-intermediate.crt \
> server.crt
cp STAR_csh.org.tw.key server.key
chmod 600 server.key
chmod 644 server.crt驗證網站憑證能否透過 bundle 建立信任鏈:
openssl verify \
-CAfile SOV-Bundle.crt \
STAR_csh.org.tw.crt預期結果為:
STAR_csh.org.tw.crt: OK安全存放與掛載
正式主機建議將部署用憑證放在 workspace 外的 root 管理目錄:
/etc/polymedx/tls/server.crt
/etc/polymedx/tls/server.key目錄與 private key 應限制存取,並將 Docker volume 設為唯讀:
volumes:
- /etc/polymedx/tls:/etc/nginx/certs:ro主機路徑是 /etc/polymedx/tls;以下 SSL_CERT 與 SSL_KEY 則是 Nginx 容器內看到的路徑。
Edge proxy 設定
正式 .env 範例:
SSL_BASE_DOMAIN=csh.org.tw
TAMS_DOMAIN=tams.csh.org.tw
HMI_DOMAIN=hmi-amr701.csh.org.tw
AMR_DOMAIN=amr701.csh.org.tw
SSL_CERT=/etc/nginx/certs/server.crt
SSL_KEY=/etc/nginx/certs/server.key
SELF_SIGNED=false
HSTS_MAX_AGE=0先保持 HSTS_MAX_AGE=0,檢查 Compose 展開結果、Nginx 設定與實際憑證鏈後再啟用長期 HSTS:
make edge-config
make edge-validate
make edge-build-up
make edge-ps
make edge-logs確認所有正式網域都能以可信任憑證正常連線後,才考慮改成:
HSTS_MAX_AGE=31536000HSTS 會讓瀏覽器在有效期間內強制使用 HTTPS;憑證或 HTTPS 設定若仍有問題,過早啟用會增加復原難度。
DNS 與院外測試
正式環境應由醫院 IT 將 DNS 指向 TAMS edge proxy,例如:
*.csh.org.tw -> <TAMS host IP>正式 DNS 尚未切換時,可先在測試機的 /etc/hosts 將三個名稱指向 proxy IP:
192.168.1.100 tams.csh.org.tw
192.168.1.100 hmi-amr701.csh.org.tw
192.168.1.100 amr701.csh.org.tw測試公開 CA 憑證時不要使用 -k,否則會略過憑證驗證:
curl \
--resolve tams.csh.org.tw:443:192.168.1.100 \
https://tams.csh.org.tw/只要 server.crt 正確包含 Intermediate CA,而且測試機的公開 Root CA trust store 正常,即使測試機沒有外網,也應能完成 TLS 信任鏈驗證。
架構圖
flowchart LR
Browser["瀏覽器"] ==>|"HTTPS/WSS 加密"| Nginx
Nginx["Nginx Edge Proxy<br/>*.csh.org.tw"]
subgraph Docker["TAMS Docker Network"]
Frontend["TAMS Frontend"]
Backend["TAMS Backend"]
RMF["RMF API"]
Redis["Redis"]
end
MongoDB["MongoDB"]
subgraph AMRHost["AMR 主機"]
HMI["HMI Frontend/Backend"]
Rosbridge["rosbridge"]
end
Nginx -.->|"HTTP"| Frontend
Nginx -.->|"HTTP"| Backend
Nginx -.->|"HTTP"| HMI
Nginx -.->|"WebSocket"| Rosbridge
Backend -.->|"HTTP"| RMF
Backend -.->|"Redis Protocol"| Redis
Backend -->|"MongoDB Protocol"| MongoDB
classDef secure fill:#d8f3dc,stroke:#2d6a4f
classDef plain fill:#fff3bf,stroke:#e67700
classDef optional fill:#e7f5ff,stroke:#1971c2
class Nginx secure
class Frontend,Backend,RMF,Redis,HMI,Rosbridge plain
class MongoDB optional重點:
目前 TLS 加密只涵蓋「用戶端到 Nginx Edge Proxy」這一段;Nginx 完成 TLS termination 後,到各 upstream 仍使用 HTTP/WS 明文連線。
- 瀏覽器到 Nginx:HTTPS/WSS 加密。
- Nginx 到各服務:目前為 HTTP/WS 明文。
- TAMS Backend 到 RMF API、Redis:Docker Network 內明文。
- MongoDB:是否啟用 TLS 由連線設定與 MongoDB Server 共同決定。