Updated README.md to provide detailed project information and instructions.
208 lines
7.1 KiB
Markdown
208 lines
7.1 KiB
Markdown
<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。
|
||
|
||
### 功能一览
|
||
|
||
- 单文件 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
|
||
```
|
||
|
||
打开 <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.
|