前言
對于一個喜歡折騰的人來說,NAS 上總會有各種各樣的服務,有用 docker 跑的服務,有用系統(tǒng)服務運行的服務,他們大都掛在一個端口上,例如 http://192.168.133.5:8190
?,時間久了自己都不記哪個端口對應哪個服務,所以一般還會做一個導航頁作為統(tǒng)一入口,維護所有服務。
image
但要能用項目名稱 + 域名的方式訪問網(wǎng)站,那看起來就優(yōu)雅的多了(比如 https://open-webui.internal.wj2015.com
?),以及有些服務需要用到瀏覽器的最新能力,比如錄音、視頻等,而這些能力需要在安全的 HTTPS 下才可以被正常使用(MDN-getUserMedia()),所以本文會介紹博主的諸多本地服務如何批量且自動的加上 HTTPS 和子域名。
image
?
順口吐槽一句,現(xiàn)在云廠商可以申請的免費證書都不超過3個月,單獨購買證書又貴的一匹,同樣可以用下面提到的證書申請方案解決。
準備工作
需要的資源如下:
- 首先需要有一個域名,域名可以在騰訊云、阿里云、百度云等有域名購買入口的云服務提供商那邊買,域名會解析到內(nèi)網(wǎng)服務,所以 域名無需備案。
- 需要一臺 NAS 或 Linux 服務器,arm 或 x86 架構(gòu)都可以,重點是需要支持 docker,博主的 NAS 是撿垃圾拼出來的組裝機,裝了 ubuntu 22.04 系統(tǒng)配合 docker 提供服務,從原理上看群輝、飛牛這些支持運行 docker 容器的 NAS 專用系統(tǒng)也可以。
注意:做 HTTPS 這里域名一定要購買,不能只在內(nèi)網(wǎng) DNS 服務器做域名解析,因為申請證書時需要做 DNS 驗證
整體思路
大概分為如下幾個步驟:
- 將內(nèi)網(wǎng) IP 固定下來,可通過路由器自帶的 MAC 綁定功能實現(xiàn),比如固定為 192.168.133.5
- 把域名的一個子域使用 DNS 泛解析的方式解析到內(nèi)網(wǎng) IP 上,比如把
*.internal.wj2015.com
? 解析到 192.168.133.5 - 運行 certd 服務和 traefik 服務并做配置
- 給需要的服務動態(tài)添加 traefik 代理配置
具體操作
固定內(nèi)網(wǎng) IP
博主家的路由器是小米 AX3000T,而博主的 NAS 機器是掛在小米路由器下的,所以家里網(wǎng)絡的 DHCP 在小米路由器中配置。
如果你的 DHCP 服務跑在做軟路由上,需要在軟路由的 DHCP 中找到 DHCP 靜態(tài) IP 分配的配置。
image
?
添加一個這樣的綁定即可。
?
image
?
注:如果綁定的 IP 和 NAS 現(xiàn)有 IP 不一樣,可以重啟 NAS 或重新獲取 IP。
配置完能 ping 通即可?
image
添加泛解析
博主域名是在騰訊云買的,所以進入 域名注冊-控制臺,添加一條這樣的泛解析
image
本地可用 nslookup
? 或者 ping
? 命令確保解析正確,一般配完就生效,不會超過配置的 600s TTL。?
image
運行容器
這里用 docker-compose 進行部署(linux 環(huán)境下可參考 docs.docker.com/compose/install/linux/ 進行 docker-compose 的安裝),docker-compose 配置中的所有屬性都可以對應到群輝或飛牛系統(tǒng)的 docker 控制臺。
注:這個 docker-compose 包含三個應用
- 一個是 alist,一個網(wǎng)盤掛載服務,這里用來測試,隨后可以通過 alist.internal.wj2015.com
- 一個是 traefik,反向代理服務,后續(xù)會細講
- 一個是 certd,HTTPS 證書申請服務,后續(xù)會細講
version: "3.8" services: alist: image: xhofe/alist-aria2:v3.39.1 container_name: alist volumes: - './alist:/opt/alist/data' - '/mnt/data/:/mnt/data/' ports: - '5244:5244' - '6800:6800' environment: - PUID=0 - PGID=0 - UMASK=022 restart: unless-stopped traefik: image: traefik:v3.2 restart: always command: - "--configFile=/etc/traefik/config.yml" ports: # The HTTP port - "80:80" - "443:443" # The Web UI (enabled by --api.insecure=true) #- "8081:8080" volumes: - ./traefik/:/etc/traefik/ - ./share/:/etc/share/ - ./traefik-logs/:/var/logs/traefik/ - /var/run/docker.sock:/var/run/docker.sock certd: image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:1.21.2 container_name: certd # 容器名 restart: unless-stopped # 自動重啟 ports: # 端口映射 # ↓↓↓↓ ---------------------------------------------------------- 如果端口有沖突,可以修改第一個7001為其他不沖突的端口號 - "7001:7001" volumes: # ↓↓↓↓↓ ------------------------------------------------------- 2、 數(shù)據(jù)庫以及證書存儲路徑,默認存在宿主機的/data/certd/目錄下【可選】 - ./certd:/app/data - ./share/certs:/var/certs # 本地證書存放位置 environment: # 環(huán)境變量 - TZ=Asia/Shanghai - certd_system_resetAdminPassword=false # ↑↑↑↑↑---------------------------4、如果忘記管理員密碼,可以設(shè)置為true,重啟之后,管理員密碼將改成123456,然后請及時修改回false【可選】 - certd_cron_immediateTriggerOnce=false # ↑↑↑↑↑---------------------------5、如果設(shè)置為true,啟動后所有配置了cron的流水線任務都將被立即觸發(fā)一次【可選】 - certd_koa_port=80 - VITE_APP_ICP_NO= # ↑↑↑↑↑ -----------------------------------------6、這里可以設(shè)置備案號【可選】 # 設(shè)置環(huán)境變量即可自定義certd配置 # 服務端配置項見: packages/ui/certd-server/src/config/config.default.ts # 服務端配置規(guī)則: certd_ + 配置項, 點號用_代替 # 客戶端配置項見: packages/ui/certd-client/.env # 按實際名稱配置環(huán)境變量即可,如: VITE_APP_API=http://localhost:7001
?docker-compose up -d
? 運行服務。
配置 CERTD 服務
github.com/certd/certd 是一個全自動證書申請、更新、續(xù)期的開源服務,
注:默認賬號密碼:admin/123456,請及時更改密碼保證安全,更多安裝細節(jié)可參考官方文檔,私有化部署
訪問 http://192.168.133.5:7001
? 輸入賬號密碼就可以看到如下頁面。
?
接下來做證書申請相關(guān)的配置,請根據(jù) certd 的操作文檔一步步進行,博主這里是騰訊云,所以最終會拿到一個 secretId 和 secretKey 。
image
?
然后回到 certd 服務,點擊左側(cè)邊欄『授權(quán)管理』按鈕,進入授權(quán)管理頁面,點擊『添加』按鈕,填寫表單,我這里選擇騰訊云并填寫 secretId 和 secretKey,然后點擊保存。?
然后點擊左側(cè)『證書自動化流水線』,創(chuàng)建一個新流水線,完整形態(tài)如下,接下來一步步的看每一個節(jié)點。
image
第一個節(jié)點在『觸發(fā)源』,這里默認會有一個手動觸發(fā),可以用來調(diào)試,但我們希望證書可以自動更新,所以點擊加號添加一個定時觸發(fā),定時規(guī)則可以寫 0 0 2 * * *
?,表示每天凌晨兩點自動觸發(fā)證書更新。
image
第二個節(jié)點是『證書申請階段』,點添加步驟
image
重點配置如下圖所示,請?zhí)顚懽约旱挠蛎?DNS 提供商、授權(quán)配置等。?
image
然后下一個關(guān)鍵點『更新證書』,注意這里的路徑跟 docker-compose 中配置的 volumns 映射的右側(cè)路徑保持一致(這里是 /var/certs/)。?
image
image
?
【可選步驟】為及時的知道證書更新情況,可以在更新失敗時通知到收件郵箱,參考這篇文檔
?
image
都配置完成后,點擊右上角的『保存』按鈕,并點擊『手動運行』看整個流程是否報異常。
image
?
運行完成后,查看 docker-compose 配置目錄下的 share/certs
? 目錄,如果可以找到這兩個文件,說明證書已經(jīng)申請好了。
$ ls share/certs/ cert.key cert.pem
配置 TRAEFIK 服務
traefik 是一個開源的反向代理、負載均衡軟件,除了 traefik 外 nginx 等支持反向代理的軟件也可以承擔同樣的任務,不過 traefik 本身對容器化服務兼容性和可配置性更好 ,所以在這個場景中更為推薦。
在 docker-compose 配置文件目錄下,編寫./traefik/config.yaml
? 內(nèi)容如下,配置的具體含義可以參考官方文檔:doc.traefik.io/traefik
注意:
- traefik HTTPS 配置文檔請訪問:doc.traefik.io/traefik/https/tls/
- 通過中間件 middleware 的配置,實現(xiàn)了默認路由 http -> https 的跳轉(zhuǎn),可按需使用
- 宿主機的 ./share/certs 對應 certd 服務的 /var/certs,證書申請好之后會在 ./share/certs 下生成證書文件,./share 對應 traefik 的 /etc/share,所以 traefik 需要配置的是 /etc/share/certs/cert{.key|.pem}
- http.routers.ip 可以配置由 IP 直接訪問時候的路由,注意這個配置不要填 tls:{},這樣就可以支持通過 http 訪問而不會被自動跳轉(zhuǎn)到 https
api: insecure: true dashboard: true entryPoints: web: address: ":80" # http: # redirections: # entryPoint: # to: websecure websecure: address: ":443" log: filePath: "/var/logs/traefik/traefik.log" accessLog: filePath: "/var/logs/traefik/access.log" filters: statusCodes: - "300-302" - "400-404" - "500-502" retryAttempts: true minDuration: "1000ms" providers: docker: true file: directory: "/etc/traefik" watch: true tls: options: default: minVersion: VersionTLS12 stores: default: defaultCertificate: certFile: "/etc/share/certs/cert.pem" keyFile: "/etc/share/certs/cert.key" http: middlewares: https-redirect: redirectScheme: scheme: https permanent: false routers: ip: rule: "Host(`192.168.133.5`)" service: traefik default: #rule: "HostRegexp(`^.+.internal.wj2015.com$`)" rule: "HostRegexp(`^.*.internal.wj2015.com$`)" middlewares: - https-redirect service: flare
如果上面的步驟都沒有問題,執(zhí)行 docker-compose restart traefik
? 后,訪問 http://你的ip
? 應該可以看到如下頁面
image
動態(tài)配置 HTTPS 和子域名
下一步就是動態(tài)的給所有的服務加上 HTTPS 和子域名了,這里有多種解決方案,比較推薦的方案是 docker labels 聲明 + 腳本生成動態(tài)配置 。
labels 動態(tài)聲明
docker label 配置是 traefik 支持的一項功能,可以在容器的 labels 中申明路由、負載均衡器等 traefik,進而實現(xiàn)動態(tài)的添加 traefik 代理配置的目的。
舉個例子,這是原始的 alist 配置
version: "3.8" services: alist: image: xhofe/alist-aria2:v3.39.1 container_name: alist volumes: - './alist:/opt/alist/data' - '/mnt/data/:/mnt/data/' ports: - '5244:5244' - '6800:6800' environment: - PUID=0 - PGID=0 - UMASK=022 restart: unless-stopped
增加 labels 聲明后,就可以把 ports 映射移除掉了,因為 traefik 和 alist 容器在同一個網(wǎng)絡,可以通過容器名稱訪問無需暴露端口 。
然后在 labels 中申明 tls = true,訪問 alist.internal.wj2015.com 時路由到 alist:5244
version: "3.8" services: alist: image: xhofe/alist-aria2:v3.39.1 container_name: alist volumes: - './alist:/opt/alist/data' - '/mnt/data/:/mnt/data/' environment: - PUID=0 - PGID=0 - UMASK=022 restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.alist.rule=Host(`alist.internal.wj2015.com`)" - "traefik.http.routers.alist.tls=true" - "traefik.http.services.alist.loadbalancer.server.port=5244" # Alist在5244端口提供服務
修改完畢后,訪問 https://alist.{域名}
?就能看到這個頁面
image
腳本動態(tài)生成
腳本動態(tài)生成的目的是將“非容器運行的服務”統(tǒng)一管理起來,比如我通過手動部署的方式部署了 comfyui,這個服務運行在 8088 端口,那么就可以通過腳本自動生成 traefik 配置文件的方式實現(xiàn)網(wǎng)站的管理。
在 docker-compose 配置文件所在目錄新建腳本 traefik-dynamic.sh
?,公共子域名和服務列表請根據(jù)實際情況自行配置
#!/bin/bash # 配置公共子域名 public_subdomain="internal.wj2015.com" # 可配置的服務列表 declare -A services_list=( ["traefik"]="http://traefik:8080" ["comfyui"]="http://172.17.0.1:8188" ) # 生成結(jié)果放到 traefik/route.yml output_file="traefik/route.yml" # 初始化路由器和服務配置 router_configs=() service_configs=() # 遍歷服務列表,并生成配置 for service in "${!services_list[@]}"; do server=${services_list[$service]} # 構(gòu)造路由器配置 router_config=" $service:n rule: "Host(`${service}.${public_subdomain}`)"n tls: {}n service: $service" router_configs+=("$router_config") # 構(gòu)造服務配置 service_config=" $service:n loadBalancer:n servers:n - url: $server/" service_configs+=("$service_config") done # 寫入配置到輸出文件 { echo "http:" echo " routers:" for rc in "${router_configs[@]}"; do echo -e "$rc" done echo " services:" for sc in "${service_configs[@]}"; do echo -e "$sc" done } > "$output_file" echo "Traefik configuration has been generated in $output_file."
執(zhí)行 bash traefik-dynamic.sh
? 后,可以看到如下提示表示生成成功
$ bash traefik-dynamic.sh Traefik configuration has been generated in traefik/route.yml.
生成的 traefik/route.yml
? 預期如下:
http: routers: traefik: rule: "Host(`traefik.internal.wj2015.com`)" tls: {} service: traefik comfyui: rule: "Host(`comfyui.internal.wj2015.com`)" tls: {} service: comfyui services: traefik: loadBalancer: servers: - url: http://traefik:8080/ comfyui: loadBalancer: servers: - url: http://172.17.0.1:8188/
訪問 https://traefik.{域名}
?,預期如下
image
總結(jié)
至此,這臺 NAS 服務器的所有服務都可以通過上述機制來自動生成 HTTPS 配置。
整個思路的關(guān)鍵點如下:
- 想辦法自動的獲取免費證書
- 想辦法動態(tài)的給容器和內(nèi)網(wǎng)服務生成 https 配置
作者聲明本文無利益相關(guān),歡迎值友理性交流,和諧討論~
,