Docker 部署 VitePress 博客教程
使用 Docker Compose 在云服务器上部署 VitePress 博客,包含完整的原理讲解和详细步骤
一、方案架构
1.1 为什么这么部署?
┌─────────────────────────────────────────────────────────────────────┐
│ 完整访问流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 用户浏览器 │
│ │ │
│ ▼ │
│ https://blog.example.com ──→ 云服务器 Nginx (443端口) │
│ │ │ │
│ │ ┌──────┴──────┐ │
│ │ │ Docker 容器 │ │
│ │ └──────┬──────┘ │
│ │ │ │
│ ▼ ┌──────▼──────┐ │
│ 返回博客页面 ┌────│ 静态文件目录 │ │
│ ┌───┴────└─────────────┴────────┐ │
│ │ /data/html │ │
│ │ ├── index.html │ │
│ │ ├── assets/ │ │
│ │ └── ... │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘1.2 组件说明
| 组件 | 作用 | 为什么用 |
|---|---|---|
| Nginx | Web 服务器,托管静态文件 | 高性能,配置简单 |
| Docker | 容器化部署 | 隔离环境,一键部署 |
| Let's Encrypt | 免费 HTTPS 证书 | 安全,自动化 |
| Certbot | 申请/续期证书 | 官方推荐 |
1.3 流量走向
二、准备工作
2.1 服务器要求
| 项目 | 要求 | 说明 |
|---|---|---|
| 系统 | Ubuntu 24.04 | 常用 Linux 发行版 |
| Docker | 已安装 | 容器运行时 |
| Docker Compose | 已安装 | 编排 Docker 容器 |
| 域名 | 已解析 | 指向服务器 IP |
2.2 检查 Docker 是否已安装
bash
# 检查 Docker 版本
docker --version
# 输出类似:Docker version 26.0.0, build 8a7b3c2
# 检查 Docker Compose 版本
docker compose version
# 输出类似:Docker Compose version v2.24.0如果未安装,看 5.1 节。
2.3 域名解析
在域名服务商(腾讯云/阿里云)添加解析:
| 记录类型 | 主机记录 | 记录值 |
|---|---|---|
| A | blog | 你的服务器IP |
验证解析生效:
bash
nslookup blog.example.com
# 应该返回服务器 IP2.4 开放端口
bash
# 防火墙开放端口
sudo ufw allow 22/tcp # SSH(必须)
sudo ufw allow 80/tcp # HTTP(证书申请需要)
sudo ufw allow 443/tcp # HTTPS(博客访问)
# 云服务器安全组也要开放这些端口!三、原理讲解
3.1 为什么需要 Nginx?
直接用 Docker 跑 VitePress 可以吗?
┌────────────────────────────────────────────────────────────┐
│ 直接跑 VitePress │
│ docker run -p 3000:3000 viki/vitepress │
│ │
│ 用户访问:http://IP:3000 ❌ 端口丑,不安全 │
│ │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Nginx 反向代理 │
│ │
│ 用户访问:https://blog.example.com ✅ 域名+HTTPS │
│ │
│ 优势: │
│ - 隐藏端口 3000 │
│ - HTTPS 加密 │
│ - 负载均衡 │
│ - 静态文件缓存 │
│ - 安全头 │
└────────────────────────────────────────────────────────────┘3.2 为什么需要 SSL 证书?
┌─────────────────────────────────────────┐
│ HTTP vs HTTPS │
├─────────────────────────────────────────┤
│ HTTP(明文) │
│ 用户 → 服务器 │
│ 密码/内容被中间人可见 ❌ │
│ │
│ HTTPS(加密) │
│ 用户 ═══════════════════ 服务器 ✅ │
│ (TLS 加密,无法窃听) │
└─────────────────────────────────────────┘3.3 为什么需要 Certbot?
手动申请证书 → 90天后过期 → 手动续期 → 麻烦!
Certbot 自动申请 + 自动续期 → 一劳永逸!
Let's Encrypt 证书:
- 免费
- 90天有效期
- Certbot 自动续期四、目录结构
4.1 最终目录结构
~/blog/
├── docker-compose.yml # Docker 容器编排配置
├── nginx/
│ └── nginx.conf # Nginx 配置文件
└── data/
├── html/ # 博客静态文件(构建产物)
│ ├── index.html
│ ├── assets/
│ └── ...
└── certs/ # SSL 证书(自动生成)
├── fullchain.pem
├── key.pem
└── ...4.2 每个文件的作用
| 文件 | 作用 |
|---|---|
docker-compose.yml | 定义 Nginx 容器配置 |
nginx/nginx.conf | Nginx 服务器配置(HTTPS、反向代理) |
data/html/ | 存放博客静态文件,Nginx 读取这里 |
data/certs/ | 存放 SSL 证书,Nginx 读取这里 |
五、部署步骤(详细版)
5.1 安装 Docker(如未安装)
为什么需要 Docker?
- 隔离环境,不影响服务器其他服务
- 一键启动/停止
- 便于迁移
bash
# 安装 Docker(官方一键脚本)
curl -fsSL https://get.docker.com | sh
# 启动 Docker 并设置开机自启
sudo systemctl enable --now docker
sudo systemctl start docker
# 把当前用户加入 docker 组(避免每次用 sudo)
sudo usermod -aG docker $USER
# 重新登录生效,或者运行:
newgrp docker
# 验证安装
docker --version
docker compose version5.2 配置镜像加速器(可选但推荐)
使用云服务容器镜像服务加速,拉取镜像更快:
bash
# 配置 Docker 镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["你的镜像加速器地址"]
}
EOF
# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 验证配置
docker info | grep -A 10 "Registry Mirrors"5.3 创建目录
bash
# 创建所有需要的目录
mkdir -p ~/blog/{nginx,data/{html,certs}}
# 查看目录结构
tree ~/blog5.4 配置 Nginx(临时配置,用于证书申请)
重要:先配置临时配置(只有 80 端口),证书申请成功后再配置完整 SSL。
bash
# 临时 Nginx 配置(仅 80 端口,用于证书申请)
cat > ~/blog/nginx/nginx.conf << 'EOF'
server {
listen 80;
server_name blog.example.com;
root /var/www/html;
index index.html;
# Let's Encrypt 证书验证
location /.well-known/ {
root /var/www/html;
}
# 允许访问首页
location / {
try_files $uri $uri/ =404;
}
}
EOF5.5 配置 Docker Compose(临时配置)
bash
cat > ~/blog/docker-compose.yml << 'EOF'
services:
nginx:
image: nginx:latest
container_name: blog-nginx
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./data/html:/var/www/html:ro
- ./data/certs:/etc/nginx/certs:ro
restart: unless-stopped
EOF
# 启动容器
cd ~/blog
docker compose up -d5.6 申请 SSL 证书(关键步骤)
原理:Certbot 通过 HTTP 验证(80端口)证明你拥有这个域名
步骤:
bash
# 先启动一个临时 Nginx(只监听 80 端口,用于验证)
cat > ~/blog/docker-compose.yml << 'EOF'
services:
nginx:
image: nginx:latest
container_name: blog-nginx
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./data/html:/var/www/html:ro
- ./data/certs:/etc/nginx/certs:ro
restart: unless-stopped
EOF
# 启动容器(临时配置,只监听 80 端口)
cd ~/blog
docker compose up -d
# 申请 Let's Encrypt 证书(替换为你的邮箱)
docker run --rm \
-v $(pwd)/data/certs:/etc/letsencrypt \
-v $(pwd)/data/html:/var/www/html \
certbot/certbot certonly \
--webroot -w /var/www/html \
-d blog.example.com \
--email your-email@example.com \
--agree-tos --non-interactive
# 停止容器
docker compose down成功后的输出:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/blog.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/blog.example.com/key.pem5.7 配置完整的 Nginx(SSL)
证书申请成功后,配置完整的 Nginx 配置:
bash
cat > ~/blog/nginx/nginx.conf << 'EOF'
server {
listen 80;
server_name blog.example.com example.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name blog.example.com example.com;
ssl_certificate /etc/nginx/certs/live/blog.example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/live/blog.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
}
EOF5.8 配置完整的 Docker Compose 并启动
bash
cat > ~/blog/docker-compose.yml << 'EOF'
services:
nginx:
image: nginx:latest
container_name: blog-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./data/html:/var/www/html:ro
- ./data/certs:/etc/nginx/certs:ro
restart: unless-stopped
EOF
# 启动博客(注意:修改端口映射需要 down + up,不能用 restart)
cd ~/blog
docker compose down
docker compose up -d验证:
bash
# 测试 HTTPS 访问
curl -I https://blog.example.com
# 应该返回:HTTP/2 200
# 查看状态
docker compose ps
# 输出:
# NAME IMAGE COMMAND STATUS PORTS
# blog-nginx nginx "/docker…" Up 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp六、部署博客静态文件
6.1 本地构建 VitePress
在本地电脑上操作:
bash
# 进入你的 VitePress 项目目录
cd your-vitepress-project
# 安装依赖
npm install
# 构建静态文件
npm run docs:build
# 查看构建产物
ls -la docs/.vitepress/dist/
# 应该看到:index.html assets/ ...6.2 上传到云服务器
方式一:scp(简单直接)
bash
# 推送静态文件到云服务器
scp -r docs/.vitepress/dist/* user@你的服务器IP:/home/user/blog/data/html/方式二:rsync(增量同步,推荐)
bash
# 首次安装 rsync
sudo apt install -y rsync
# 增量同步(只上传不同的文件)
rsync -avz --delete \
-e "ssh -p 22" \
docs/.vitepress/dist/ \
user@你的服务器IP:/home/user/blog/data/html/七、常用命令
bash
# 启动博客
cd ~/blog && docker compose up -d
# 停止博客
docker compose down
# 注意:修改 docker-compose.yml 后必须用 down + up
docker compose down
docker compose up -d
# 查看运行状态
docker compose ps
# 查看日志
docker logs blog-nginx -f八、SSL 证书续期
Let's Encrypt 证书有效期 90 天,需要自动续期
bash
# 手动续期
cd ~/blog
docker run --rm \
-v $(pwd)/data/certs:/etc/letsencrypt \
-v $(pwd)/data/html:/var/www/html \
certbot/certbot renew \
--webroot --webroot-path /var/www/html --non-interactive
# 重载 Nginx 加载新证书
docker exec blog-nginx nginx -s reload自动续期脚本:
bash
# 添加到 crontab(每月 1 号凌晨 3 点执行)
crontab -e
# 添加:
# 0 3 1 * * /home/user/blog/renew-ssl.sh九、故障排查
常见问题
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 访问显示 502 | Nginx 无法找到静态文件 | 检查 data/html/ 是否有文件 |
| 访问显示 400 | SSL 证书路径错误 | 检查 data/certs/ 是否有证书 |
| 证书申请失败 | 域名未解析/端口未开放 | 检查 DNS 和防火墙 |
| 443 端口不通 | docker-compose.yml 端口未映射 | 使用 down + up,不是 restart |
调试命令
bash
# 1. 检查容器是否运行
docker ps
# 2. 检查端口占用
sudo lsof -i :80
sudo lsof -i :443
# 3. 检查 Nginx 配置
docker exec blog-nginx nginx -t
# 4. 查看 Nginx 错误日志
docker exec blog-nginx cat /var/log/nginx/error.log十、关键点总结
- 临时配置:先只用 80 端口申请证书,不要重定向
- 端口映射:修改
docker-compose.yml后必须docker compose down && up - 证书路径:Let's Encrypt 生成的证书在
live/你的域名/子目录 - 镜像加速:国内服务器建议配置容器镜像加速器