这篇博文主要用于备份,方便自己在迁移服务时做个参考
前景提要
我的 lkwplus.com 域名最初注册于 Namesilo,后迁移至 Cloudflare,域名解析和 CDN 由 Cloudflare 提供,项目代码托管于 GitHub(Private & Public repo)。
- VPS:腾讯云 2C2G30M 新加坡 LightHouse 服务器、
VKVM 4C8G500M 洛杉矶 9950X 高性能服务器、FameSystems 6C24G EPYC 9654 Root Server;- Containerized;
- PaaS:Cloudflare (Pages/Workers)、Vercel、fly.io、Zeabur、
Netlify、Heroku、Render、Koyeb、Glitch;- Serverless;
- Containerized;
云服务器
准备工作
安装 Docker
- 卸载旧版本:
- 配置 Docker apt 仓库:
- 安装最新版本 Docker:
配置 Node 环境
- 安装 pnpm:
- 安装 Node.js:
- 安装 PM2:
Caddy
文档地址,配置文件路径:/etc/caddy/Caddyfile
stable releases 安装方式:
Caddyfile 配置文件示例:
常用命令:
SABnzbd
Usenet 即新闻组,是一种历史久远的互联网产物,在早期主要用于论坛式的交流讨论,现在已经逐渐转化为文件存档类的服务,如想更多了解这个方向,可以在 r/usenet 等社区论坛上进行探索。
现在 Usenet 的使用体系由三部分构成:
- Indexer(索引器):负责在 Usenet 站点上搜集并索引内容,存储在索引库中。由于很多文件在上传时会经过加密或混淆处理,没有合适的 Indexer 很难从 Usenet 上获取高质量的资源。互联网上有少数的免费 Indexer 可供选择,但质量参差不齐,往往需要付费订阅多个 Indexer 站点从而获取更高质量的资源、更多的 API Quota;
- Provider(服务商):提供 Usenet 资源的 Post 和 Download 服务,由于 Usenet 上的资源十分庞大,各大服务商会根据自己的策略选择性地同步和存储部分内容。为了优雅的使用 Usenet 服务,往往需要付费订阅多个 Provider(不同 Backbone 的 Provider 间互相补充)来获取你所需的资源;
- Downloader(下载器):Downloader 是传入 nzb 文件,将 Usenet 上的资源下载到本地的工具。SABnzbd 是目前使用体验最好的两个 nzb 下载器之一(另一个是 NZBGet)。
可以配合 Sonarr、Radarr、Overseerr 等各类媒体管理工具,从而实现影视资源的自动入库和刮削,这是一个漫长的但有意思的折腾之路。
安装目录 /opt/sabnzbd
,docker-compose.yml
文件内容如下:
Alist
文档地址,安装目录: /opt/alist
服务状态则通过 systemctl 管理:
创建管理员密码:
对于个人而言,在配置文件 data/config.json
中修改以下内容:
添加如下存储源:
- 坚果云:协议为 WebDAV;
- 115 网盘:WebDAV 策略为 302 重定向,使得本地可快速访问,Cookie 则通过 Stream 软件获取自 115 官方微信小程序,有效期可达一年;
- Cloudflare R2:对象存储,有多个 Bucket 需要添加,统一置于
/cloudflare-r2
顶层目录下;- 地区:不可填默认的 auto,需要根据实际情况填入 Bucket 所在区域,如 apac、wnam;
- 自定义 host:根据个人在 Cloudflare 上为 R2 绑定的域名进行填写,如
https://img.lkwplus.com
;
- 本机存储。
Dozzle
文档地址,安装目录 /opt/dozzle
。
Dozzle 是一个轻量的 Docker 容器日志监视器,可以实时监视 Docker 容器的日志输出,并以可视化的方式呈现,同时还支持 SQL Analytics 等,功能强大,如下图:
首先建立数据目录 /opt/dozzle/data
,然后通过 Dozzle 的 generate 命令创建 users.yaml 文件,用于 Web 界面用户鉴权:
生成的 users.yml 文件内容中记录了用户信息和经过 hash 后的密码,对于版本在 8.5.1 前的 Dozzle 实例,采用 sha-256 算法进行加密,存在安全隐患,而自 Patched version 8.5.3 起,则采用 bcrypt 算法加密密码。
data/users.yml
形如:
docker-compose.yml
文件内容如下:
可以在多台服务器上运行 Dozzle agent,另一台服务器上通过 DOZZLE_REMOTE_AGENT
环境变量指定 Remote Agent 的地址,即可实现多主机的日志展示,详见文档。
Open WebUI
文档地址,安装目录 /opt/open-webui
。
Docker 安装
docker-compose.yml
文件内容如下:
pip 安装
采用 uv 管理 Python 虚拟环境,安装方式如下:
创建虚拟环境并安装 Open WebUI:
创建 ecosystem.config.js
用于 pm2 进行进程管理:
启动 Open WebUI:
Glance
文档地址,安装目录 /opt/glance
。
Glance 是一个定制化程度比较高的、用于各类信息源集中展示的 dashboard。
官方给出了一个 Preconfigured page 对应的配置文件,可以先上手按照搭建出来,后面再根据自己的需求逐步修改面板的布局、功能、信息源等。配置文件路径为:/opt/glance/glance.yml
docker-compose.yml
文件内容如下:
n8n
n8n 可用于构建自动化工作流,是 IFTTT 的开源替代,有各类软件集成,通过 Web UI 可以很方便的对自动化流程进行编辑与配置。
文档地址,安装目录 /opt/n8n
,docker-compose.yml
文件内容如下:
下面介绍的是一个简单的 Grafana + Prometheus + blabla-exporter + cAdvisor 构建的个人服务器监控体系:
Node Exporter
参考官方的 GitHub README,照抄配置文件即可。
Node Exporter 和下面的 Postgres Exporter 均采用 host 模式,直接使用宿主机的网络,从而便携的对相关资源进行监控。
docker-compose.yml
文件内容如下:
Postgres Exporter
docker-compose.yml
文件内容如下:
cAdvisor
监控容器资源可以有多种方案,这里采用 cAdvisor,它是一个运行在 Docker 容器内的、提供容器资源监控的工具。GitHub README
由于 Prometheus 实例和 cAdvisor 实例间通信通过 docker network 内部完成,因此可以省略掉 ports
配置。
docker-compose.yml
文件内容如下:
Beszel
Beszel 是一个轻量级的服务器监控工具,功能强大、前端界面美观,支持 Docker 监控和告警等。暂时选用 Beszel 作为容器资源监控的方案,替换掉了之前的 cAdvisor。
GitHub README,安装目录 /opt/beszel
,docker-compose.yml
文件内容如下:
进入页面后会要求设置初始管理员账户,添加需要进行监控的主机的相关 IP、端口信息,Beszel 会自动生成 agent 部署所需的 docker-compose.yml
。在放行相关端口的防火墙策略后,便可在目标主机启动 agent 开启监控。
Prometheus
为了使得 Prometheus 实例和 Grafana、cAdvisor 实例间顺畅通信,可以创建一个 docker network,命名为 monitering,并在相关的 docker-compose 配置文件中做好相关的定义,使其加入到这个 network 中。
同时,为了使得 Promethus 可以向 Node Exporter 和 Postgres Exporter 等采集数据,可以配置 extra_hosts
选项,将宿主机的 IP 地址映射到容器内的 host.docker.internal
。
docker-compose.yml
文件内容如下:
同时,通过 Prometheus 的配置文件 prometheus.yml
,定义各类 job,如下:
共定义了五个 job,每个 job 后续在 Grafana 对应一个 Dashboard,展示相关数据:
-
prometheus
:Prometheus 自身的监控指标,默认对外提供服务于http://localhost:9090
; -
node
:Node Exporter 采集的主机资源数据,由于采用 host 模式,可以通过http://host.docker.internal:9100
访问宿主机的 9100 端口获取数据; -
postgres
:Postgres Exporter 采集的数据库资源数据,由于采用 host 模式,可以通过http://host.docker.internal:9187
访问宿主机的 9187 端口获取数据; -
caddy
:Caddy 自身提供 Metrics 获取接口以供 Prometheus 采集,需要在 Caddyfile 中进行配置,开启 Metrics 接口: -
cadvisor
:cAdvisor 采集的容器资源数据,由于 Prometheus 和 cAdvisor 在同一个 docker network 中,因此通过http://cadvisor:8080
可以访问到。
VictoriaMetrics
经过对比,由 Prometheus 切换至单节点部署的 VictoriaMetrics,在存储空间、性能、系统资源占用方面都有明显提升。需要部署两个容器:
victoria-metrics
:用于存储和查询时间序列数据,采用单机模式部署;vmagent
:用于从数据源抓取信息,并将其上报到 VictoriaMetrics。
docker-compose.yml
文件内容如下:
配置文件 vmagent.yml
可与此前的 prometheus.yml
基本兼容,部分不支持的字段会默认跳过不进行严格校验。
下面简要描述为 vmagent 和 VictoriaMetrics 配置 Basic Auth 认证的过程。
- 修改
docker-compose.yml
,在各 service 的 command 部分添加命令行参数:- 对于 VictoriaMetrics,添加
--httpAuth.username={user1}
和--httpAuth.password={pwd1}
用于自身的身份认证; - 对于 vmagent,添加
--remoteWrite.basicAuth.username={user1}
和--remoteWrite.basicAuth.password={pwd1}
,用于 remote write 推送数据时进行认证;添加--httpAuth.username={user2}
和--httpAuth.password={pwd2}
用于自身的身份认证;
- 对于 VictoriaMetrics,添加
- 修改
vmagent.yml
,为 vmagent 从自身拉取 metrics 指标时添加认证: - 在 Grafana 中配置数据源时选择 Prometheus,添加 VictoriaMetrics 实例,并添加 Basic Auth 认证信息。
认证会在三个阶段进行:
- 访问 vmagent 和 VictoriaMetrics 的 WebUI;
- vmagent 向 VictoriaMetrics 进行 remote write 推送数据指标;
- Grafana 对接 VictoriaMetrics 进行数据查询并展示为图表。
Grafana
安装 Grafana 时会默认将数据存储于 sqlite3。考虑到性能和高可用等因素,可以选用 Postgres 等作为数据库,在常规的 Docker Compose 配置文件中加入如下环境变量即可:
docker-compose.yml
文件内容如下:
对应 Prometheus 中的五个 job,在 Grafana 中添加如下 Dashboard,用于不同类别的监控信息展示:
Gitea
一个基于 Go 语言开发的轻量级的 Git 服务器,文档地址,安装目录 /opt/gitea
,docker-compose.yml
文件内容如下:
qBittorrent
安装目录 /opt/qbittorrent
,docker-compose.yml
文件内容如下:
your_spotify
一个很美观的 Spotify 听歌记录展示页面,项目地址,由三部分组成:
your_spotify_server
:后端服务,负责提供 API 接口;your_spotify_client
:前端客户端,负责展示数据;mongodb:6
:数据库,负责存储数据。
为了节省资源,我省去了部署 MongoDB 的步骤,使用的是来自外部的免费 MongoDB 实例,通过 MONGO_ENDPOINT
环境变量进行声明。
值得注意的是,在部署完毕后 Web 端和服务端一直无法进行通信导致无法 Auth,最终解决方案是在 Cloudflare 域名解析中将 API_ENDPOINT
的 Proxy Status 设置为 DNS only(即关闭小黄云)。
在管理面板创建 token 后,可以将自己的 Spotify 数据分析面板分享给访客,示例效果。
docker-compose.yml
文件内容如下:
Opengist
GitHub Gist 的开源替代,项目地址,安装目录 /opt/opengist
,docker-compose.yml
文件内容如下:
Hoarder
此前一直使用 Omnivore 作为稍后读工具,存档一些值得阅读学习的文章、项目链接等,而近期该项目宣布停止服务,于是便开始寻找一款合适的开源自部署的 {书签、网页存档、稍后读} 工具。
在搜寻了一些社区的讨论后,通过筛选 selfh.st 中标签为 Bookmarks 的项目,了解到 Linkwarden、Readeck、Linkding 等活跃的社区项目替代品。
我比较看重经由接入 OpenAI API 自动根据网页内容生成标签的功能,选择 Hoarder 作为新的稍后读工具。安装部署流程详见 官方文档。
Redis
安装目录 /opt/redis
,docker-compose.yml
文件内容如下:
Vikunja
Vikunja 是一个开源的 Todo 应用,整体体验还不错,但目前功能有一定的局限性,例如在 iOS 上工作不正常、无法离线使用等,后续可能会寻找其他 Todo 类的开源替代。
后端数据库可选用 mariadb、postgres、sqlite 等,docker-compose.yml
文件内容如下:
Changedetection.io
Changedetection.io 是一个开源的网页变更监控工具,可以监控网页内容的变化并及时通知。它支持多种监控方式,包括文本内容、CSS 选择器、JSON 数据等,还可以设置过滤规则来忽略不需要关注的变化。可用于监测博客文章更新或是 VPS 商家补货等。
需要注意的是,Changedetection 通过 apprise 实现消息的实时通知,例如 Telegram Bot 的通知方式可定义为 tgram://bottoken/ChatID
。docker-compose.yml
文件内容如下:
SFTPGo
SFTPGo 是一个功能强大的 SFTP 服务器,可以通过界面美观简洁的 WebUI 进行用户管理和文件操作,支持 FTP、SFTP、SCP、WebDAV 等多种协议,并支持多种认证方式。docker-compose.yml
文件内容如下:
PG Back Web
PG Back Web 是一个开源的 PostgreSQL 备份管理工具,可以通过 WebUI 进行备份管理,将数据库定期备份于本地和 S3 等对象存储。安装部署流程详见 GitHub README。类似的解决方案还有 Docker PG Backup 等。
WeWeRSS
文档地址,用于将微信公众号转为 RSS Feed,体验还不错,订阅了一些技术类的公众号。docker-compose.yml
文件内容如下:
Moments
极简朋友圈风格的个人站点,用来无聊的时候瞎哔哔几句,项目地址,安装目录 /opt/moments
,docker-compose.yml
文件内容如下:
Uptime-Kuma
用于监控各类网站、服务等的可用性,并即时通知,文档地址,安装目录 /opt/uptime-kuma
,docker-compose.yml
文件内容如下:
Watchtower
文档地址,用于(自动)更新 Docker 镜像。
目前使用其用于自动更新镜像,并使用 Telegram Bot 进行通知,对于无需进行自动更新的 Container,可以在配置文件中添加 labels "com.centurylinklabs.watchtower.enable=false"
,docker-compose.yml
文件内容如下:
Diun
Diun (Docker Image Update Notifier) 是一个 Docker 镜像更新通知工具,暂时未使用,由 Watchtower 替代。安装目录 /opt/diun
,docker-compose.yml
文件内容如下:
Restic
增量备份方案,文档地址,类似的项目如 Duplicati (Linux 下运行需要 mono,所以排除)、Borg 等,详见 ArchLinux Wiki。
首先 dry-run 测试可以正常进行备份:
可以将备份任务添加至 crontab,如:
资源使用情况
这个小鸡目前 Docker 使用资源大致如下:
TODO
- 重要数据定期备份方案,上传至 Cloudflare R2;—> Restic
- 容器镜像的自动更新方案,通过 Telegram Bot 通知;—> Watchtower
- …
Cloudflare
可以参考 Awesome Cloudflare,发现更多有意思的基于 Cloudflare 的开源工具。
Cloudflare Pages
ChatGPT-Next-Web
调用各类 LLM api 进行对话的网页端项目,文档地址,配置构建命令和输出目录如下:
- Build command:
npx @cloudflare/next-on-pages --experimental-minify
- Build output:
.vercel/output/static
配置如下环境变量:
PS: Next.js 项目还是 Vercel 的支持更好,应该优先部署到 Vercel 而非 Cloudflare :)
excalidraw
用于绘制手绘风格的流程图,GitHub REAMDE,构建配置如下:
- Build command:
yarn --cwd ./excalidraw-app build
- Build output:
excalidraw-app/build
BroadcastChannel
用于将 Telegram Channel 转换为微博客,0 JS 的理念很有意思,文档地址,构建配置如下:
- Build command:
pnpm run build
- Build output:
dist
配置如下环境变量:
IT-Tools
IT 工具箱,功能丰富、UI 美观,文档地址,构建配置如下:
- Build command:
pnpm run build
- Build output:
dist
Web Archive
Web Archive 可以提供类似于使用 Singlefile 插件进行网页存档的功能,服务基于 Cloudflare D1 数据库及 R2 存储桶。参考 官方文档 进行一键部署,从 Release 页下载 Chrome 插件后即可开始使用。
Quartz
将 Obsidian 的笔记内容构建为静态网页,可定制性强,是一个很好的官方 Obsidian Publish 功能的替代方案,文档地址。我仿照一个非常好看 Quartz 实例 Garden’s Gate 进行了一些修改。构建配置如下:
- Build command:
git fetch --unshallow && npx quartz build
- Build output:
public
Slidev
Slidev 是一个为开发者设计的基于 Web 的幻灯片制作工具,文档地址,构建配置如下:
- Build command:
pnpm run build
- Build output:
dist
- Rewrites:
"source": "/(.*)", "destination": "/index.html"
MkDocs
采用 Material for MkDocs 主题的文档站,GitHub Repo。构建配置如下:
- Build command:
mkdocs build
- Build output:
site
R2 Uploader
此前一直苦于没有美观好用的用于 Cloudflare R2 的 S3 兼容上传器,用如 PicGo 之类的软件会感觉太重,体验一般。
而 jw-12138/r2-uploader 则很好的规避了太重的问题,保留核心功能,还支持传输大文件、自动压缩、自定义域名等,且密钥等均通过浏览器存在本地,保障了安全的问题,部署教程详见 README。
除此之外,轻量的命令行工具 pluveto/upgit 也很不错,非常推荐。
Sink
完全运行于 Cloudflare 的短链接生成工具,支持分析功能。部署教程详见 README。
Dimension
此前的个人主页,稍稍修改自 HTML5 UP 设计的静态页面。
site-status
基于 UptimeRobot API 的在线状态面板,根据 README 中的部署教程,修改 .env
文件中的 UptimeRobot API Key 即可。
Clouflare Workers
gh-proxy
基于 Cloudflare Workers 对 GitHub Release、Archive 以及项目文件进行反代,从而实现加速访问,提供了一个简单的 Web UI,部署教程。
DeepLX
详见项目 deeplx-for-cloudflare,可以给如沉浸式翻译插件或 Bob 等软件提供翻译 API 接口。
Reverse Proxy
基于 Cloudflare Workers 的简单反向代理脚本,且可以处理跨域请求,偶尔用于给无法访问源网站的朋友分享内容时会用到,部署教程详见 README。
Pastebin
通过 Cloudflare KV 进行存储的 Pastebin 项目,用于临时分享代码或小文件等使用,部署教程详见 README。
ChatGPT-Telegram-Workers
部署教程详见 README。环境变量如下:
Oaifree Helper
提取多个 ChatGPT 账号的 AccessToken/RefreshToken 后,基于 Cloudflare Workers 反代始皇的 new.oaifree.com 镜像站,从而实现免梯访问 ChatGPT 和多号切换,部署教程详见 README。
Fuclaude
Letterboxd Diary Embed
基于 Cloudflare Workers 获取任意用户的最新 Letterboxd 影评,并生成 HTML 代码以嵌入个人网站中,项目地址。
其逻辑是发出 GET 请求后会首先在 Cloudflare KV 中查询是否有缓存,若有则直接返回缓存内容,若没有则向 Letterboxd API 发出请求获取最新影评,并将结果 HTML 代码缓存到 KV 中。
个人对缓存逻辑和生成的影评 CSS 样式进行了简单修改后重新部署,以添加 ?username=lkw123
参数为例发送请求,获取到的的内容如下:
可以通过如下方式将其嵌入到博客中。具体效果详见我的博客的 Movies 页面。
PT Gen
根据豆瓣、IMDb、Bangumi、Steam 链接自动生成简介,主要用于 PT(自动化)发种,文档地址。
Vercel
此前在 Vercel 上部署的项目很多,但自决定全面转向 Cloudflare 的 CDN 和各类服务后,逐步对项目进行迁移。
RSSHub
RSSHub 是一个开源的、用于将各种网站的内容聚合到一个统一的接口中生成 RSS Feed 的项目,主要用于订阅未提供 RSS Feed 的网站或社交媒体。在这个碎片化信息爆炸的时代,做一些试图逃脱信息茧房的挣扎。
根据 GitHub Issue #14622 的讨论,在今年上半年起 Vercel/Cloudflare Workers 无法部署 RSSHub 的最新代码,测试可用的最新 Commit 截至 29276d8
。这个问题的修复目前卡在 got 和 NextJS 不兼容,需要等待 got 依赖从 RSSHub 项目移除。
暂时性的解决方案为:首先将 DIYgod/RSSHub 完整的 Fork 至自己账号下,可以在 Vercel 的 Create Deployment 处填入相应的 Commit 链接 https://github.com/{your-username}/RSSHub/commit/29276d8
,或是在 GitHub 将默认分支由 master 切换至 legacy 分支后再部署。
Koodo Reader
跨平台的电子书阅读器,部署教程详见 README。
Umami
Google Analytics 的开源替代,项目地址。
采用 Vercel 免费提供的 Postgres 作为后端数据库,和项目进行关联后,在部署页面配置数据库连接信息即可。同时,可以修改 TRACKER_SCRIPT_NAME
环境变量为不包含 umami、analytics 等关键字的名称,避免目标网站中引入的 js 脚本被 Adblock 等插件拦截。
Nobelium
项目地址,基于 Notion 的 Next.js 静态博客,类似的开源解决方案如 NotionNext,闭源解决方案如 Super,或是直接选择使用官方的 Notion Website 功能即可。
Homer
项目地址,极简风格的静态面板,比较适合用于服务器、Homelab、NAS 等,可以方便的集中整理自己的各类自部署服务或书签。
DailyHot
项目后端 imsyy/DailyHotApi-Vercel,项目前端 imsyy/DailyHot。后端部署完毕后,更改前端项目的环境变量 VITE_GLOBAL_API
即可,如 “https://dailyhot-api.lkwplus.com”。
Last.fm Recently Played
项目地址,用于生成个人的最新 Last.fm 听歌记录,可美观的展示于 GitHub Profile 或其他地方,类似的还可以选择同开发者的 JeffreyCA/spotify-recently-played-readme 项目。
由于该仓库自身提供服务使用的 *.vercel.app
子域名被墙,因此部署后绑定自定义域名以规避这个问题。具体效果详见我的博客的 Music 页面。
NetEase Music API
网易云音乐 Node.js API service,原仓库由于版权问题现已删库,如有需求可以考虑部署 PHP 实现 kilingzhang/NeteaseCloudMusicApi。自己此前 fork 的 仓库 尚且幸存,部署的 API 一直可以能正常使用。此前主要用于配合 qier222/YesPlayMusic 在 Vercel 搭建在线音乐 Web 端,但很少使用。
fly.io
我的 fly.io 账户幸运的停留在了 Legacy Hobby plan,可以免费部署三个 cpu-1x mem-256M 的实例,相当的大方且慷慨,感激 :)
Reader
阅读的服务器端项目,可以方便的在网页端摸鱼看小说。文档地址,fly.toml
文件内容如下:
FastAPI
源码存放于我的 GitHub 仓库 synthpop123/fly-fastapi,fly.toml
文件内容如下:
Vaultwarden
使用 Rust 构建的开源密码管理器 Bitwarden 的服务端实现,且和上游的 Bitwarden 客户端兼容,fly.toml
文件内容如下:
Memos
参考 hu3rror/memos-on-fly 的文档进行部署,除了保有项目的原功能外,还支持通过 Litestream 自动备份数据库到个人的 Backblaze B2。
为了接入 Telegram Bot,需要采用标签为 stable-memogram
的镜像,并需要手动添加 Bot Token 至环境变量:
fly.toml
文件内容如下:
顺手记录一下自己的 Memos 自定义 CSS 样式:
Zeabur
Zeabur 是一个比较新的云端部署服务,作为国人团队开发的产品,它会有更多的本地化支持和对大陆用户的优化。
在通常情况下,我们使用如 Zeabur 这类 PaaS 服务时,主要是将项目部署至其多区域的共享集群 (Shared Cluster),利用其 Edge 节点提供的高速网络连接,同时降低运维成本。
Zeabur 最近推出了“独立服务器”的功能,用户可以将自己的服务器注册到 Zeabur 上,从而无需支付硬件资源的使用费用,又能享受到平台为部署流程带来的便利。我用 VKVM 的洛杉矶 9950X 4C8G VPS 测试了下,效果还不错,但是占用系统资源比较多,如果有闲置的大内存机器可以尝试。
Blog
基于 Astro 构建,修改自 astro-erudite,并使用了 astro-theme-pure 中的部分组件样式。
Homepage
个人很喜欢博客主题 astro-erudite 的样式,就根据博客 clone 了一份,去除无用的依赖,保留 index.astro
单页面中的 Card 组建,并稍微调整样式,便成了新的个人主页。
Blog Legacy
基于 Astro 构建,修改自 AstroPaper,部分修改过程记录在了博文 AstroPaper 博客自定义 中,代码存放于我的 GitHub 仓库 synthpop123/astro-blog。自迁移至新的主题后,该旧博客暂时保留。
参考: