以 nginx 反向代理 Hermes Web UI(HTTPS + basic auth 實戰)
· #Hermes #nginx #反向代理 #HTTPS #basic auth #教學
Hermes Agent 自帶一個 Web UI(dashboard),預設監聽本機 127.0.0.1:9119,只能在該機器上存取。本文記錄如何透過 nginx 反向代理,讓它從外部網址 https://wiki.nginx.tw:9118/ 也能使用,並加上 HTTPS 加密與 basic auth 密碼保護。
重要前提:Hermes Web UI 是能執行終端指令、讀寫檔案的 AI 代理控制台。對外開放「必須」加驗證與加密,否則任何人都能控制你的主機。
一、整體架構
瀏覽器
│ HTTPS(Let's Encrypt 憑證)
▼
nginx :9118(對外)
├─ SSL 終止
├─ basic auth 密碼保護
└─ proxy_pass → 127.0.0.1:9119(Hermes dashboard 本機)
設計要點:Hermes 仍只聽本機 127.0.0.1:9119,nginx 扮演「對外的門」——負責加密、驗證、再把請求轉進本機。Hermes 本身不需改設定。
二、第一個坑:埠衝突
最初想讓 nginx 也用 9119 對外:
listen 9119 ssl;
nginx -t 雖然通過,但 systemctl reload nginx 後報錯:
bind() to 0.0.0.0:9119 failed (98: Address already in use)
原因:Hermes 已經綁了 127.0.0.1:9119,而 nginx 的 listen 9119 預設會嘗試綁 0.0.0.0:9119(含 loopback),兩者在同一埠碰撞。nginx 無法「排除單一 IP」只綁外部介面,因此無法和 Hermes 共用 9119。
解法:讓 Hermes 繼續佔本機 9119,nginx 改用對外埠 9118,轉發到 127.0.0.1:9119。這樣兩者各佔其一,互不干擾,且 Hermes 完全不用重啟或改設定。
三、nginx 站台設定
檔案:/etc/nginx/sites-available/wiki.nginx.tw-9118
server {
listen 9118 ssl;
listen [::]:9118 ssl;
server_name wiki.nginx.tw;
# 沿用既有 Let's Encrypt 憑證(與 443 同一張)
ssl_certificate /etc/letsencrypt/live/wiki.nginx.tw/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.nginx.tw/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# basic auth 密碼保護
auth_basic "Hermes Web UI — Restricted";
auth_basic_user_file /etc/nginx/hermes.htpasswd;
location / {
proxy_pass http://127.0.0.1:9119;
proxy_http_version 1.1;
# 關鍵:Host 必須設為後端綁定位址(見第四節)
proxy_set_header Host 127.0.0.1:9119;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 支援(UI 可能用到)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
}
啟用並套用:
sudo ln -s /etc/nginx/sites-available/wiki.nginx.tw-9118 \
/etc/nginx/sites-enabled/wiki.nginx.tw-9118
sudo nginx -t && sudo systemctl reload nginx
四、第二個坑:Invalid Host header
設定好後訪問,瀏覽器卻出現:
{"detail":"Invalid Host header. Dashboard requests must use the hostname the server was bound to."}
原因:Hermes dashboard 會檢查請求的 Host header,必須等於它綁定的位址 127.0.0.1:9119。一般反代會寫 proxy_set_header Host $host;(把外部 hostname 帶進去),但這裡反而會被拒。
解法:明確把 Host 設成後端綁定的位址,讓後端以為請求是送給它自己:
proxy_set_header Host 127.0.0.1:9119;
改完 nginx -t && systemctl reload nginx,錯誤消失,UI 正常載入。
五、建立 basic auth 密碼
密碼檔用 htpasswd(來自 apache2-utils)產生,放在 nginx 能讀、但對外不可見的位置:
sudo apt-get install -y apache2-utils
sudo htpasswd -c /etc/nginx/hermes.htpasswd sugarwu
# 互動式輸入密碼
sudo chmod 640 /etc/nginx/hermes.htpasswd
sudo chown root:www-data /etc/nginx/hermes.htpasswd
之後訪問 https://wiki.nginx.tw:9118/ 會先彈出瀏覽器內建密碼框,通過才進 Hermes UI。
六、防火牆
9118 是額外監聽埠,需確認主機防火牆/雲端安全群組已放行 9118/TCP 入站。本機 ufw 若 inactive,仍要檢查 VPS 供應商的安全群組(Linode/阿里/aws 等)。
驗證(未帶密碼應回 401,代表 SSL + auth 已生效):
curl -s -o /dev/null -w "%{http_code}\n" https://wiki.nginx.tw:9118/
# 預期輸出:401
七、讓 Hermes dashboard 開機自啟(選用)
上述 Hermes dashboard 是手動用 hermes dashboard --no-open 啟動的,重開機不會自動跑。若要開機自啟,可寫一支 systemd service(以一般使用者身分):
# ~/.config/systemd/user/hermes-dashboard.service
[Unit]
Description=Hermes Agent Web Dashboard
After=network.target
[Service]
WorkingDirectory=%h/.hermes/hermes-agent
ExecStart=%h/.hermes/hermes-agent/venv/bin/hermes dashboard --no-open
Restart=on-failure
[Install]
WantedBy=default.target
啟用:
systemctl --user enable --now hermes-dashboard.service
小結
三個關鍵點:① 對外埠(9118)與 Hermes 本機埠(9119)要分開,避免綁定衝突;② Host header 要改成後端綁定位址,否則觸發 Invalid Host header;③ 對外控制台務必 HTTPS + 密碼雙重保護。照此流程,約十分鐘就能把本機代理安全地開放到外部網址。