Revise README with project details and usage instructions

Updated README.md to provide detailed project information and instructions.
This commit is contained in:
Frank Vitrano
2026-05-10 11:11:42 +08:00
committed by GitHub
parent a14917693b
commit e4a3b2c28f
+207 -2
View File
@@ -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.
<h1 align="center">py-blog</h1>
<p align="center">
<em>像写一份课程作业那样,搭一个属于自己的博客。</em><br/>
<em>Build your own blog the way you'd hand in a class project.</em>
</p>
<p align="center">
<a href="#中文文档">中文</a> · <a href="#english">English</a>
</p>
---
## 中文文档
### 为什么要再造一个博客
市面上的博客产品越来越像「企业级 CMS」:装一堆插件、配一套主题、改一坨 YAML,
最后才能写下第一行字。对一个**刚入门的同学**来说,这个过程不是在写博客,
是在向所有人宣告自己「不会用」。
但是新手**也有**写博客的需求:
- 想把课程笔记整理出来;
- 想把第一份小作品挂到自己的域名下;
- 想拥有一个写得不漂亮、但完全属于自己的角落。
`py-blog` 就是为这种需求做的。
### 核心理念:像项目作业一样构建博客
- **一个 `blog.py` 文件**就是整个项目,没有 `src/`,没有十层目录。
- 看得懂 Python 基本语法,就看得懂这个博客;想改首页样式,直接搜模板字符串。
- 部署像交作业:装依赖、跑脚本、看终端输出 —— 没有 Webpack,没有 Node。
### 功能一览
- 单文件 PythonFastAPI + 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
```
打开 <http://127.0.0.1:8765>,登录入口在 `/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 <http://127.0.0.1:8765>. 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.