编辑
2026-10-25
项目分享
00

目录

简介
部署
有服务器、域名
1. 前置条件
2. 本地建站
3. 站点配置
4. 写文章
5. 本地开发与构建
6. 服务器初始化
7. Nginx
8. HTTPS
9. DNS(三家对比)
10. 发布
11. 检查清单
github免费部署
1. 仓库与 Pages 设置
2. Actions 工作流
3. 项目站的 base
4. 自定义域名
5. 检查清单与排错
常见故障对照(两条路线通用)
个人博客配置
导航与页脚
RSS 与 sitemap
SEO 与分享
评论
深色模式与阅读体验
多端写作实现
核心模型
内容目录约定
手机端方案对比
写作纪律
一键发布

简介

Astro 是一个面向内容网站的构建框架。它把 Markdown / MDX 当成一等公民,构建时把页面预渲染成纯 HTML,只在确实需要交互的组件上加载 JavaScript——官方把这种模式叫「群岛架构」(Islands)。

和 Hugo 一样,产物是静态文件,可以直接丢给 Nginx 或 GitHub Pages;不同的是 Astro 用 JS/TS 生态,页面是 .astro 组件,可以按需嵌入 React、Vue、Svelte 组件。

核心特点与优势:

  • 内容集合(Content Collections):在 src/content.config.ts 里用 zod 给 front matter 定义 schema,字段写错、日期格式不对会在构建时直接报错,而不是上线后才发现。

  • 默认零 JS:博客正文、列表页、RSS 都是构建时生成的静态 HTML,首屏没有框架运行时,加载快、SEO 友好。

  • 组件化:导航、卡片、评论这些可以写成组件复用;需要交互时再单独挂一个 React/Vue 岛屿,不必全站背框架。

  • 官方集成齐全:RSS、sitemap、图片优化、MDX、站点地图都是一条命令(npx astro add xxx)接入。

  • 模板生态成熟:npm create astro@latest -- --template blog 直接得到一份可用的博客(含文章集合、RSS、暗色模式),改内容即可上线。

  • Markdown 能力完整:支持 front matter、代码高亮、GFM 表格和任务列表,需要时可以写 MDX 混入组件。

和 Hugo 的取舍:

维度AstroHugo
构建速度秒级,文章上千时差距明显毫秒级到亚秒级,最快
技术栈Node + JS/TS,页面是组件Go 模板,纯配置文件驱动
可扩展性高:可嵌 React/Vue/Svelte,能写任意逻辑中:靠 shortcode、partial 和外部脚本
主题数量少但质量高,官方 blog 模板够用非常多,中文主题也多
学习成本需要会一点 JS/TS会 Markdown 就能写,改模板要学 Go 模板
部署静态产物,任意托管静态产物,任意托管

适合「想要现代前端体验、以后可能往站点里加交互组件、不介意为此装 Node 工具链」的人;如果只想最快出一篇博客,Hugo 更省事。

部署

Astro 的部署只有一条链路:本地或 CI 执行 npm run build,把 dist/ 里的静态文件放到 Web 服务器上。没有服务端进程,也不需要 Node 运行时。

维度服务器 + 域名GitHub Pages
费用服务器 + 域名公开仓库免费
国内访问备案后稳定*.github.io 不稳定
构建位置本地或服务器GitHub Actions
可控性高:任意 Nginx 规则低
适合场景正式博客、需要国内速度试水、读者在海外

有服务器、域名

1. 前置条件

  • 本地安装 Node.js(官方当前要求 22.23.4 或更高),node -v、npm -v 有输出。
  • 一台云服务器,1 核 1G 够用;系统 Ubuntu 22.04 / 24.04。
  • 域名一个。服务器在中国大陆境内必须先完成 ICP 备案。
  • 安全组和 ufw 放行 22 / 80 / 443。
  • 服务器不需要装 Node —— 构建在本地完成,只上传 dist/。

2. 本地建站

用官方 blog 模板起步:

bash
npm create astro@latest myblog -- --template blog cd myblog npm install

生成的目录(模板结构,略有版本差异):

