Skip to content

Docker 部署 VitePress 博客

使用 Docker Compose 在云服务器上部署 VitePress 博客


一、方案架构

1.1 访问流程

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

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 compose version

2.3 域名解析

在域名服务商添加解析:

记录类型主机记录记录值
Ablog111.230.145.190

2.4 开放端口

bash
# 防火墙开放端口
sudo ufw allow 22/tcp    # SSH(必须)
sudo ufw allow 80/tcp    # HTTP(证书申请需要)
sudo ufw allow 443/tcp   # HTTPS(博客访问)

# 腾讯云安全组也要开放这些端口!

三、原理讲解

3.1 为什么需要 Nginx?

┌────────────────────────────────────────────────────────────┐
│  直接跑 VitePress                                          │
│  docker run -p 3000:3000 viki/vitepress                   │
│                                                             │
│  用户访问:http://IP:3000  ❌ 端口丑,不安全                 │
└────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────┐
│  Nginx 反向代理                                            │
│                                                             │
│  用户访问:https://blog.hoseahu.cn  ✅ 域名+HTTPS          │
│                                                             │
│  优势:                                                     │
│  - 隐藏端口 3000                                           │
│  - HTTPS 加密                                              │
│  - 静态文件缓存                                             │
└────────────────────────────────────────────────────────────┘

3.2 为什么需要 SSL 证书?

┌─────────────────────────────────────────┐
│         HTTP vs HTTPS                   │
├─────────────────────────────────────────┤
│  HTTP(明文)                           │
│  用户 → 服务器                          │
│  密码/内容被中间人可见 ❌               │
│                                         │
│  HTTPS(加密)                          │
│  用户 ═══════════════════ 服务器 ✅      │
│  (TLS 加密,无法窃听)                   │
└─────────────────────────────────────────┘

四、目录结构

~/blog/
├── docker-compose.yml      # Docker 容器编排配置
├── nginx/
│   └── nginx.conf         # Nginx 配置文件
└── data/
    ├── html/              # 博客静态文件(构建产物)
    │   ├── index.html
    │   ├── assets/
    │   └── ...
    └── certs/             # SSL 证书(自动生成)
        ├── fullchain.pem
        ├── privkey.pem
        └── ...

五、部署步骤

5.1 安装 Docker(如未安装)

bash
# 安装 Docker(官方一键脚本)
curl -fsSL https://get.docker.com | sh

# 启动 Docker 并设置开机自启
sudo systemctl enable --now docker

# 把当前用户加入 docker 组
sudo usermod -aG docker $USER
newgrp docker

# 验证安装
docker --version

5.2 创建目录

bash
# 创建所有需要的目录
mkdir -p ~/blog/{nginx,data/{html,certs}}

5.3 配置 Nginx(临时配置,用于证书申请)

