从 0 开始:在阿里云 ECS 上部署 Astro 博客,并用 GitHub Actions 自动发布
最近把个人博客从本地开发环境迁移到了阿里云 ECS。服务器是全新实例,系统为 Ubuntu 24.04.4 LTS。这篇文章完整记录了从一台空白 ECS 开始,到博客可通过域名访问、启用 HTTPS,并且支持 GitHub Actions 自动部署的整个过程。
这篇文章适合以下场景:
- 你有一台全新的阿里云 ECS
- 你想部署的是 Astro 静态博客
- 你已经有自己的域名
- 你希望博客支持 HTTPS
- 你希望以后写完文章后,执行
git push就能自动上线
本文最终实现的架构如下:
- 本地电脑负责写博客和提交代码
- GitHub Actions 自动安装依赖、构建 Astro 项目
- 构建产物
dist/自动上传到 ECS - ECS 上的 Nginx 直接托管静态文件
- 域名解析到 ECS 公网 IP
- 网站通过 HTTPS 对外提供服务
一、为什么选择这种部署方式
Astro 博客本质上非常适合静态部署。对于个人博客来说,没有必要在服务器上长期运行 Node 服务,更没必要把 ECS 当构建机。
更稳妥的做法是:
- 本地或 GitHub Actions 负责构建
- 服务器只负责托管静态文件
- Nginx 负责访问入口和 HTTPS
- GitHub Actions 负责自动发布
这种方式有几个明显优点:
第一,服务器压力小。 第二,架构简单,出问题时容易排查。 第三,CI/CD 清晰,后续维护成本很低。 第四,适合 Astro、Vite 一类静态站点项目。
二、准备工作
开始之前,需要准备好以下几样东西:
- 一台阿里云 ECS,系统为 Ubuntu 24.04
- ECS 拥有公网 IP
- 一个已经注册好的域名
- GitHub 仓库
- 本地已经有 Astro 项目,或者准备新建一个
- 一个可用的 SSL 证书(本文采用手动部署证书,而不是 Certbot)
如果你的 ECS 在中国大陆节点,网站正式上线前还需要关注备案要求。
三、服务器基础初始化
先通过 SSH 登录 ECS。
ssh root@你的ECS公网IP登录后先更新系统,并安装基础软件:
apt update && apt upgrade -yapt install -y nginx git curl unzip ufw如果你希望启用 Ubuntu 防火墙,可以继续执行:
ufw allow OpenSSHufw allow 80/tcpufw allow 443/tcpufw enableufw status此外,在阿里云 ECS 控制台里,还需要确认安全组已开放以下端口:
- 22(SSH)
- 80(HTTP)
- 443(HTTPS)
如果安全组没有开放 80/443,即便 Nginx 配好了,外部也无法访问网站。
四、配置域名解析
进入域名的 DNS 管理后台,添加两条 A 记录:
主域名解析:
- 记录类型:A
- 主机记录:
@ - 记录值:ECS 公网 IP
www 子域名解析:
- 记录类型:A
- 主机记录:
www - 记录值:ECS 公网 IP
完成后可以在本地简单验证一下:
ping yourdomain.comping www.yourdomain.com如果解析结果已经指向 ECS 公网 IP,就说明域名已经生效。
五、准备博客部署目录
在服务器上创建博客目录:
mkdir -p /var/www/astro-blogchown -R www-data:www-data /var/www/astro-blogchmod -R 755 /var/www/astro-blog为了便于确认 Nginx 配置是否成功,可以先放一个临时测试页面:
cat > /var/www/astro-blog/index.html <<'EOF'<!doctype html><html> <head> <meta charset="utf-8"> <title>Astro Blog Ready</title> </head> <body> <h1>Astro Blog 部署目录已就绪</h1> </body></html>EOF六、配置 Nginx 托管站点
在 /etc/nginx/sites-available/ 下创建站点配置文件:
cat > /etc/nginx/sites-available/astro-blog <<'EOF'server { listen 80; listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/astro-blog; index index.html;
location / { try_files $uri $uri/ /index.html; }}EOF启用站点,并关闭默认站点:
ln -s /etc/nginx/sites-available/astro-blog /etc/nginx/sites-enabled/astro-blogrm -f /etc/nginx/sites-enabled/defaultnginx -tsystemctl reload nginx如果 nginx -t 输出 syntax is ok 和 test is successful,说明配置语法没有问题。
此时访问:
http://yourdomain.comhttp://www.yourdomain.com
如果能看到测试页,说明:
- 域名解析正常
- 80 端口正常
- Nginx 配置正常
- 站点目录可访问
七、创建或准备 Astro 项目
如果你还没有 Astro 项目,可以在本地创建:
npm create astro@latest如果你使用的是现成主题,比如 AstroPaper,也可以直接基于主题模板初始化。
进入项目目录后,安装依赖并本地运行:
npm installnpm run dev本地确认页面正常后,执行生产构建:
npm run build构建成功后,静态文件会输出到 dist/ 目录。
如果你的项目使用的是 pnpm,而不是 npm,那么命令应该改成:
pnpm installpnpm build八、Astro 项目的关键配置
部署到正式域名后,建议确认 astro.config.mjs 或主题配置文件里已经写入正确的生产环境地址。
例如:
import { defineConfig } from 'astro/config';
export default defineConfig({ site: 'https://yourdomain.com'});如果你使用 AstroPaper 之类的主题,还要修改主题自己的站点配置,例如:
- 网站标题
- 作者名
- 站点描述
- 正式域名
- 社交链接
- 时区
- 文章编辑地址
以 AstroPaper 为例,重点文件通常是:
src/config.tssrc/constants.ts
尤其要注意把正式域名填进去,否则 canonical URL、社交分享链接、SEO 信息可能都会不正确。
九、第一次手动部署 Astro 构建产物
在启用自动化部署前,建议先手动部署一次,确保服务器侧配置没问题。
本地构建:
npm run build或者:
pnpm build然后通过 rsync 或 scp 把 dist/ 上传到 ECS。
例如:
rsync -avz --delete dist/ root@你的ECS公网IP:/var/www/astro-blog/上传完成后,再次访问域名。 如果已经能看到 Astro 首页,而不是之前的测试页,说明静态文件部署路径是正确的。
十、手动部署 SSL 证书
本文使用的是手动申请的 SSL 证书,所以不使用 Certbot,而是手动把证书部署到 Nginx。
通常证书包里会有:
- 证书文件,例如
fullchain.pem或yourdomain.pem - 私钥文件,例如
yourdomain.key
先在 ECS 上创建证书目录:
mkdir -p /etc/nginx/sslchmod 700 /etc/nginx/ssl把证书文件上传到这个目录中,例如:
/etc/nginx/ssl/fullchain.pem/etc/nginx/ssl/yourdomain.key
然后收紧权限:
chmod 600 /etc/nginx/ssl/yourdomain.keychmod 644 /etc/nginx/ssl/fullchain.pem接着修改 Nginx 配置,让 80 跳转到 443,并配置 HTTPS。
cat > /etc/nginx/sites-available/astro-blog <<'EOF'server { listen 80; listen [::]:80; server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;}
server { listen 443 ssl; listen [::]:443 ssl; server_name yourdomain.com www.yourdomain.com;
root /var/www/astro-blog; index index.html;
ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/yourdomain.key;
location / { try_files $uri $uri/ /index.html; }}EOF然后测试并重载 Nginx:
nginx -tsystemctl reload nginx此时访问:
https://yourdomain.comhttps://www.yourdomain.com
如果能正常打开,说明 HTTPS 部署完成。
十一、为 GitHub Actions 准备部署账号
为了安全起见,不建议让 GitHub Actions 直接使用 root 用户登录 ECS。更合理的做法是创建一个专门的部署用户,比如 deploy。
adduser deployusermod -aG www-data deploymkdir -p /home/deploy/.sshchmod 700 /home/deploy/.sshchown -R deploy:deploy /home/deploy/.ssh然后需要给这个用户配置 SSH 公钥登录。
十二、生成 GitHub Actions 专用 SSH 密钥
在本地 Windows 电脑上,可以使用如下命令生成一对密钥。
mkdir %USERPROFILE%\.sshssh-keygen -t ed25519 -C "github-actions-deploy" -f "%USERPROFILE%\.ssh\github_actions_astro"会生成两个文件:
- 私钥:
C:\Users\你的用户名\.ssh\github_actions_astro - 公钥:
C:\Users\你的用户名\.ssh\github_actions_astro.pub
查看公钥内容:
type %USERPROFILE%\.ssh\github_actions_astro.pub会输出类似这样的一整行:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... github-actions-deploy把这一整行写入服务器上的:
/home/deploy/.ssh/authorized_keys可以用 nano 打开:
nano /home/deploy/.ssh/authorized_keys粘贴公钥后保存,再执行:
chmod 600 /home/deploy/.ssh/authorized_keyschown deploy:deploy /home/deploy/.ssh/authorized_keys一定要注意,authorized_keys 中写入的是:
github_actions_astro.pub的内容
不是私钥文件内容。
另外,公钥开头必须是:
ssh-ed25519如果写成了 sh-ed25519 之类的错误格式,SSH 会直接认证失败。
十三、先在本地测试 SSH 是否打通
在正式跑 GitHub Actions 之前,建议本地先测试一次 SSH 登录。
ssh -i "%USERPROFILE%\.ssh\github_actions_astro" deploy@你的ECS公网IP如果能成功登录,说明:
- 本地私钥没问题
- 服务器上的公钥没问题
- 用户名正确
- 权限正确
只有这一步先打通,GitHub Actions 的远程上传才有成功的基础。
十四、配置 GitHub 仓库 Secrets
进入 GitHub 仓库:
Settings -> Secrets and variables -> Actions
添加以下几个 Secrets:
ECS_HOST:你的 ECS 公网 IPECS_PORT:22ECS_USER:deployECS_SSH_KEY:私钥文件github_actions_astro的完整内容
注意,ECS_SSH_KEY 填的是私钥全文,内容会包含:
-----BEGIN OPENSSH PRIVATE KEY-----...-----END OPENSSH PRIVATE KEY-----不能把 .pub 文件内容填进这个 Secret。
十五、编写 GitHub Actions 自动部署 workflow
如果你的 Astro 项目使用的是 pnpm,推荐使用下面这份 workflow。
创建文件:
.github/workflows/deploy.yml内容如下:
name: Deploy Astro to ECS
on: push: branches: - main
env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs: build-and-deploy: runs-on: ubuntu-latest
steps: - name: Checkout uses: actions/checkout@v5
- name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.14.4
- name: Setup Node uses: actions/setup-node@v5 with: node-version: 22 cache: pnpm
- name: Install dependencies run: pnpm install --frozen-lockfile
- name: Build Astro run: pnpm build
- name: Upload dist to ECS uses: appleboy/scp-action@v1 with: host: ${{ secrets.ECS_HOST }} username: ${{ secrets.ECS_USER }} key: ${{ secrets.ECS_SSH_KEY }} port: ${{ secrets.ECS_PORT }} source: "dist/*" target: /var/www/astro-blog strip_components: 1 overwrite: true
- name: Fix permissions uses: appleboy/ssh-action@v1 with: host: ${{ secrets.ECS_HOST }} username: ${{ secrets.ECS_USER }} key: ${{ secrets.ECS_SSH_KEY }} port: ${{ secrets.ECS_PORT }} script: | chown -R deploy:www-data /var/www/astro-blog find /var/www/astro-blog -type d -exec chmod 775 {} \; find /var/www/astro-blog -type f -exec chmod 664 {} \;如果你项目使用的是 npm,就把 pnpm 相关命令替换成 npm 即可。
十六、pnpm 项目常见问题
如果你使用的是 pnpm 项目,仓库根目录里必须提交:
pnpm-lock.yaml否则 GitHub Actions 安装依赖时会失败。
另外,如果 package.json 中写了:
"packageManager": "pnpm@9.14.4"那么 pnpm/action-setup 里也要保持同样版本,不能写成 10,否则会报版本冲突错误。
换句话说,workflow 里的 pnpm 版本必须和项目自己声明的版本一致。
十七、触发自动部署
把 workflow 提交到仓库后,执行:
git add .git commit -m "add deploy workflow"git push之后进入 GitHub 仓库的 Actions 页面,就能看到自动部署任务开始执行。
成功后,流程会是:
- 拉取仓库代码
- 安装 Node 和 pnpm
- 安装依赖
- 构建 Astro
- 把
dist/上传到 ECS - 修复目录权限
- 网站自动更新
以后每次写完文章,只需要:
git add .git commit -m "publish new post"git push新的内容就会自动部署上线。
十八、常见问题排查
整个部署过程中,最容易踩到的坑主要有以下几类。
1. GitHub Actions 无法通过 SSH 认证
典型报错是:
ssh: unable to authenticate, attempted methods [none publickey]这通常说明:
ECS_SSH_KEY不是正确私钥- 服务器上的
authorized_keys没写对 - 公钥格式写错
- 用户名不匹配
.ssh或authorized_keys权限不正确
正确的排查顺序应该是:
先本地测试:
ssh -i "%USERPROFILE%\.ssh\github_actions_astro" deploy@你的ECS公网IP只有本地这条能通,GitHub Actions 才有机会成功。
2. authorized_keys 公钥格式错误
这是一个很隐蔽但常见的问题。 比如原本应当是:
ssh-ed25519 AAAA...如果误写成:
sh-ed25519 AAAA...那么 SSH 会直接把这行视为无效公钥,导致始终认证失败。
3. pnpm 版本冲突
如果 workflow 里写的是:
version: 10但 package.json 里写的是:
"packageManager": "pnpm@9.14.4"则会报多版本冲突错误。
解决方法很简单:保持两边完全一致。
4. 找不到 lock file
如果项目是 pnpm 项目,却使用了 npm 的 workflow,可能会报找不到 package-lock.json。
解决思路是:
- 使用
cache: pnpm - 使用
pnpm install --frozen-lockfile - 确保仓库里有
pnpm-lock.yaml
5. HTTPS 配好了但站点打不开
这种情况优先检查:
- 阿里云安全组是否放行 443
- UFW 是否放行 443
- 证书路径是否写对
- 证书和私钥是否配对
- Nginx 是否重载成功
十九、最终效果
完成上述所有步骤后,你会得到一个完整可用的个人博客部署方案:
- 域名已经绑定到阿里云 ECS
- Nginx 正常提供静态站点
- 网站通过 HTTPS 对外访问
- 每次提交代码后,GitHub Actions 自动构建并部署
这个方案对个人博客来说已经足够稳定,而且维护起来非常轻松。
二十、结语
这次部署最大的感受是: 对于 Astro 这类静态站点,最省心的方式并不是在服务器上运行开发环境,而是把服务器当作一个稳定的静态资源托管端。
本地负责开发。 GitHub Actions 负责构建。 ECS 负责托管。 Nginx 负责访问和 HTTPS。
职责清晰,问题也更容易定位。
如果你也正好在用阿里云 ECS、Ubuntu 24.04、Astro 或 AstroPaper,希望这篇记录能帮你少踩一些坑。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!