myblog/ ├── astro.config.mjs ├── package.json ├── public/ # 原样拷贝到 dist/ 的静态文件 ├── src/ │ ├── assets/ # 会被优化的图片 │ ├── components/ │ ├── content/ │ │ └── blog/ # 文章,一篇一个 .md / .mdx │ ├── content.config.ts # 内容集合的 schema │ ├── layouts/ │ └── pages/ # 路由,文件路径即 URL └── dist/ # 构建产物,不要提交到 Git

3. 站点配置

astro.config.mjs:

js
import { defineConfig } from 'astro/config'; export default defineConfig({ site: 'https://example.com', // 必须和最终域名一致,RSS / sitemap 靠它生成绝对链接 // base: '/blog', // 只有部署在子路径(GitHub 项目站)时才需要 });

site 不做末尾斜杠;base 只在站点挂载在子目录时使用,写了之后所有内部链接都会带这个前缀。

4. 写文章

模板的文章放在 src/content/blog/,front matter 由 src/content.config.ts 校验:

ts
import { defineCollection, z } from 'astro:content'; import { glob } from 'astro/loaders'; const blog = defineCollection({ loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }), schema: z.object({ title: z.string(), description: z.string().optional(), pubDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), heroImage: z.string().optional(), tags: z.array(z.string()).default([]), draft: z.boolean().default(false), }), }); export const collections = { blog };

一篇文章:

markdown
--- title: 'Astro 博客部署笔记' description: '从建站到上线的一条完整路径' pubDate: '2026-10-25' tags: ['部署'] draft: false --- 正文从这里开始。

pubDate 写错格式、漏了 title,npm run build 会直接失败——这是 Astro 相对 Hugo 最舒服的一点:错误提前暴露。

5. 本地开发与构建

bash
npm run dev # http://localhost:4321,热更新 npm run build # 产物在 dist/ npm run preview # 本地预览 dist/ 的构建结果

发布前至少跑一次 npm run build && npm run preview,确认构建产物没问题,而不是只看 dev 的效果。

6. 服务器初始化

bash
ssh ubuntu@1.2.3.4 sudo apt update && sudo apt install -y nginx sudo mkdir -p /var/www/myblog sudo chown -R $USER:$USER /var/www/myblog sudo ufw allow 'Nginx Full'

7. Nginx

/etc/nginx/sites-available/myblog.conf:

nginx
server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/myblog; index index.html; location / { try_files $uri $uri/ =404; } location ~* \.html$ { add_header Cache-Control "no-cache"; } # Astro 的 /_astro/ 资源带内容哈希,可以放心长期缓存 location /_astro/ { expires 30d; add_header Cache-Control "public, max-age=2592000, immutable"; } error_page 404 /404.html; gzip on; gzip_types text/css application/javascript application/json image/svg+xml; gzip_min_length 1024; }
bash
sudo ln -s /etc/nginx/sites-available/myblog.conf /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t && sudo systemctl reload nginx

8. HTTPS

bash
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d example.com -d www.example.com sudo certbot renew --dry-run

9. DNS(三家对比)

服务器 IP 假设 1.2.3.4:

DNS 服务商配置入口记录注意点
CloudflareNS 改到 Cloudflare → DNS → RecordsA @ → 1.2.3.4、A www → 1.2.3.4橙云走代理时 SSL/TLS 必须是 Full (strict);签证书期间先灰云
阿里云 / 腾讯云云解析 DNS → 解析设置 → 添加记录A @ / www → 1.2.3.4,TTL 600国内服务器先备案
DNSPod域名解析 → 添加记录,主机记录 @ / www同上,TTL 600改完等 TTL 过期再验证
bash
dig +short example.com curl -I https://example.com

10. 发布

bash
npm run build rsync -avz --delete dist/ deploy@1.2.3.4:/var/www/myblog/

Windows Git Bash 没 rsync 时:scoop install rsync,或用 tar 管道:

bash
tar -czf - -C dist . | ssh deploy@1.2.3.4 'find /var/www/myblog -mindepth 1 -delete && tar -xzf - -C /var/www/myblog'

11. 检查清单

  • astro.config.mjs 的 site 与最终域名一致
  • npm run build 无报错,dist/index.html 存在
  • dist/ 在 .gitignore 里,没有提交进仓库
  • /_astro/ 资源返回 200,控制台无 404
  • certbot renew --dry-run 通过
  • 发布命令带 --delete,删掉的旧文章不残留
  • 手机 4G 打开一次,确认图片懒加载和字体正常

