---
# System prepended metadata

title: 使用druidfi/stonehenge，實現 https + Domain Name 在Windows本機開發網路應用
tags: [stonehenge, DevOps, Docker Compose, Visual Studio, Docker]

---

---
tags: Docker,Docker Compose,DevOps,Visual Studio,stonehenge
---
# 使用druidfi/stonehenge，實現 https + Domain Name 在Windows本機開發網路應用

撰寫者 ： Cymon Dez
撰寫時間 ： 2025-09-11

## 前言

筆者曾於2020年時撰寫過[使用 SSL 與 Domain Name 在Windows本機開發後端應用](https://hackmd.io/@sf_cGmuJRQS2k1Z3FHd-zA/S1WqDTifP)一文。
隨著時間推移，如今(2025)已經有良好的開源套件[druidfi/stonehenge](https://github.com/druidfi/stonehenge)可以輕鬆搭建此功能的開發環境，故決定寫一篇在Windows10/11 wsl2環境下，使用`stonehenge`搭建能夠使用SSL+Domain的本地開發環境。

## 目標

1. 本機上的專案(前端、後端均可)可以使用`SSL` + `Domain Name`進行測試時
2. 80,443 port 的複用，減少port衝突
3. 減少修改 `hosts`檔案的麻煩
4. 使用 `VS2022`整合`docker-compose` debug環境

### 適用場景

1. 專案容器化開發
2. 產品使用容器部屬

### 建置環境

以下是本篇蚊帳撰寫時，所使用到的系統以及工具版版本

+ `Win10` 22H2
+ `powershell` 7.5.2
+ `wsl2` 2.5.10.0 with `distribution Ubuntu-20.04`
+ `Docker Desktop` 4.45.0
  + `docker` 28.3.3
  + `docker compose` v2.39.2-desktop.1
+ `Visual Studio 2022` 17.14.11
+ `vscode` 1.103.2
+ `druidfi/stonehenge` 5.1.0
  + `traefik` v3.5.0
  + `Mailpit` v1.27.7

## stonehenge

### 簡介

stonehenge是一套藉由traefik + mkcert 實現本地https domain name開發環境的一套開源專案。
套件(5.x)由以下幾項整合

+ traefik：具備服務發現器與自動憑證申請的新一代服務發現器，與docker的相容性良好
+ mkcert：產生本機測試用途之可信任的SSL檔
+ Mailpit：email快取，用於測試專案的郵件發送機制

### 安裝前檢查

1. 請先確認您的Windows10/11環境，已經安裝好`wsl2`與`docker`
2. 確認套件stonehenge預設會使用到的port未被其他服務占用，以下列出所需要的port以及功能：
   1. 80   port: http
   2. 443  port: https
   3. 1025 port: Mailpit

### 詳細安裝 (與快速安裝則一)

1. 開啟`powershell`，在`wsl2`下安裝`build-essential`

   ```ps
   wsl sh -c "sudo apt update && sudo apt upgrade && sudo apt install build-essential"
   ```

2. git clone stonehenge專案

    ```ps
    wsl git clone -b 5.x https://github.com/druidfi/stonehenge.git ~/stonehenge
    ```

3. 如果需要調整安裝參數，請進到stonehenge/.env裡進行設定

    這邊使用vscode修改，您也可以將code改為nano或vim

    ```ps
    wsl code ~/stonehenge/.env
    ```

    可修改的參數如下：
    + `DOCKER_DOMAIN`：反向代理的root domain，預設值是`docker.so`，其原理是將`*.docker.so`指向`127.0.0.1`；如果想修改成自己單位使用的domain，請記得將設定的domain指向`127.0.0.1`

    | type |            domain            | ip address |
    | :--: | :--------------------------: | :--------: |
    |  A   |  <your_organization_domain>  | 127.0.0.1  |
    |  A   | *.<your_organization_domain> | 127.0.0.1  |

    + `HTTP_PORT`：http使用的port，預設值是80
    + `HTTPS_PORT`：https使用的prot，預設值是443
    + `SMTP_PORT`：smtp(email)使用的prot，預設值是1025

    ```sh
    # Root domain for all local services
    DOCKER_DOMAIN=docker.so

    # Prefix for containers
    PREFIX=stonehenge

    # Stonehenge major version
    STONEHENGE_VERSION=5

    # Image versions
    STONEHENGE_TAG=5.1

    # http port ，預設是 80，原始檔案沒有，須自己加上
    # HTTP_PORT=80

    # https port ，預設是 443，原始檔案沒有，須自己加上
    # HTTPS_PORT=443
    
    # smtp port ，預設是 1025，原始檔案沒有，須自己加上
    # HTTP_PORT=1025
    ```

4. 安裝

   ```ps
   wsl make -s -C ~/stonehenge up
   ```

5. 設定開發用憑證

   ```ps
    $WSL_NAME = $(wsl sh -c 'echo $WSL_DISTRO_NAME')
    $WSL_USER = $(wsl whoami)
    Import-Certificate -Filepath \\wsl$\$WSL_NAME\home\$WSL_USER\stonehenge\certs\rootCA.pem -CertStoreLocation cert:\CurrentUser\Root
   ```

### 快速安裝 (與詳細安裝則一)

如果打算都使用預設值，可以考慮使用作者撰寫的ps1直接安裝

   ```ps
   iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/druidfi/stonehenge/5.x/install.ps1'))
   ```

### 檢測

在瀏覽器上，輸入下列網址，如果能順裡開起，代表安裝與設定皆正常：

+ traefik 管理頁面 [traefik.docker.so](https://traefik.docker.so)

+ mailpit 管理頁面 [mailpit.docker.so](https://mailpit.docker.so)

!!!
    提示：如果安裝時有修改`DOCKER_DOMAIN`，請使用您定的domain加上服務前綴測試
    如:
    traefik.<your_organization_domain>
    mailpit.<your_organization_domain>

### 試著佈署一個服務 - 使用 traefik/whoami

traefik/whoami是一個輕量容器的Echo服務，功能如下：

+ 請求方法（GET、POST 等）
+ 請求的 Host 與 URL
+ HTTP Header
+ 來源 IP
+ TLS/HTTPS 相關資訊（如果有）

很適合用來測試traefik網路環境

1. 在你的專案資料夾下，建一個新資料夾`whoami`
2. 在`whoami`資料夾下，產生`compose.yml`檔並加入以下內容

   ```yaml
   networks:
     # stonehenge 的traefik 所使用的docker network，於安裝時建立
     stonehenge-network:
       external: true
   services:
     app:
       image: traefik/whoami:latest
       labels:
         # 要使用字串的方式才能套用到環境變數
         # container啟用traefik反向代理功能
         - "traefik.enable=true"
         
         # stonehenge 的traefik 所使用的docker network，於安裝時建立
         - "traefik.docker.network=stonehenge-network"
   
         # ${COMPOSE_PROJECT_NAME} 會預設套用compose.yml所在的資料夾名稱，這樣可以盡量避免traefik route 名稱重複造成的衝突問題
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.entrypoints=https"
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`whoami.docker.so`)"
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls=true"
         - "traefik.http.services.${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=80"
       networks:
         - default
         # 需要反向代理的服務才加入 stonehenge-network
         - stonehenge-network
   ```

3. 啟動docker compose

   ```sh
   docker compose up -d
   ```

4. 測試
   使用wsl的curl，輸入`whoami.docker.so`，檢測是否能連線並自動重新導向到https

   ```sh
   wsl curl -vL --ssl-revoke-best-effort whoami.docker.so
   # -v: 顯示詳細訊息
   # -L: 代表 follow redirect
   ```

   如果成功會看到以下訊息：

   ```sh
   * Host whoami.docker.so:80 was resolved.
   * IPv6: (none)
   * IPv4: 127.0.0.1
   *   Trying 127.0.0.1:80...
   * Connected to whoami.docker.so (127.0.0.1) port 80
   > GET / HTTP/1.1
   > Host: whoami.docker.so
   > User-Agent: curl/8.9.1
   > Accept: */*
   >
   < HTTP/1.1 301 Moved Permanently
   < Location: https://whoami.docker.so/
   < Date: Thu, 11 Sep 2025 16:35:00 GMT
   < Content-Length: 17
   * Ignoring the response-body
   <
   * Connection #0 to host whoami.docker.so left intact
   * Clear auth, redirects to port from 80 to 443
   * Issue another request to this URL: 'https://whoami.docker.so/'
   * Host whoami.docker.so:443 was resolved.
   * IPv6: (none)
   * IPv4: 127.0.0.1
   *   Trying 127.0.0.1:443...
   * Connected to whoami.docker.so (127.0.0.1) port 443
   * schannel: disabled automatic use of client certificate
   * ALPN: curl offers http/1.1
   * ALPN: server accepted http/1.1
   * using HTTP/1.x
   > GET / HTTP/1.1
   > Host: whoami.docker.so
   > User-Agent: curl/8.9.1
   > Accept: */*
   >
   < HTTP/1.1 200 OK
   < Content-Length: 377
   < Content-Type: text/plain; charset=utf-8
   < Date: Thu, 11 Sep 2025 16:35:00 GMT
   <
   Hostname: 36529239ef8f
   IP: 127.0.0.1
   IP: ::1
   IP: 172.19.0.3
   IP: 172.21.0.2
   RemoteAddr: 172.19.0.2:59848
   GET / HTTP/1.1
   Host: whoami.docker.so
   User-Agent: curl/8.9.1
   Accept: */*
   Accept-Encoding: gzip
   X-Forwarded-For: 172.19.0.1
   X-Forwarded-Host: whoami.docker.so
   X-Forwarded-Port: 443
   X-Forwarded-Proto: https
   X-Forwarded-Server: 68578e0bf36c
   X-Real-Ip: 172.19.0.1

   * Connection #1 to host whoami.docker.so left intact
   ```

   在traefik dashboard中，應該能看見http route有新增了 whoami.docker.so這項
   ![traefik-whoami](https://hackmd.io/_uploads/H1m2QFZogl.png)


### 範例參考

stonehenge專案有提供很多佈署相關的範例，可以到stonehenge專案的[examples](https://github.com/druidfi/stonehenge/tree/5.x/examples)查詢

## 如何用於開發專案

### `VS2022` 使用 `docker compose 支援`

詳細內容請參考[微軟官方教學](https://docs.microsoft.com/zh-tw/visualstudio/containers/tutorial-multicontainer?view=vs-2022)

1. 建立一個`asp.net core 8 MVC`專案
   ![create-aspnetcore-mvc-porj](https://hackmd.io/_uploads/BJk57YWoll.png)
   
   ![create-aspnetcore-mvc-porj-settings](https://hackmd.io/_uploads/ByO5mFZigg.png)

2. 加入`docker compose 支援`
   專案上按右鍵，選擇 [ 加入 > 容器協調器支援]。 [ Docker 支援選項 ]
   ![container-supports](https://hackmd.io/_uploads/SJMeEFZixl.png)

   
   對話框出現後，選擇 [ Docker Compose]。
   ![docker-compose-supports](https://hackmd.io/_uploads/HJiVXt-sle.png)

3. 設定`docker-compose.override.yml`，加入`stonehenge`的網路設定
   docker-compose.override.yaml

   ```yaml
   services:
     webapplication_stonehege_demo:
       environment:
         - ASPNETCORE_ENVIRONMENT=Development
         - ASPNETCORE_HTTP_PORTS=8080
       ports:
         - "8080"
       networks:
         - default
         - traefik-proxy
       labels:
         # 要使用字串的方式才能套用到環境變數
         # container啟用traefik反向代理功能
         - "traefik.enable=true"
         
         # stonehenge 的traefik 所使用的docker network，於安裝時建立
         - "traefik.docker.network=stonehenge-network"
   
         # ${COMPOSE_PROJECT_NAME} 會預設套用compose.yml所在的資料夾名稱，這樣可以盡量避免traefik route 名稱重複造成的衝突問題
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.entrypoints=https"
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`webapp.docker.so`)"
         - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls=true"
         - "traefik.http.services.${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=8080"
   
   networks:
     traefik-proxy:
         name: stonehenge-network
         external: true
   ```

   請確認檔案是以UTF-8編碼儲存，不然啟動時會遇到 `yaml: invalid leading UTF-8 octet`這個錯誤
   ![yaml_invalid_leading_UTF-8_octet](https://hackmd.io/_uploads/rk3-7tZsxg.png)

4. 修改`docker-compose.dcproj`

   ```xml
   <?xml version="1.0" encoding="utf-8"?>
   <Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
     <PropertyGroup Label="Globals">
       <ProjectVersion>2.1</ProjectVersion>
       <DockerTargetOS>Linux</DockerTargetOS>
       <DockerPublishLocally>False</DockerPublishLocally>
       <ProjectGuid>81dded9d-158b-e303-5f62-77a2896d2a5a</ProjectGuid>
       <DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
       <!--將DockerServiceUrl修改改成 與override中相同的網址-->
       <DockerServiceUrl>https://webapp.docker.so</DockerServiceUrl>
       <DockerServiceName>webapplication_stonehege_demo</DockerServiceName>
     </PropertyGroup>
     <ItemGroup>
       <None Include="docker-compose.override.yml">
         <DependentUpon>docker-compose.yml</DependentUpon>
       </None>
       <None Include="docker-compose.yml" />
       <None Include=".dockerignore" />
     </ItemGroup>
   </Project>
   ```

5. `F5`啟動專案測試
   如果設定正確 `vs2022`會啟動瀏覽器
   ![vs2022-debug-browser](https://hackmd.io/_uploads/Byck7KZsll.png)

   `traefik dashboard` 上 `http` `route`會看到此專案的路由
   ![vs2022-debug-traefik](https://hackmd.io/_uploads/S1i9MFZoxg.png)


## 結語

透過 `stonehenge`，Windows 本機開發環境能夠輕鬆實現 SSL + Domain Name 的需求，並且大幅簡化設定流程。無論是前端或後端專案，都能享受一致且安全的本地測試體驗。`stonehenge` 讓容器化開發更貼近正式環境，減少 port 衝突與 hosts 檔案修改的困擾，也方便團隊協作與 CI/CD 部署。
