Docker 静态站点部署指南
目录
1. 本地构建与推送
1.1 构建项目
# 在项目根目录执行
npm install
npm run docs:build
构建产物输出到 docs/.vuepress/dist/(即 docker-compose.yml 挂载进容器的目录)。 该目录会一并提交到 Git,服务器只需拉取即可直接使用,无需在服务器上安装 Node 重新构建。
1.2 提交并推送到 Git
git add -A
git commit -m "docs: rebuild for deployment"
git push
项目根目录的
.gitattributes已统一换行符为 LF,避免在 Windows 编辑后带到 Linux 上出错。 确保远程仓库已配置好,且 Ubuntu 服务器有访问该仓库的权限。
1.3 项目docker相关文件
① docker-compose.yml
services:
# ========================================
# Nginx (Web 服务器)
# ========================================
nginx:
image: nginx:1.25-alpine
container_name: doc-nginx
restart: unless-stopped
ports:
# 只绑定本地回环地址,由宿主机 Nginx 反代接入,统一处理 SSL
- "127.0.0.1:8002:80"
volumes:
# 静态站点:本地 npm run docs:build 生成 docs/.vuepress/dist 并提交到 Git
- ./docs/.vuepress/dist:/var/www/html:ro
- ./docker/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf:ro
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
② docker/nginx/example.com.conf(宿主机反代模板,占位符
__DOMAIN__)
# 宿主机 Nginx 反向代理配置模板(占位符 __DOMAIN__ 由 run.bash 自动替换)
#
# 推荐用法(在项目根目录执行,脚本会自动替换占位符、安装配置并重载 Nginx):
# ./run.bash <你的域名>
#
# 手工用法:
# sed 's/__DOMAIN__/你的域名/g' docker/nginx/example.com.conf \
# | sudo tee /etc/nginx/sites-available/你的域名
# sudo ln -sfn /etc/nginx/sites-available/你的域名 /etc/nginx/sites-enabled/你的域名
# sudo nginx -t && sudo systemctl reload nginx
#
# 前置条件:证书 /etc/nginx/ssl/fullchain.pem 与 /etc/nginx/ssl/privkey.key 已存在
# 强制 HTTP → HTTPS 跳转
server {
listen 80;
server_name __DOMAIN__;
return 301 https://$host$request_uri;
}
# HTTPS 服务
server {
# 注意:Ubuntu 24.04 自带 Nginx 1.24,须保留 "ssl http2" 写法;
# Nginx >= 1.25.1 建议改为 "listen 443 ssl;" + "http2 on;"
listen 443 ssl http2;
server_name __DOMAIN__;
# SSL 证书(使用 acme.sh 申请泛域名证书后,所有站点共用)
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.key;
# SSL 安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 日志
access_log /var/log/nginx/doc-access.log;
error_log /var/log/nginx/doc-error.log;
# 客户端上传大小限制
client_max_body_size 64M;
# 反代到本项目的 Docker Nginx
location / {
proxy_pass http://127.0.0.1:8002;
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;
}
}
③ docker/nginx/conf.d/default.conf
# 使用 realip 模块从上游(宿主机 Nginx)获取真实客户端 IP
# 注意:容器经过端口映射后,请求来源是 Docker 网桥网关(172.16.0.0/12),
# 而不是 127.0.0.1,所以只写 127.0.0.1 会导致真实 IP 不被信任。
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 127.0.0.1;
real_ip_header X-Real-IP;
real_ip_recursive on;
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.html index.htm;
# 不对外暴露 nginx 版本号
server_tokens off;
# gzip 压缩
gzip on;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml image/svg+xml;
gzip_min_length 1k;
gzip_vary on;
# 静态资源缓存
location ~* \.(gif|jpe?g|png|bmp|swf|ico|svg|webp|woff2?|ttf|eot)$ {
expires 30d;
access_log off;
}
# JS/CSS(VuePress 产物文件名带 hash,可放心缓存)
location ~* \.(js|css)$ {
expires 7d;
access_log off;
}
# 未命中的路径返回 VuePress 生成的 404 页面,并保留 404 状态码
error_page 404 /404.html;
location = /404.html {
internal;
}
location / {
# 依次尝试:真实文件 -> 目录 -> 同名 .html(VuePress 产物形态),
# 都未命中则 404,避免把不存在的地址伪装成首页 200
try_files $uri $uri/ $uri.html =404;
}
}
2. Ubuntu 服务器拉取与部署
2.1 首次部署
# 进入用户 projects 目录
cd ~/projects
# 克隆项目(docs/.vuepress/dist 已包含在仓库中,无需再构建)
git clone <仓库地址> mydoc
# 进入项目目录
cd mydoc
2.2 启动 Docker 容器
项目已提供 docker-compose.yml,直接启动即可:
# 启动容器(后台运行)
docker compose up -d
启动后验证容器状态:
docker compose ps
应能看到 doc-nginx 容器正常运行,监听 127.0.0.1:8002。
2.3 更新部署
当有代码更新时:
cd ~/projects/mydoc
# 拉取最新代码(docs/.vuepress/dist 已包含在提交中)
git pull
# 目录是 bind mount,静态文件立即生效,无需重启容器。
# 仅在改动 docker-compose.yml 或 Nginx 配置后需要重建容器:
docker compose up -d
3. 宿主机 Nginx 配置
请先把你的域名解析到服务器 IP(仓库里不写死域名,由部署脚本传入)。 项目 Docker Nginx 运行在
127.0.0.1:8002,由宿主机 Nginx 反代并统一处理 SSL。
3.1 一键安装(推荐)
项目根目录的 run.bash 会读取模板 docker/nginx/example.com.conf,把域名占位符 __DOMAIN__ 替换为真实域名,安装到 /etc/nginx/sites-available/ 并重载 Nginx:
cd ~/projects/mydoc
chmod +x run.bash
./run.bash doc.example.com # 换成你的真实域名;不要用 sudo 执行
脚本可重复执行(幂等),并在域名未传、模板缺失、证书不存在时提前报错退出。
3.2 手工安装(不使用脚本时)
cd ~/projects/mydoc
DOMAIN=doc.example.com
sed "s/__DOMAIN__/$DOMAIN/g" docker/nginx/example.com.conf | sudo tee /etc/nginx/sites-available/$DOMAIN
sudo ln -sfn /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/$DOMAIN
sudo nginx -t && sudo systemctl reload nginx
前置条件:证书
/etc/nginx/ssl/fullchain.pem与/etc/nginx/ssl/privkey.key已存在 (用 acme.sh 申请泛域名证书后所有站点共用)。
4. 日常维护命令
| 操作 | 命令 |
|---|---|
| 查看容器状态 | docker compose ps |
| 查看容器日志 | docker compose logs -f |
| 重启容器 | docker compose restart |
| 停止容器 | docker compose down |
| 重新构建并启动 | docker compose up -d --build |
| 宿主机 Nginx 重载 | sudo systemctl reload nginx |
| 宿主机 Nginx 状态 | sudo systemctl status nginx |
5. 常见问题
Q: 为什么 Docker Nginx 绑定在 127.0.0.1:8002 而不是 0.0.0.0:8002?
为了安全。Docker Nginx 只监听本地回环地址,不直接暴露给外网。所有外部请求必须经过宿主机 Nginx(已配置 SSL),再由宿主机转发到 Docker 内部。
Q: 容器启动后访问出现 502 Bad Gateway?
- 检查
docker compose ps确认容器是否正常运行 - 检查宿主机 Nginx 配置中的
proxy_pass地址是否正确 - 检查 Docker 容器端口映射:
docker port doc-nginx
Q: 更新代码后页面没变化?
cd ~/projects/mydoc
git pull
容器以 bind mount 方式挂载 ./docs/.vuepress/dist,git pull 后新文件立即生效,不需要重启容器。 若页面仍是旧内容,先确认本地是否已重新执行 npm run docs:build 并提交,再用 Ctrl+F5 强制刷新浏览器缓存。
Q: 如何查看构建后的文件是否正确?
ls -la ~/projects/mydoc/docs/.vuepress/dist/