bash
# 临时 Nginx 配置(仅 80 端口,用于证书申请)
cat > ~/blog/nginx/nginx.conf << 'EOF'
server {
    listen 80;
    server_name blog.hoseahu.cn;
    root /var/www/html;
    index index.html;

    location /.well-known/ {
        root /var/www/html;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}
EOF

5.4 配置 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.5 申请 SSL 证书

bash
# 申请 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.hoseahu.cn \
  --email your-email@example.com \
  --agree-tos --non-interactive

# 停止容器
docker compose down

成功后的输出

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/blog.hoseahu.cn/fullchain.pem
Key is saved at: /etc/letsencrypt/live/blog.hoseahu.cn/privkey.pem

5.6 配置完整的 Nginx(SSL)

bash
cat > ~/blog/nginx/nginx.conf << 'EOF'
server {
    listen 80;
    server_name blog.hoseahu.cn hoseahu.cn;
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }
    location / {
        return 301 https://$host$request_uri;
    }
}
server {
    listen 443 ssl http2;
    server_name blog.hoseahu.cn hoseahu.cn;
    ssl_certificate /etc/nginx/certs/live/blog.hoseahu.cn/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/live/blog.hoseahu.cn/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    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.7 配置完整的 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

# 启动
docker compose up -d

# 查看状态
docker compose ps

5.8 验证部署成功

bash
# 测试 HTTPS 访问
curl -I https://blog.hoseahu.cn
# 应该返回:HTTP/2 200

六、部署博客静态文件

6.1 本地构建 VitePress

本地电脑上操作:

bash
# 进入你的 VitePress 项目目录
cd your-vitepress-project

# 安装依赖
npm install

# 构建静态文件
npm run docs:build

6.2 上传到云服务器

bash
# 推送静态文件到云服务器
scp -r docs/.vitepress/dist/* user@111.230.145.190:/home/user/blog/data/html/

# 或使用 rsync 增量同步
rsync -avz --delete docs/.vitepress/dist/ user@111.230.145.190:/home/user/blog/data/html/

七、CI/CD 自动部署

7.1 原理

┌─────────────────────────────────────────────────────────────┐
│                     CI/CD 流程                               │
├─────────────────────────────────────────────────────────────┤
│   1. 开发者 push 代码                                        │
│           │                                                  │
│           ▼                                                  │
│   2. Gitea 检测到 push                                       │
│           │                                                  │
│           ▼                                                  │
│   3. Runner 执行 Workflow                                    │
│           │                                                  │
│       ┌───┴───┐                                              │
│       ▼       ▼                                              │
│   4. 构建   5. 推送静态文件                                   │
│   静态文件  到云服务器                                        │
│           │                                                  │
│           ▼                                                  │
│   6. 博客自动更新                                            │
└─────────────────────────────────────────────────────────────┘

7.2 Workflow 配置

yaml
# .gitea/workflows/deploy.yml
name: Deploy Blog

on:
  push:
    branches: [main]
    paths: ['docs/**']

jobs:
  deploy:
    runs-on: self-hosted
    timeout-minutes: 10
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Build
        run: |
          npm install
          npm run docs:build
      
      - name: Deploy
        env:
          SSH_KEY: ${{ secrets.SSH_KEY }}
          HOST: ${{ secrets.HOST }}
          USER: ${{ secrets.USER }}
        run: |
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no" \
            docs/.vitepress/dist/ \
            $USER@$HOST:/home/$USER/blog/data/html/

八、管理维护

8.1 常用命令

bash
# 启动博客
cd ~/blog && docker compose up -d

# 停止博客
docker compose down

# 重启博客
docker compose restart

# 查看日志
docker logs blog-nginx -f

8.2 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

8.3 自动续期脚本

bash
cat > ~/blog/renew-ssl.sh << 'EOF'
#!/bin/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
docker exec blog-nginx nginx -s reload
EOF

chmod +x ~/blog/renew-ssl.sh

# 添加到 crontab(每月 1 号凌晨 3 点执行)
crontab -e
# 添加:0 3 1 * * /home/user/blog/renew-ssl.sh

九、故障排查

常见问题

问题原因解决方法
访问显示 502Nginx 无法找到静态文件检查 data/html/ 是否有文件
访问显示 400SSL 证书路径错误检查 data/certs/ 是否有证书
证书申请失败域名未解析/端口未开放检查 DNS 和防火墙
样式丢失静态资源路径错误检查 Nginx 配置

调试命令

bash
# 1. 检查容器是否运行
docker ps

# 2. 检查端口占用
sudo lsof -i :80
sudo lsof -i :443

# 3. 检查 Nginx 配置
docker exec blog-nginx nginx -t

# 4. 查看错误日志
docker exec blog-nginx cat /var/log/nginx/error.log

# 5. 检查静态文件
docker exec blog-nginx ls -la /var/www/html/

十、总结

部署成果

项目
博客地址https://blog.hoseahu.cn
静态文件目录~/blog/data/html/
SSL 证书Let's Encrypt (自动续期)

关键命令

操作命令
启动docker compose up -d
停止docker compose down
查看日志docker logs blog-nginx
重载 Nginxdocker exec blog-nginx nginx -s reload
更新博客rsync -avz docs/.vitepress/dist/ ~/blog/data/html/

基于开源技术构建