Skip to content

Docker 部署 VitePress 博客教程

使用 Docker Compose 在云服务器上部署 VitePress 博客,包含完整的原理讲解和详细步骤


一、方案架构

1.1 为什么这么部署?

┌─────────────────────────────────────────────────────────────────────┐
│                         完整访问流程                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   用户浏览器                                                          │
│        │                                                              │
│        ▼                                                              │
│   https://blog.example.com ──→ 云服务器 Nginx (443端口)              │
│        │                           │                                 │
│        │                    ┌──────┴──────┐                          │
│        │                    │  Docker 容器 │                        │
│        │                    └──────┬──────┘                          │
│        │                           │                                 │
│        ▼                    ┌──────▼──────┐                          │
│   返回博客页面          ┌────│ 静态文件目录 │                          │
│                    ┌───┴────└─────────────┴────────┐                  │
│                    │   /data/html                 │                  │
│                    │   ├── index.html            │                  │
│                    │   ├── assets/               │                  │
│                    │   └── ...                   │                  │
│                    └─────────────────────────────┘                  │
└─────────────────────────────────────────────────────────────────────┘

1.2 组件说明

组件作用为什么用
NginxWeb 服务器,托管静态文件高性能,配置简单
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 域名解析

在域名服务商(腾讯云/阿里云)添加解析:

记录类型主机记录记录值
Ablog你的服务器IP

验证解析生效

bash
nslookup blog.example.com
# 应该返回服务器 IP

2.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.confNginx 服务器配置(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 version

5.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 ~/blog

5.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;
    }
}
EOF

5.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 -d

5.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.pem

5.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;
}
EOF

5.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

九、故障排查

常见问题

问题原因解决方法
访问显示 502Nginx 无法找到静态文件检查 data/html/ 是否有文件
访问显示 400SSL 证书路径错误检查 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

十、关键点总结

  1. 临时配置:先只用 80 端口申请证书,不要重定向
  2. 端口映射:修改 docker-compose.yml 后必须 docker compose down && up
  3. 证书路径:Let's Encrypt 生成的证书在 live/你的域名/ 子目录
  4. 镜像加速:国内服务器建议配置容器镜像加速器

基于 VitePress 构建