Skip to content

x01n/My-Blog

Repository files navigation

My-Blog

个人主页 + 服务导航 + 状态监控 + 博客,前后端一体化部署。

技术栈

技术
后端 Go + Gin + GORM/SQLite + go-redis + JWT + zap
前端 Next.js 16 + React 19 + shadcn/ui + TailwindCSS 4 + shiki
部署 Go embed 嵌入前端静态产物,单一二进制

前端含 PWAmanifest.json + public/sw.js):核心页可离线预缓存(含 /blog/archive/);用户导航mode === 'navigate')为网络优先,失败再读预缓存或 503 离线提示,在线始终易拿到新 HTML;子资源仍为缓存优先且非主文档可写入运行时缓存;仅同源 GET/api/uploads*.xml/admin/login/external 不拦截。嵌入部署时 _next/static/1 年 immutableicons/7 天 缓存。

快速开始

环境要求

  • Go 1.21+
  • Node.js 18+ / Bun 1.0+
  • (可选)Redis

开发模式

# 后端
go run ./cmd/main.go

# 前端(另一个终端)
cd frontend && bun install && bun run dev

一键构建

make build
# 生成 my-blog 二进制,运行:
./my-blog

Windows 用户可使用 PowerShell:.\build.ps1 -Target build,运行 .\my-blog.exe

配置

编辑 config.yaml

server:
  port: 8080
  mode: debug # debug / release
  trusted_proxies: [] # 可信代理列表(CIDR/IP)
  trusted_platform: "" # 可信平台(如 Cloudflare/Fly)
  cors:
    allow_origins: ["*"]
    allow_methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
    allow_headers: ["Origin", "Content-Type", "Authorization", "Accept"]
    expose_headers: ["Content-Length"]
    allow_credentials: false
    max_age_seconds: 86400

database:
  path: ./data/blog.db

redis:
  addr: ""  # 留空使用内存缓存

jwt:
  secret: "" # 必须修改

admin:
  username: "" # 必须修改
  password: "" # 必须修改
  email: "" # 必须修改

upload:
  path: ./data/uploads
  max_size_mb: 10
  allowed_extensions: [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".pdf", ".zip", ".md", ".txt"]

site:
  name: "My Blog"
  description: "一个个人博客站点"
  url: "" # 必须修改

# 可选:正文最大长度(Unicode 码点),0 为不限制;嵌入 Base64 图片时请酌情调大或改用上传
blog:
  max_content_runes: 0

站点配置(site-config)扩展键(示例)nav_page_intro(导航页说明)、home_background_modenone / fixed_url / random_pool)、home_background_urlhome_background_pool(每行一图 URL),在管理后台「站点设置」中填写。

