自托管服务
EdiWang/Moonglade avatar
EdiWang/Moonglade

Moonglade 评测:一个把 Azure 文件存储和双路径图片管理写进默认配置的 .NET 博客系统

该项目围绕「Blog system of runs on Microsoft Azure. Azure Blob Storage (Recommended) Create an Azure Blob Storage container with appropriate permissions: Enable CDN in admin settings for faster image delivery.」构建,适用于实际场景的开源实践,提供可复用的工具链与集成方式。

538 个 Star139 个 ForkC#GPL-3.0

秒懂

它是什么?
Moonglade 是一个面向开发者的自托管博客平台,默认部署路径深度绑定 Azure App Service 与 Azure Files。本文基于其 README 与仓库结构,分析它的架构、部署方式、存储设计以及适用边界。
适合谁用?
Moonglade 适合已经或计划把博客托管在 Azure App Service 上的 .NET 开发者,尤其是希望用 Azure Files 分离公开图片与原始图片、并愿意接受 Azure 生态锁定的用户。不适合需要零云依赖、想在共享主机或低配 VPS 上运行、或对图片存储路径没有清晰规划的人。
能商用吗?
可以,但有条件。GPL-3.0 是 copyleft 许可证:如果你分发包含它的软件,就必须以同一许可证公开该软件的源代码。只在内部运行、不对外分发,则不会触发这项义务。
还在维护吗?
在维护。仓库最近一次提交在 2 天前。
用什么语言写的?
主要是 C#(依据 GitHub 的语言统计)。

以上回答依据项目的 GitHub 数据(最近同步于 2026年9月14日)和我们的分析,不构成法律意见。

开源项目深度解析

它解决什么问题,以及为谁准备

Moonglade 解决的是开发者自托管博客时最烦的两件事:内容管理界面和部署脚本。它不是一个内容农场系统,也不是多用户 CMS。README 说得很清楚,它面向个人博客,提供文章、页面、分类、标签、评论、归档这些基本功能。真正的重点在部署层。项目默认把 Azure App Service 当作一等公民,Bicep 模板会为你创建两个独立的 Azure Files 共享,分别挂载到容器的 /app/images 和 /app/images-origin。这个设计直接回应了图片管理的常见痛点:公开访问的图片和保留原始文件的图片应该分开存储。如果你恰好是 Azure 用户,这个项目能省掉你手动写脚本和配置挂载点的时间。但如果你不是 Azure 用户,这套默认配置对你帮助有限,虽然 Docker 部署也存在,但它的存储设计依然围绕双路径展开。

双路径图片存储:设计意图与代价

Moonglade 的存储模型把图片分成公开版本和原始版本。公开图片放在 /app/images,原始图片放在 /app/images-origin。这个分离不是可选的,README 里强调必须保持两个卷都存在,否则升级或重建容器时图片会丢。这种做法的好处是,你可以对公开目录做 CDN 加速,而原始文件不受影响。代价是运维复杂度翻倍。你需要同时备份两个目录,任何一步遗漏都会造成不可恢复的丢失。Docker Compose 文件里用命名卷映射这两个路径,但命名卷的备份和迁移比单个目录麻烦。如果你只是个人写博客,这个设计显得过度。但如果你处理大量图片,或者有批量替换图片的需求,分离存储能让你安全地操作公开目录而不碰原始文件。README 没有说明如何迁移旧 Blob 容器里的图片,所以从旧版本升级时,你需要自己处理数据搬运。

架构:从解决方案文件看模块划分

仓库根目录是 src/Moonglade.slnx,这是 .NET 的新版解决方案格式。核心项目是 Moonglade.Web,它承载 Razor Pages、API 控制器、中间件和静态资源。业务逻辑放在 Moonglade.Features,里面是命令和查询,也就是 CQRS 风格的代码组织。数据访问用 EF Core,Moonglade.Data 定义 BlogDbContext 和实体,然后通过 Moonglade.Data.SqlServer 和 Moonglade.Data.PostgreSql 两个项目分别注册不同的数据库提供程序。这种拆分让数据库切换变得直接,你只需要改 appsettings.json 里的 ConnectionStrings:DatabaseProvider 字段。后台任务被隔离在 Moonglade.BackgroundServices,负责定时发布、更新检查这类工作。认证放在 Moonglade.Auth,支持本地账号和 OpenID Connect。测试项目按生产项目对齐,每个模块都有对应的 xUnit 测试。这个结构对维护者友好,但对你来说,它意味着编译和部署时你需要理解多个项目之间的依赖关系。

运行方式:Docker 与 Azure 脚本的差异

本地跑起来很简单,仓库根目录有 compose.yaml,执行 docker compose up -d 就能启动。Compose 文件里已经配置好两个命名卷和 ImageStorage 路径,你不需要手动创建目录。但要注意,默认的 Email 配置是空的,应用启动时会记录一条警告,博客照常运行,只是邮件通知不生效。你需要登录 /admin/settings/notification 查看设置指引,然后通过部署密钥添加 SMTP 配置。Azure 部署则走 Bicep 模板,它自动创建 Azure Files 共享并挂载到容器。这个模板不包含 CDN,也不迁移旧 Blob 容器里的图片。如果你想用 Blob Storage 而不是文件共享,README 提到 Azure Blob Storage 是推荐选项,但具体配置方式没有展开。开发时用 dotnet run --project src/Moonglade.Web/Moonglade.Web.csproj 启动,默认访问 https://localhost:10210,管理后台在 /admin,初始账号是 admin,密码 admin123,首次登录必须扫描二维码启用 TOTP。这个默认密码是公开的,生产环境必须改,README 没有说明改密码的具体步骤,但管理后台的账号设置页面可以处理。

