--- title: Docker + nginx 部署 description: 推荐环境部署方式:多阶段构建镜像 + nginx 托管 outline: deep --- # 推荐环境部署:Docker + nginx 适用:生产环境、需要长期稳定运行、机器上不想装 Node。 仓库自带多阶段 `Dockerfile`:Node 阶段执行 `vitepress build`,最终镜像只含 nginx 与静态产物,**不含 Node 和 `node_modules`**。 ## 构建镜像 ```bash SHA=$(git rev-parse --short HEAD) docker build -t iotlcm-docs:$SHA . ``` 用 commit sha 做标签,便于追溯与回滚;不建议只用 `latest`。 ## 启动容器 ```bash docker run -d \ --name iotlcm-docs \ --restart unless-stopped \ -p 8019:80 \ iotlcm-docs:$SHA ``` ## nginx 配置(关键) `docker/nginx.conf` 用 `alias` 把 `/docs/` 前缀剥掉: ```nginx server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # 产物按 base=/docs/ 生成,资源引用形如 /docs/assets/xxx location /docs/ { alias /usr/share/nginx/html/; try_files $uri $uri.html $uri/ $uri/index.html =404; } # 根路径跳到文档入口,避免访问 / 时白屏 location = / { return 302 /docs/; } location / { try_files $uri $uri.html $uri/ =404; } } ``` `try_files` 里的 `$uri.html` 与 `$uri/index.html` 是必需的:配置启用了 `cleanUrls: true`,页面 URL 不带 `.html` 后缀,需要服务器做内部映射。 原理说明见 [路径前缀必读](./path-prefix)。 ## 部署后自检 ```bash # 1. 入口可访问(应返回 200) curl -o /dev/null -s -w '%{http_code}\n' http://127.0.0.1:8019/docs/ # 2. 根路径应 302 到 /docs/ curl -o /dev/null -s -w '%{http_code}\n' http://127.0.0.1:8019/ # 3. 静态资源不能 404(最容易出问题的一步) ASSET=$(curl -s http://127.0.0.1:8019/docs/ | grep -o '/docs/assets/style[^"]*\.css' | head -1) curl -o /dev/null -s -w '%{http_code}\n' "http://127.0.0.1:8019$ASSET" # 4. 抽查正文页面 curl -o /dev/null -s -w '%{http_code}\n' http://127.0.0.1:8019/docs/manual/web/ ``` 四项都返回 `200`(第 2 项返回 `302`)才算部署成功。 ## 通过外层反向代理对外 生产常见做法:容器只监听 `127.0.0.1`,由外层 nginx 转发。 ```nginx upstream iotlcm_docs { server 127.0.0.1:8019; } location = /docs { return 301 /docs/; } location /docs/ { proxy_pass http://iotlcm_docs; # 末尾不要加斜杠 proxy_http_version 1.1; proxy_set_header Host $host; 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; } ``` ::: danger proxy_pass 末尾斜杠 写成 `proxy_pass http://iotlcm_docs/;`(带末尾斜杠)会把 `/docs/` 前缀剥掉,转发到容器变成 `/`,导致资源全部 404 白屏。**必须不带末尾斜杠**。 ::: ## docker compose `docker-compose.yml` 中镜像名是占位值,需替换为自己的仓库地址: ```yaml services: docs: image: your-registry/iotlcm/iotlcm-docs:${TAG:-latest} container_name: iotlcm-docs restart: unless-stopped ports: - "127.0.0.1:8019:80" networks: - iotlcm-network networks: iotlcm-network: external: true name: iotlcm-network ``` compose 文件声明 `iotlcm-network` 为外部网络,若不存在需先创建: ```bash docker network create iotlcm-network ``` 启动: ```bash TAG=$(git rev-parse --short HEAD) docker compose up -d ``` ## 版本固定与升级 开源仓按**固定版本**发布(无 git 历史,单次初始提交)。部署时请记录并锁定 commit: ```bash SHA=$(git rev-parse HEAD) echo "部署基线: $SHA" >> deploy.log docker build -t iotlcm-docs:$SHA . ``` 升级文档时,从上游选定基线重新发布后,按新 sha 重建镜像并滚动替换容器: ```bash docker rm -f iotlcm-docs docker run -d --name iotlcm-docs --restart unless-stopped -p 8019:80 iotlcm-docs:$NEW_SHA ```