github免费部署

1. 仓库与 Pages 设置

  • 用户站:仓库名 <用户名>.github.io,访问根路径。
  • 项目站:仓库名随意,访问 https://<用户名>.github.io/<仓库名>/,此时必须设置 base。

推代码前确认 .gitignore 里有 dist/、node_modules/、.astro/。

仓库 Settings → Pages → Build and deployment → Source 选 GitHub Actions。

2. Actions 工作流

.github/workflows/deploy.yml(与 Astro 官方文档一致):

yaml
name: Deploy to GitHub Pages on: push: branches: [main] workflow_dispatch: permissions: contents: read pages: write id-token: write jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - name: Install, build, and upload your site uses: withastro/action@v6 deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - id: deployment uses: actions/deploy-pages@v5

要点:

  • withastro/action 自己会装依赖、跑 build、把产物上传成 Pages artifact,不用手写 npm install。
  • 它默认用 Node 24;项目需要别的版本时,用 action 的 node-version 输入覆盖。
  • workflow 里的 action 大版本会随官方文档更新,升级前对照一次 Astro 部署文档,别照抄旧版本号。

3. 项目站的 base

部署到 https://name.github.io/blog/ 时:

js
export default defineConfig({ site: 'https://name.github.io', base: '/blog', });

同时所有手写的绝对链接(/about/ 这种)都要改成带前缀或相对路径,否则会跳到域名根。模板自带的链接如果是 import.meta.env.BASE_URL 拼的就不用改。

4. 自定义域名

  1. astro.config.mjs 的 site 改成 https://blog.example.com,删除 base。
  2. 仓库 Settings → Pages → Custom domain 填同一个域名。Actions 发布路线下 GitHub 不生成也不读取 public/CNAME,不用再放这个文件。
  3. DNS:子域名 CNAME blog → <用户名>.github.io;根域名用四条 A 记录(185.199.108.153 / .109.153 / .110.153 / .111.153)。
  4. 等解析生效后勾选 Enforce HTTPS。

5. 检查清单与排错

现象原因处理
页面能开、样式全丢base 没配或配错项目站补 base,站点根域删掉
站内链接 404手写绝对路径没带 base改相对路径或用 BASE_URL
Action 构建失败Node 版本 / 依赖锁文件看日志,按需覆盖 node-version
RSS / sitemap 404没装 @astrojs/rss / @astrojs/sitemap,或 site 未配装集成,补 site
自定义域一直 pendingDNS 未生效 / 记录被代理dig 验证,Cloudflare 先关代理

常见故障对照(两条路线通用)

现象优先检查
构建报 front matter 校验失败src/content.config.ts 的 schema 与文章字段是否一致
图片 404放 public/ 的用 /xxx.jpg;放 src/assets/ 的必须 import 后用
中文路径打不开文件名用英文 slug,标题写在 front matter
改了文章线上没变浏览器缓存;Nginx 是否给 .html 设了 no-cache
部署后是旧版本上传目录不对(应上传 dist/ 的内容,不是 dist 文件夹本身)

个人博客配置

模板已经给了大部分结构,下面这几项决定它「像个博客」。

导航与页脚

导航在 src/components/Header.astro(模板命名可能略有差异),直接改链接数组:

astro
--- const links = [ { href: '/', label: '首页' }, { href: '/blog/', label: '文章' }, { href: '/about/', label: '关于' }, { href: '/rss.xml', label: 'RSS' }, ]; ---

页脚里放 GitHub、邮箱、备案号(国内服务器要放 ICP 备案号并链接到工信部)。

RSS 与 sitemap

bash
npm install @astrojs/rss npx astro add sitemap

RSS 端点 src/pages/rss.xml.js:

js
import rss from '@astrojs/rss'; import { getCollection } from 'astro:content'; export async function GET(context) { const posts = await getCollection('blog', ({ data }) => !data.draft); return rss({ title: '我的博客', description: '记录与分享', site: context.site, items: posts.map((post) => ({ title: post.data.title, pubDate: post.data.pubDate, description: post.data.description, link: `/blog/${post.id}/`, })), }); }