安全提醒

  • 生产环境必须修改 jwt.secretadmin.password
  • 若使用反向代理/CDN,请配置 trusted_proxiestrusted_platform
  • site.url 影响 RSS/Atom/Sitemap 链接生成
  • 默认响应含基础安全头(X-Content-Type-OptionsX-Frame-OptionsReferrer-Policy 等);HSTS 建议在网关/反代上开启 HTTPS 后配置
  • 登录接口与 /api/v1/admin/*POST /api/v1/comments 响应带 Cache-Control: no-store,降低共享缓存误存含 Token/管理数据的风险

Docker / Compose

# 构建并启动
docker compose up -d --build

# 访问
http://localhost:8080

容器 healthcheck 默认探测 GET /live(轻量、不访问数据库)。编排 readiness 可选用 GET /ready(SQLite + 缓存 Ping;启用 Redis 时包含 Redis,失败返回 503)。

健康检查

路径 说明
GET /live 仅确认 HTTP 服务响应,适合 liveness
GET /ready Ping SQLite + 缓存;配置 Redis 时会探测 Redis,失败返回 503

项目结构

My-Blog/
├── cmd/main.go              # 入口
├── internal/
│   ├── app/                 # DI 容器
│   ├── model/               # 数据模型(UUID 主键)
│   ├── repository/          # 数据访问层(接口 + 实现)
│   ├── cache/               # 缓存层(Redis/Memory 双实现)
│   ├── service/             # 业务逻辑
│   │   ├── checker/         # 监控检测器(HTTP/TCP/Ping/DNS/SSL/Push)
│   │   ├── notifier/        # 通知发送器(Webhook/Email/Telegram)
│   │   └── scheduler/       # 监控任务调度器
│   ├── handler/             # HTTP 处理器
│   ├── middleware/           # 中间件(JWT/CORS/频率限制)
│   ├── router/              # 路由注册
│   └── static/              # 前端静态产物嵌入
├── frontend/                # Next.js 前端
│   ├── app/                 # 页面层
│   ├── services/            # API 调用层
│   ├── stores/              # 状态管理层
│   ├── hooks/               # 交互逻辑层
│   ├── components/          # UI 组件层
│   └── lib/                 # 工具层
├── config.yaml              # 配置文件
└── Makefile                 # 构建脚本

功能

  • 个人主页 — 头像/简介/社交链接/一言/时间
  • 博客 — Markdown 全量渲染(shiki 代码高亮 + KaTeX 公式 + GFM)+ 渐进式渲染防卡死 + 密码保护 + 评论(嵌套回复;后端校验文章状态、父评论归属与最大 3 层嵌套);列表/归档/上下篇等站内链接对 slug 使用 encodeURIComponent,与 RSS/Sitemap 的 PathEscape 语义一致;公开列表搜索可选 同时搜索正文search_in_content,有关闭时仅标题/摘要类字段,减轻大库扫描)。
  • 服务导航 — 分类卡片网格 + 搜索
  • 状态监控 — HTTP/TCP/Ping/DNS/关键字/SSL/Push 7种监控 + 可用性统计 + 告警通知
  • 后台管理 — 文章/评论/导航/监控/站点设置全 CRUD

API 接口

所有接口以 /api/v1/ 为前缀。管理接口需 JWT 认证(/api/v1/admin/)。

前端 frontend/services/* 对 URL 路径参数(slug、UUID、site-config key 等)统一使用 encodeApiPathSegmentencodeURIComponent,避免特殊字符截断路由;Gin 会按标准解码路径段。

frontend/lib/api-clientapi.get 查询参数 支持 boolean,会序列化为 true/false 字符串,与后端 ParseBoolQuery(如 search_in_contentinclude_configinclude_stats)一致。

Push 心跳POST /api/v1/push/:id 带约 300 次/分钟/IP 限流(正常 Push 监控上报频率远低于此);需正确 Authorization: Bearer <token>

OpenAPI 3.0 描述见仓库根目录 docs/openapi.yaml,可用 Swagger UI / Redoc 等工具浏览;文档内使用 components/responses(通用错误体)与 components/parameters(分页)做复用。健康检查GET /live(存活)、GET /ready(就绪,含 DB + 缓存)在站点根路径,不在 /api/v1 下。

文章 Slug:不可使用保留字 archive,否则与公开接口 GET /api/v1/posts/archive(归档列表)路由冲突,详情页与 getPostBySlug('archive') 会无法正确取文。

站点配置键(site-config:仅允许 ASCII 字母、数字、_-.,长度 ≤128,且不得包含 ..;单条配置值长度 ≤512KiB,避免异常键污染缓存键或超大写入。公开 GET /api/v1/site-config 会额外附带只读派生项 upload_max_size_mb(上传单文件上限 MB,来自 config.yamlupload.max_size_mb,≤0 时按 10),不可通过管理接口写入或删除。

文件上传upload.allowed_extensions 须至少包含一个有效扩展名,否则进程启动失败;管理端 POST /api/v1/admin/upload 带约 20 次/分钟/IP 限流(与 max_size_mb、白名单一并约束)。max_size_mb ≤ 0 时按 10MB 处理,且 Gin 的 MaxMultipartMemory 与此对齐,避免大请求体占用过多内存后才被拒。

Feed / Sitemap

  • /feed.xml/rss.xml
  • /atom.xml
  • /sitemap.xml

RSS/Atom/Sitemap 中文章链接对 slug 使用 PathEscape 编码,避免空格、Unicode 或特殊字符导致 URL 非法。

许可

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors