使用 GitHub Actions 自动部署 Astro 到云服务器完全指南

185 阅读4分钟

为什么选择自有服务器部署?

🎯 GitHub Pages 的限制

  • 路径问题:必须使用 /仓库名 作为基础路径

  • 域名限制:只能使用 username.github.io 或自定义域名

  • 功能限制:只支持静态文件,无法运行服务端代码

  • 存储限制:仓库大小和带宽有限制

✅ 自有服务器的优势

  • 完全控制:自由配置域名、路径、服务器环境

  • 性能优化:可以配置 CDN、缓存、压缩等

  • 功能扩展:支持 API、数据库、动态功能

  • 无限制:存储、带宽根据服务器配置而定

准备工作

🛠️ 必需的资源

1. 服务器环境

  • 操作系统:Debian 12 (本文以此系统为例)

2. 软件环境

  • Web 服务器:Nginx

  • Node.js:18+ 版本(如果需要服务端功能)

  • Git:版本控制

  • PM2:进程管理(可选)

服务器环境配置

🐧 Debian 服务器配置

1. 连接服务器

# 使用 SSH 连接服务器
ssh root@your-server-ip

# 或使用非 root 用户
ssh username@your-server-ip

2. 更新系统

# 更新包列表
sudo apt update

# 升级已安装的包
sudo apt upgrade -y

# 安装基础工具
sudo apt install -y curl wget git unzip

3. 安装 Nginx

# 安装 Nginx
sudo apt install -y nginx

# 启动 Nginx
sudo systemctl start nginx

# 设置开机自启
sudo systemctl enable nginx

# 检查状态
sudo systemctl status nginx

4. 安装 Node.js(可选)

# 安装 Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# 验证安装
node --version
npm --version

SSH 密钥配置

🔐 生成和配置 SSH 密钥

1. 在本地生成 SSH 密钥对

# 生成新的 SSH 密钥对
ssh-keygen -t ed25519 -C "github-actions@yourdomain.com" -f ~/.ssh/deploy_key

# 查看公钥
cat ~/.ssh/deploy_key.pub

2. 配置服务器

# 连接到服务器
ssh root@your-server-ip

# 创建部署用户(推荐)
sudo adduser deploy
sudo usermod -aG sudo deploy

# 切换到部署用户
sudo su - deploy

# 创建 .ssh 目录
mkdir -p ~/.ssh
chmod 700 ~/.ssh

# 添加公钥到授权文件
echo "你的公钥内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# 创建网站目录
sudo mkdir -p /var/www/your-website
sudo chown deploy:deploy /var/www/your-website

3. 配置 GitHub Secrets

在 GitHub 仓库中添加以下 Secrets:

  1. 进入仓库 → Settings → Secrets and variables → Actions

  2. 添加以下 secrets:

HOST: your-server-ip
USERNAME: deploy
SSH_PRIVATE_KEY: (私钥内容,即 ~/.ssh/deploy_key 文件的内容)

GitHub Actions 工作流配置

🤖 创建部署工作流

创建 .github/workflows/deploy.yml

name: 🚀 部署到自有服务器

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build-and-deploy:
    name: 构建并部署到服务器
    runs-on: ubuntu-latest

    steps:
      - name: 📥 检出代码
        uses: actions/checkout@v4

      - name: 🟢 设置 Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'

      - name: 📦 安装依赖
        run: npm ci

      - name: 🔨 构建项目
        run: npm run build
        env:
          NODE_ENV: production

      - name: 🚚 准备服务器
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script_stop: true
          script: |
            # 确保目标目录存在并设置权限
            sudo mkdir -p /var/www/my-website
            sudo chown -R deploy:www-data /var/www/my-website
            
            # 清理目标目录
            sudo rm -rf /var/www/my-website/*
            
            # 清理临时文件(如果有)
            rm -rf /tmp/dist

      - name: 📤 直接上传构建文件到目标目录
        uses: appleboy/scp-action@v0.1.4
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: 'dist/*'
          target: '/var/www/my-website/'
          strip_components: 1

      - name: 🔧 设置权限
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script_stop: true
          script: |
            # 设置正确的权限
            chmod -R 755 /var/www/my-website
            sudo chown -R deploy:www-data /var/www/my-website
            
            echo "✅ 部署完成!"

      - name: 🔄 重载 Nginx
        if: success()
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            echo "🔄 重载 Nginx..."
            if sudo nginx -t; then
              sudo systemctl reload nginx
              echo "✅ Nginx 重载成功"
            else
              echo "❌ Nginx 配置测试失败"
              exit 1
            fi

      - name: 🎉 部署成功通知
        if: success()
        run: |
          echo "🎉 网站已成功部署到服务器!"
          echo "🌐 访问地址: http://${{ secrets.HOST }}"

      - name:  部署失败处理
        if: failure()
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            echo "❌ 部署失败,清理临时文件..."

            # 清理临时文件
            rm -rf /tmp/website-build /tmp/my-website_deploy.sh /tmp/dist
            
            echo "⚠️ 请检查部署日志并手动处理"

Astro 项目配置优化

⚙️ 优化 astro.config.mjs

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  // 配置为你的域名或服务器 IP
  site: 'https://your-domain.com', // 或 'http://your-server-ip'
  
  // 输出目录
  outDir: './dist',
  
  // 静态资源配置
  build: {
    assets: 'assets',
    inlineStylesheets: 'auto',
  },
  
  // 集成插件
  integrations: [
    mdx(),
    sitemap(),
  ],
  
  // 开发服务器配置
  server: {
    port: 4321,
    host: true
  },
  
  // Vite 配置
  vite: {
    build: {
      rollupOptions: {
        output: {
          assetFileNames: 'assets/[name].[hash][extname]',
          chunkFileNames: 'assets/[name].[hash].js',
          entryFileNames: 'assets/[name].[hash].js',
        },
      },
    },
  },
});

安全性配置

🔐 Nginx 安全配置

创建 /etc/nginx/sites-available/your-website

# Nginx 配置文件
server {
    listen 80;
    server_name your-domain.com www.your-domain.com; # 替换为你的域名
    
    # 重定向到 HTTPS(如果配置了 SSL)
    # return 301 https://$server_name$request_uri;
    
    root /var/www/your-website/current;
    index index.html index.htm;
    
    # 安全头部
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    
    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;
    
    # 缓存静态资源
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
    
    # 主要路由
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # 隐藏 Nginx 版本
    server_tokens off;
    
    # 防止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
    
    # 错误页面
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
}

激活配置:

# 创建软链接
sudo ln -s /etc/nginx/sites-available/your-website /etc/nginx/sites-enabled/

# 删除默认配置(可选)
sudo rm -f /etc/nginx/sites-enabled/default

# 测试配置
sudo nginx -t

# 重新加载
sudo systemctl reload nginx

配置完成了,去 GitHub 提交代码就可以了。

🎉 总结

部署流程回顾

代码推送 → GitHub Actions → 构建项目 → 上传到服务器 → 自动部署 → 完成