数据库选择:SQL Server 与 PostgreSQL 的取舍

Moonglade 支持两种数据库:SQL Server 和 PostgreSQL。连接字符串都写在 appsettings.json 的 ConnectionStrings:MoongladeDatabase 里。SQL Server 的示例是 Windows 集成认证,PostgreSQL 的示例包含用户名密码和 Pooling=true。切换数据库只需要把 ConnectionStrings:DatabaseProvider 改成 SqlServer 或 PostgreSql。README 建议 SQL Server Express 免费版足够大多数生产场景。这个建议意味着,如果你已有 SQL Server 环境,可以沿用;如果你更熟悉 PostgreSQL,项目也给了同等支持。但要注意,两个数据库提供程序是独立项目,意味着某些 EF Core 行为可能不同,比如日期处理或分页语法。项目没有提供迁移工具,所以从 SQL Server 切换到 PostgreSQL 需要你自行处理数据迁移。对于新部署,选择哪个取决于你的运维习惯。如果你在 Azure 上,Azure SQL 和 Azure Database for PostgreSQL 都是选项,但 README 没有给出云数据库的配置示例。

限制与失败模式:哪些场景不适合

最明显的限制写在 README 开头:这个博客系统不得用于服务中国大陆用户,也不得发布中国法律禁止的内容。这不是一个技术限制,而是一个法律和合规声明,如果你面向中国大陆读者,你需要仔细评估。另一个失败模式是图片卷丢失。README 反复强调两个目录必须同时保留,但实际运维中,容器重建时忘记挂载卷是常见错误。一旦发生,公开图片和原始图片都会消失,且没有内置恢复机制。第三个限制是默认配置没有 CDN。README 提到可以在管理后台启用 CDN 来加速图片,但 Azure 快速部署脚本不包含 CDN,你需要手动配置。这意味着开箱即用的性能并不完整。另外,TOTP 是默认启用的,本地开发环境可以通过 Authentication:Totp:Required=false 绕过,但这个设置在生产环境会被忽略。如果你不习惯每次登录都输入验证码,这个强制步骤可能让你觉得繁琐。

替代方案:与同类 .NET 博客系统的差异

在 .NET 生态里,Moonglade 的主要替代是 Blogifier 和 Miniblog。Blogifier 是一个基于 ASP.NET Core 的博客系统,它采用更传统的单体架构,管理界面和前台在同一项目中,但它的存储不强制依赖 Azure Files,图片默认存在本地文件系统,也没有双路径分离。这意味着 Blogifier 部署到任意 VPS 或共享主机更容易,但它的图片管理没有 Moonglade 精细。Miniblog 则是一个极简的博客引擎,只支持 Markdown 和本地文件存储,没有数据库,也没有评论系统。它适合那些只需要写文章、不想维护数据库的人,但功能远少于 Moonglade。Moonglade 的差异点在于,它把 Azure 存储细节做进了默认配置,而 Blogifier 和 Miniblog 都保持云中立。如果你已经决定用 Azure,Moonglade 能省去配置时间;如果你还在云之间摇摆,Blogifier 的迁移成本更低。

维护与升级成本,以及许可证的含义

Moonglade 的更新节奏看起来稳定,最近的发布是 v16.5.0,间隔大约一周。这意味着你如果长期使用,需要定期跟进版本。升级时,README 强调要保留两个图片卷,否则数据丢失。这意味着升级不只是替换镜像,还要确保存储挂载配置不变。代码层面,项目使用 .NET 10.0 SDK,这是一个较新的版本,意味着你的开发环境需要跟进。Visual Studio 2026 或 VS Code 加 .NET 10 SDK 是官方推荐。数据库方面,SQL Server 2025 或 PostgreSQL 都在支持列表里,但旧版数据库可能不被支持。许可证是 GPL-3.0,这意味着如果你修改了代码并分发,你必须以相同许可证开源你的修改。如果你只是自托管运行,不修改代码,那么许可证的影响很小。但如果你计划基于 Moonglade 做二次开发并商业化,GPL-3.0 会要求你公开源码,这一点需要提前确认。

编辑结论

Moonglade 适合已经或计划把博客托管在 Azure App Service 上的 .NET 开发者,尤其是希望用 Azure Files 分离公开图片与原始图片、并愿意接受 Azure 生态锁定的用户。不适合需要零云依赖、想在共享主机或低配 VPS 上运行、或对图片存储路径没有清晰规划的人。在采用前,先确认两点:一是你能否接受 README 中明确写出的中国大陆使用限制,二是你是否愿意维护两个独立的图片卷或 Azure Files 共享,因为升级或迁移时丢失任一卷都会导致图片不可用。若你只是想要一个能快速跑起来的博客,Docker Compose 是可行路径,但默认配置里没有 CDN,图片加速需要你自行在 Azure 控制台或管理后台启用。最终判断:Moonglade 是一个把 Azure 部署细节做到默认配置里的博客系统,它的价值在于省去你手动配置存储挂载的步骤,而不是给你一个通用的跨云博客框架。

官方来源

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
社区笔记

社区笔记