From e4a3b2c28f40313641197a16be7515832d6025a2 Mon Sep 17 00:00:00 2001 From: Frank Vitrano <90512559+WHC2006@users.noreply.github.com> Date: Sun, 10 May 2026 11:11:42 +0800 Subject: [PATCH] Revise README with project details and usage instructions Updated README.md to provide detailed project information and instructions. --- README.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f065222..56d1fe9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,207 @@ -# py-blog -A single-file Python blog (FastAPI + SQLite) with Markdown uploads, KaTeX math, tree-structured categories, pre-rendered HTML cache, admin panel with single-password login, and ICP footer for self-hosting behind nginx. +

py-blog

+ +

+ 像写一份课程作业那样,搭一个属于自己的博客。
+ Build your own blog the way you'd hand in a class project. +

+ +

+ 中文 · English +

+ +--- + +## 中文文档 + +### 为什么要再造一个博客 + +市面上的博客产品越来越像「企业级 CMS」:装一堆插件、配一套主题、改一坨 YAML, +最后才能写下第一行字。对一个**刚入门的同学**来说,这个过程不是在写博客, +是在向所有人宣告自己「不会用」。 + +但是新手**也有**写博客的需求: + +- 想把课程笔记整理出来; +- 想把第一份小作品挂到自己的域名下; +- 想拥有一个写得不漂亮、但完全属于自己的角落。 + +`py-blog` 就是为这种需求做的。 + +### 核心理念:像项目作业一样构建博客 + +- **一个 `blog.py` 文件**就是整个项目,没有 `src/`,没有十层目录。 +- 看得懂 Python 基本语法,就看得懂这个博客;想改首页样式,直接搜模板字符串。 +- 部署像交作业:装依赖、跑脚本、看终端输出 —— 没有 Webpack,没有 Node。 + +### 功能一览 + +- 单文件 Python:FastAPI + SQLite + Jinja2,**一份脚本即一个站点**。 +- Markdown 写作:上传 `.md` 即可,**保存时预渲染**为 HTML 缓存,访问零开销。 +- 数学公式:内置 KaTeX,支持 `$...$` / `$$...$$` / `\(...\)` / `\[...\]`。 +- 图片走图床:正文里用外链 URL,省去本地存储与备份烦恼。 +- 树形分组:按目录组织文章,同级按字典序,文章可按时间或手动顺序排列。 +- 单管理员后台:密码登录、CSRF、Session,够用且不繁琐。 +- 备案号挂载:`BLOG_ICP_TEXT` / `BLOG_ICP_URL` 环境变量直接生效,国内合规。 +- 反代友好:默认监听 `127.0.0.1:8765`,套 Nginx 即可上 HTTPS。 + +### 30 秒上手 + +```bash +git clone https://github.com/WHC2006/py-blog.git +cd py-blog +pip install -r requirements.txt +python blog.py +``` + +打开 ,登录入口在 `/admin/login`。 +若没设置 `BLOG_ADMIN_PASSWORD`,**首次启动会在终端打印一次随机密码**,请立刻收好。 + +### 环境变量 + +| 变量 | 默认 | 说明 | +| --- | --- | --- | +| `BLOG_HOST` | `127.0.0.1` | 监听地址,建议保持本机由 Nginx 反代 | +| `BLOG_PORT` | `8765` | 监听端口 | +| `BLOG_DATA_DIR` | `data` | SQLite 与运行数据目录 | +| `BLOG_SITE_TITLE` | — | 站点标题 | +| `BLOG_ADMIN_PASSWORD` | — | 管理员密码;未设置则首次启动随机生成并打印 | +| `BLOG_SECRET_KEY` | — | Session 签名密钥;未设置则自动生成并持久化 | +| `BLOG_ICP_TEXT` | — | 页脚备案文案,例如 `京ICP备xxxxxx号-1` | +| `BLOG_ICP_URL` | — | 备案查询链接,例如 `https://beian.miit.gov.cn/` | + +### Nginx 反代示例 + +```nginx +server { + listen 443 ssl http2; + server_name your.domain.com; + + # ssl_certificate ...; + # ssl_certificate_key ...; + + large_client_header_buffers 8 16k; + + location / { + proxy_pass http://127.0.0.1:8765; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +> 若使用 EdgeOne / WAF,请为 `/admin/*` 添加放行规则,避免登录 POST 被拦截。 + +### 不打算做的事 + +- 不内置富文本编辑器:写 Markdown 用你顺手的本地编辑器即可。 +- 不内置评论系统:需要时挂 Giscus / Disqus / Waline。 +- 不做主题市场:想换样式直接改模板字符串,**这才像做作业**。 + +### 协议 + +MIT。随便用,写得不好别骂得太狠。 + +--- + +## English + +### Why another blog + +Most blog platforms today feel like enterprise CMSs: plugins, themes, +YAML configs and a build pipeline before you can write a single sentence. +For a **beginner**, that whole process isn't writing a blog — +it's announcing to the world that you can't use one. + +But beginners also deserve a blog: + +- to publish their class notes; +- to put their very first project under their own domain; +- to own a small, imperfect corner of the internet. + +`py-blog` is built for that. + +### Core idea: build a blog like a class project + +- One file: `blog.py` **is** the whole project. No `src/`, no ten-level tree. +- If you can read basic Python, you can read this blog. Want to tweak the + homepage? Search the template strings inline. +- Deploying feels like submitting homework: install deps, run the script, + read the terminal. No Webpack, no Node, no incantations. + +### Features + +- Single-file Python: FastAPI + SQLite + Jinja2 — **one script, one site**. +- Markdown-first: upload `.md` files; HTML is **pre-rendered on save**. +- Math: KaTeX out of the box (`$...$`, `$$...$$`, `\(...\)`, `\[...\]`). +- Images via external CDN (image hosts) — no local upload/backup hassle. +- Tree-structured categories; siblings sorted A→Z; articles sorted by + time or by a manual `display_order`. +- Single-admin panel: password login, CSRF, sessions. Enough, not more. +- Built-in ICP footer (`BLOG_ICP_TEXT` / `BLOG_ICP_URL`) for hosting in China. +- Reverse-proxy friendly: binds to `127.0.0.1:8765` by default; put Nginx + in front for HTTPS. + +### Quick start + +```bash +git clone https://github.com/WHC2006/py-blog.git +cd py-blog +pip install -r requirements.txt +python blog.py +``` + +Open . Admin login lives at `/admin/login`. +If `BLOG_ADMIN_PASSWORD` is unset, **a random password is printed once** to +the terminal on first boot — copy it immediately. + +### Environment variables + +| Variable | Default | Description | +| --- | --- | --- | +| `BLOG_HOST` | `127.0.0.1` | Bind address; keep local and front with Nginx | +| `BLOG_PORT` | `8765` | Bind port | +| `BLOG_DATA_DIR` | `data` | Data directory (SQLite, etc.) | +| `BLOG_SITE_TITLE` | — | Site title | +| `BLOG_ADMIN_PASSWORD` | — | Admin password; auto-generated on first boot if unset | +| `BLOG_SECRET_KEY` | — | Session signing key; auto-generated and persisted if unset | +| `BLOG_ICP_TEXT` | — | Footer ICP text (China hosting) | +| `BLOG_ICP_URL` | — | Footer ICP link | + +### Nginx reverse proxy + +```nginx +server { + listen 443 ssl http2; + server_name your.domain.com; + + # ssl_certificate ...; + # ssl_certificate_key ...; + + large_client_header_buffers 8 16k; + + location / { + proxy_pass http://127.0.0.1:8765; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +> If you sit behind EdgeOne / a WAF, whitelist `/admin/*` so the login +> POST isn't silently dropped. + +### Non-goals + +- No bundled rich-text editor — use your favourite Markdown editor locally. +- No bundled comment system — drop in Giscus / Disqus / Waline if needed. +- No theme marketplace — edit the template strings; that's the whole point. + +### License + +MIT. Use it freely; be gentle when judging the code.