link 要与实际路由一致:模板的文章路由是 src/pages/blog/[...slug].astro,所以是 /blog/<id>/。sitemap 装好后访问 /sitemap-index.xml 验证。

SEO 与分享

在 layout 的 <head> 里保证有:

astro
<title>{title}</title> <meta name="description" content={description} /> <link rel="canonical" href={new URL(Astro.url.pathname, Astro.site)} /> <meta property="og:title" content={title} /> <meta property="og:description" content={description} /> <meta property="og:type" content="article" /> <meta property="og:image" content={new URL('/og.png', Astro.site)} />

Astro.site 来自 astro.config.mjs 的 site,所以配置没写对,canonical 和 OG 全是错的。

评论

静态站用 Giscus(基于 GitHub Discussions)。新建 src/components/Comments.astro:

astro
<script is:inline src="https://giscus.app/client.js" data-repo="your-name/blog" data-repo-id="R_xxx" data-category="Announcements" data-category-id="DIC_xxx" data-mapping="pathname" data-reactions-enabled="1" data-theme="preferred_color_scheme" data-lang="zh-CN" data-loading="lazy" crossorigin="anonymous" async> </script>

data-repo-id 和 data-category-id 在 giscus.app 按仓库生成,别手填。把组件放在文章 layout 的正文之后即可;data-mapping="pathname" 让每篇文章对应一个 Discussion。

深色模式与阅读体验

模板自带主题切换(ThemeToggle + localStorage);没有的话用 prefers-color-scheme 加一个手动切换按钮即可。阅读相关的两个建议:

  • 正文最大宽度控制在 65ch 左右;
  • 代码块加复制按钮(模板一般已内置),长文加目录需要自己从 headings 生成。

多端写作实现

核心模型

Markdown 在 Git 仓库,写作 = 提交,发布 = 推送触发构建。

改 src/content/blog/*.md → commit → push → GitHub Actions 跑 npm run build → Pages 部署 dist/(服务器路线则本地构建后 rsync)

Astro 比 Hugo 多一层 Node:手机上直接改 md 会触发 CI 构建,所以手机端不需要装环境;但本地预览和新增依赖必须在装了 Node 的机器上做。

内容目录约定

src/content/blog/ ├── astro-deploy/ │ ├── index.md # 文章 │ └── cover.jpg # 图片跟着文章走 └── hugo-deploy.md # 也可以单文件
  • 文件名或目录名用小写英文 slug,标题写 front matter。
  • 图片放文章同目录时用相对路径 ./cover.jpg;放 public/ 时用 /images/xxx.jpg;放 src/assets/ 时必须 import 才能享受图片优化。
  • draft: true 的文章模板默认不会出现在列表和 RSS 里,确认要发再改 false。

手机端方案对比

方案平台优点代价
GitHub 网页 / GitHub Mobile全平台零安装,改 md 即触发构建长文编辑弱;不能本地预览
Obsidian + GitiOS / Android / 桌面本地库、离线写、可直接 push手机端冲突要手动合并
Working CopyiOS完整 Git 客户端付费解锁推送
IntelliJ / VS Code桌面可 npm run dev 实时预览需要 Node 环境

写作纪律

  • 写前 git pull,写完立刻 push;不要两台设备同时挂未提交改动。
  • 一次提交一件事,提交信息 post: 文章标题。
  • 新增依赖(RSS、sitemap、评论)放在桌面端做,并提交 package.json 与锁文件,否则 CI 装不到。
  • 图片压缩:宽 ≤ 1600px、webp / jpg、单张 < 300KB。
  • 改 astro.config.mjs 后必须本地 npm run build 验证一次,配置错误只有在构建时才暴露。

一键发布

deploy.sh(GitHub Pages 路线删掉 rsync 那行):

bash
#!/usr/bin/env bash set -euo pipefail msg="${1:-post: 更新}" git pull --rebase npm ci npm run build git add -A git commit -m "$msg" || echo "没有需要提交的改动" git push # 服务器路线 rsync -avz --delete dist/ deploy@1.2.3.4:/var/www/myblog/ echo "已发布 $(date '+%F %T')"

npm ci 要求仓库里有 package-lock.json,没有就改成 npm install 并把它提交上去——CI 里的构建可复现性全靠这个锁文件。

本文作者:Weee

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!