From cf06e723486db51b7b5671462d11b28f1a378d34 Mon Sep 17 00:00:00 2001 From: Vaica <94612053+zqlit@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:04:35 +0800 Subject: [PATCH] 1404 --- write-server/README.md | 367 ++++++++++++++++----------- write-server/src/app/bot/page.tsx | 35 ++- write-server/src/app/wechat/page.tsx | 4 +- 3 files changed, 248 insertions(+), 158 deletions(-) diff --git a/write-server/README.md b/write-server/README.md index 03f3091c..6c3854ab 100644 --- a/write-server/README.md +++ b/write-server/README.md @@ -1,202 +1,275 @@ -# Write Server - Hugo Blog Admin for Linux -# 基于 Next.js 16 的 Hugo 博客管理后台 Linux 部署版本 +# Write Server -这是一个为 Linux 服务器优化的 Hugo 博客管理后台,支持 Docker 部署和 systemd 服务管理。 +Hugo 博客的本地管理后台,基于 Next.js 16 + Tailwind CSS 4,Docker 容器化部署。 -## 特性 +域名:`https://post.usj.cc` -- 完整的博客管理功能(文章、评论、友链、订阅源等) -- Docker 容器化部署 -- systemd 服务支持 -- Nginx 反向代理配置 -- 自动重启和健康检查 -- 日志管理 -- 备份策略 +## 功能模块 -## 快速开始 +| 模块 | 路径 | 说明 | +|------|------|------| +| 文章管理 | `/` | 列表、搜索、编辑、删除、预览 | +| 撰写文章 | `/edit` | Markdown 编辑器,图片上传 | +| 评论管理 | `/comments` | Artalk 评论回复、删除 | +| 订阅源 | `/feeds` | RSS 订阅源管理 | +| 友链管理 | `/links` | 友链增删改查 | +| 图片管理 | `/images` | 图片上传管理 | +| 公众号 | `/wechat` | 微信公众号发布(自包含) | +| 回收站 | `/recycle` | 已删文章恢复 | +| Bot 管理 | `/bot` | Telegram Bot / Hugo 状态 | -### 方式一:Docker 部署(推荐) +## 技术栈 -```bash -# 1. 克隆项目 -git clone -cd write-server - -# 2. 配置环境变量 -cp .env.example .env -nano .env # 编辑配置 - -# 3. 启动服务 -docker-compose up -d - -# 4. 查看日志 -docker-compose logs -f -``` - -### 方式二:直接部署 - -```bash -# 1. 安装依赖 -./scripts/install.sh - -# 2. 配置环境变量 -cp .env.example .env -nano .env - -# 3. 启动服务 -./scripts/start.sh - -# 4. 设置开机自启 -sudo ./scripts/setup-service.sh -``` +- **框架**: Next.js 16 (Turbopack, standalone 输出) +- **样式**: Tailwind CSS 4, SEN 暖色系 +- **数据**: 直接读写 Hugo Markdown 文件,无数据库 +- **评论**: Artalk API v2 +- **Bot**: Telegram Bot (长轮询) +- **公众号**: 微信 API 直连(不依赖外部服务) +- **反向代理**: Nginx + Basic Auth + Service Worker +- **Hugo 预览**: 独立端口 1313,HTTPS 访问 ## 目录结构 ``` write-server/ -├── src/ # 源代码 -├── public/ # 静态资源 -├── scripts/ # 部署脚本 -├── nginx/ # Nginx 配置 -├── systemd/ # systemd 服务文件 -├── backups/ # 备份目录 -├── logs/ # 日志目录 -├── Dockerfile # Docker 镜像配置 -├── docker-compose.yml # Docker Compose 配置 -├── .env.example # 环境变量模板 -└── README.md # 本文档 +├── src/ # 源代码 +│ ├── app/ # Next.js 页面和 API +│ ├── components/ # React 组件 +│ └── lib/ # 核心库(posts, recycle, bot, wechat, hugo) +├── nginx/ # Nginx 配置 +│ ├── conf.d/ # 站点配置(主站 + Hugo 预览) +│ ├── login.html # 登录页面 +│ └── sw.js # Service Worker(认证) +├── entrypoint.sh # Docker 入口脚本(权限修复) +├── Dockerfile # Docker 镜像 +├── docker-compose.yml # Docker Compose +├── .env.example # 环境变量模板 +└── .htpasswd # Basic Auth 密码文件 ``` -## 配置说明 +## 端口说明 -### 环境变量 +| 端口 | 用途 | 协议 | +|------|------|------| +| 80 | HTTP → HTTPS 重定向 | HTTP | +| 443 | 写作后台(nginx 代理 → 8016) | HTTPS | +| 1313 | Hugo 预览(nginx 代理 → 容器内 1313) | HTTPS | +| 8016 | write-server(仅容器内部) | - | -复制 `.env.example` 为 `.env`,并填写以下配置: +## 环境变量 (.env) ```bash -# 博客根目录(Hugo 项目路径) -BLOG_ROOT=/path/to/your/hugo/blog +# 评论系统 +ARTALK_SERVER=https://artalk.usj.cc +ARTALK_SITE=优世界 -# 服务端口 -PORT=8016 - -# Artalk 评论系统 -ARTALK_SERVER=https://artalk.your-domain.com -ARTALK_SITE=Your Site Name - -# Telegram Bot(可选) +# Telegram Bot TG_BOT_TOKEN=your-bot-token TG_ALLOWED_CHAT_IDS=your-chat-id -# 微信公众号(可选) +# 微信公众号(自包含,直连微信 API) WECHAT_APP_ID=your-app-id WECHAT_APP_SECRET=your-app-secret -# AI 配置(可选) -DEEPSEEK_API_KEY=your-api-key +# RSS/友链 API +RSS_API_BASE=https://api.usj.cc +RSS_API_TOKEN=your-token + +# AI +DEEPSEEK_API_KEY=your-key DEEPSEEK_BASE_URL=https://api.deepseek.com DEEPSEEK_MODEL=deepseek-chat + +# 其他 +DEFAULT_AUTHOR=小赵 +PREFER_IFACE=eth0 ``` -### Nginx 配置 - -如果需要域名访问,参考 `nginx/write-server.conf` 配置 Nginx 反向代理。 - -## 管理命令 +## 常用命令 ```bash -# Docker 方式 -docker-compose up -d # 启动 -docker-compose down # 停止 -docker-compose restart # 重启 -docker-compose logs -f # 查看日志 -docker-compose ps # 查看状态 +# 启动 +docker compose up -d -# systemd 方式 -sudo systemctl start write-server # 启动 -sudo systemctl stop write-server # 停止 -sudo systemctl restart write-server # 重启 -sudo systemctl status write-server # 查看状态 -sudo journalctl -u write-server -f # 查看日志 +# 停止 +docker compose down + +# 重建(代码/Dockerfile 变更后) +docker compose down +docker compose build --no-cache +docker compose up -d + +# 查看日志 +docker logs write-server -f +docker logs write-nginx -f + +# 重启单个服务 +docker compose restart write-server +docker compose restart nginx ``` -## 备份与恢复 +--- + +## 迁移到新服务器 + +### 1. 新服务器准备 ```bash -# 手动备份 -./scripts/backup.sh +# 安装 Docker +curl -fsSL https://get.docker.com | sh +systemctl enable docker +systemctl start docker -# 恢复备份 -./scripts/restore.sh backups/write-server-20260101.tar.gz - -# 自动备份(已配置 cron) -crontab -l # 查看定时任务 +# 安装 docker compose 插件 +apt install -y docker-compose-plugin git ``` -## 更新升级 +### 2. 克隆项目 ```bash -# 拉取最新代码 -git pull - -# Docker 方式 -docker-compose build --no-cache -docker-compose up -d - -# 直接部署方式 -npm install -npm run build -sudo systemctl restart write-server +cd ~ +mkdir -p hugo && cd hugo +git clone blog +cd blog/write-server ``` -## 故障排查 - -### 查看日志 +### 3. 配置环境变量 ```bash -# 应用日志 -tail -f logs/app.log - -# PM2 日志(直接部署方式) -pm2 logs write-server - -# Docker 日志 -docker-compose logs -f +cp .env.example .env +nano .env ``` -### 常见问题 +填写所有必要的 Token 和 API Key。 -1. **端口被占用** - ```bash - lsof -i :8016 - kill -9 - ``` +### 4. 生成 Basic Auth 密码 -2. **权限问题** - ```bash - sudo chown -R $USER:$USER /path/to/blog - ``` +```bash +docker run --rm httpd:alpine htpasswd -nbB admin "your-password" > .htpasswd +``` -3. **Hugo 未安装** - ```bash - # 参考 scripts/install.sh 安装 Hugo - ``` +### 5. 配置域名 DNS -## 安全建议 +添加 A 记录指向新服务器 IP: +``` +post.usj.cc → 新服务器IP +``` -1. 使用 HTTPS(配置 SSL 证书) -2. 限制访问 IP(防火墙或 Nginx 配置) -3. 定期更新依赖 -4. 启用访问日志 -5. 配置 fail2ban 防暴力破解 +### 6. 申请 SSL 证书 -## 性能优化 +```bash +apt install -y certbot -1. 启用 Gzip 压缩 -2. 配置 CDN -3. 使用 PM2 集群模式 -4. 配置 Redis 缓存(可选) +# 先启动 nginx(HTTP 模式) +docker compose up -d nginx -## 许可证 +# 停 nginx 释放 80 端口 +docker compose stop nginx -MIT License +# 申请证书 +certbot certonly --standalone -d post.usj.cc --agree-tos --email your@email.com + +# 复制证书 +mkdir -p nginx/ssl +cp /etc/letsencrypt/live/post.usj.cc/fullchain.pem nginx/ssl/ +cp /etc/letsencrypt/live/post.usj.cc/privkey.pem nginx/ssl/ + +# 启动所有服务 +docker compose up -d +``` + +### 7. 配置防火墙 + +```bash +ufw allow 22/tcp +ufw allow 80/tcp +ufw allow 443/tcp +ufw allow 1313/tcp +ufw enable +``` + +### 8. 配置 Git + +```bash +# 博客目录需要 git 可写 +git config --global --add safe.directory /root/hugo/blog +``` + +### 9. 验证 + +```bash +# 检查容器状态 +docker ps + +# 检查 API +curl -s https://post.usj.cc/api/stats + +# 检查 Hugo 预览 +curl -s https://post.usj.cc:1313/ | head -5 +``` + +### 10. 自动续期 SSL 证书 + +```bash +# 添加 crontab +crontab -e + +# 添加: +0 3 1 * * certbot renew --quiet && docker compose restart nginx +``` + +--- + +## 迁移清单 + +换服务器时需要迁移的内容: + +### 必须迁移 + +| 内容 | 位置 | 说明 | +|------|------|------| +| 博客源码 | `~/hugo/blog/` | git clone 即可 | +| write-server 代码 | `~/hugo/blog/write-server/` | git clone 即可 | +| .env 文件 | `write-server/.env` | 手动创建,填写 Token | +| .htpasswd 文件 | `write-server/.htpasswd` | 重新生成 | +| SSL 证书 | `nginx/ssl/` | 重新申请 | + +### 可选迁移 + +| 内容 | 位置 | 说明 | +|------|------|------| +| 回收站数据 | `write-server/recycle/` | 30 天自动过期,可不迁移 | +| 日志 | `write-server/logs/` | 可不迁移 | + +### 需要在新服务器操作 + +| 操作 | 说明 | +|------|------| +| DNS 解析 | 把 post.usj.cc 指向新 IP | +| SSL 证书 | 在新服务器重新申请 | +| 防火墙 | 放行 80, 443, 1313 端口 | +| git safe.directory | 新服务器执行 `git config --global --add safe.directory ...` | +| 微信 IP 白名单 | 如果用公众号功能,新服务器 IP 需加入微信白名单 | + +### 不需要迁移 + +| 内容 | 原因 | +|------|------| +| Docker 镜像 | 新服务器重新构建 | +| node_modules | Docker 构建时自动安装 | +| .next 目录 | Docker 构建时自动生成 | +| Hugo 二进制 | Dockerfile 自动安装 | + +--- + +## 已知限制 + +- Hugo 预览和写作后台共用域名,Hugo 导航链接只在 1313 端口有效 +- Telegram Bot 通过 Docker 挂载的 SSH 密钥进行 git push +- 博客目录 owner 会被 entrypoint 改为 uid 1001(nextjs 用户) +- 3 小时登录过期(localStorage + Service Worker 双重检查) + +## License + +MIT diff --git a/write-server/src/app/bot/page.tsx b/write-server/src/app/bot/page.tsx index f6cf5759..25ac938f 100644 --- a/write-server/src/app/bot/page.tsx +++ b/write-server/src/app/bot/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect } from "react"; -import { Bot, RefreshCw, Server } from "lucide-react"; +import { Bot, RefreshCw, Server, StopCircle } from "lucide-react"; interface BotStatus { bot: { enabled: boolean; polling: boolean }; @@ -33,6 +33,13 @@ export default function BotPage() { }, 3000); } + async function stopHugo() { + try { + await fetch("/api/hugo", { method: "DELETE" }); + await fetchStatus(); + } catch { /* ignore */ } + } + useEffect(() => { fetchStatus(); const timer = setInterval(fetchStatus, 10000); @@ -87,14 +94,24 @@ export default function BotPage() { : "已停止"} - +
+ + +
); diff --git a/write-server/src/app/wechat/page.tsx b/write-server/src/app/wechat/page.tsx index d675fa2c..1c422ed6 100644 --- a/write-server/src/app/wechat/page.tsx +++ b/write-server/src/app/wechat/page.tsx @@ -238,7 +238,7 @@ export default function WechatPage() { 我知道了