Upload 8 files
Browse files- DEPLOYMENT_GUIDE.md +318 -0
- Dockerfile +50 -226
- LICENSE +21 -0
- app.py +231 -31
- requirements.txt +25 -5
- start-services.sh +134 -0
DEPLOYMENT_GUIDE.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces WordPress 部署指南
|
| 2 |
+
|
| 3 |
+
本指南将帮助您在 Hugging Face Spaces 上成功部署 WordPress 应用。
|
| 4 |
+
|
| 5 |
+
## 📋 部署前准备
|
| 6 |
+
|
| 7 |
+
### 1. 账户要求
|
| 8 |
+
- Hugging Face 账户(免费或付费)
|
| 9 |
+
- 基本的 Git 操作知识
|
| 10 |
+
|
| 11 |
+
### 2. 文件清单
|
| 12 |
+
确保您有以下文件:
|
| 13 |
+
|
| 14 |
+
```
|
| 15 |
+
├── Dockerfile # Docker 构建文件
|
| 16 |
+
├── app.py # Python 应用入口
|
| 17 |
+
├── requirements.txt # Python 依赖
|
| 18 |
+
├── wp-config.php # WordPress 配置
|
| 19 |
+
├── monitor-cleanup.sh # 清理脚本
|
| 20 |
+
├── start-services.sh # 服务启动脚本
|
| 21 |
+
├── test-deployment.sh # 部署测试脚本
|
| 22 |
+
├── .dockerignore # Docker 忽略文件
|
| 23 |
+
├── README_SPACES.md # Spaces 说明文档
|
| 24 |
+
└── DEPLOYMENT_GUIDE.md # 本部署指南
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
## 🚀 部署步骤
|
| 28 |
+
|
| 29 |
+
### 步骤 1: 创建 Hugging Face Space
|
| 30 |
+
|
| 31 |
+
1. 访问 [Hugging Face Spaces](https://huggingface.co/spaces)
|
| 32 |
+
2. 点击 **"Create new Space"**
|
| 33 |
+
3. 填写 Space 信息:
|
| 34 |
+
- **Space name**: 选择一个唯一的名称(如:`my-wordpress-site`)
|
| 35 |
+
- **License**: 选择合适的许可证
|
| 36 |
+
- **SDK**: 选择 **"Docker"**
|
| 37 |
+
- **Visibility**: 选择 Public 或 Private
|
| 38 |
+
4. 点击 **"Create Space"**
|
| 39 |
+
|
| 40 |
+
### 步骤 2: 克隆仓库
|
| 41 |
+
|
| 42 |
+
```bash
|
| 43 |
+
# 克隆您的 Space 仓库
|
| 44 |
+
git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
|
| 45 |
+
cd YOUR_SPACE_NAME
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
### 步骤 3: 上传文件
|
| 49 |
+
|
| 50 |
+
将所有必要文件复制到 Space 仓库目录:
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
# 复制所有文件到 Space 目录
|
| 54 |
+
cp /path/to/wordpress-files/* ./
|
| 55 |
+
|
| 56 |
+
# 检查文件
|
| 57 |
+
ls -la
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
### 步骤 4: 提交和推送
|
| 61 |
+
|
| 62 |
+
```bash
|
| 63 |
+
# 添加所有文件
|
| 64 |
+
git add .
|
| 65 |
+
|
| 66 |
+
# 提交更改
|
| 67 |
+
git commit -m "Initial WordPress deployment for Hugging Face Spaces"
|
| 68 |
+
|
| 69 |
+
# 推送到远程仓库
|
| 70 |
+
git push origin main
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
### 步骤 5: 等待构建
|
| 74 |
+
|
| 75 |
+
1. 返回您的 Space 页面
|
| 76 |
+
2. Hugging Face 会自动检测 Dockerfile 并开始构建
|
| 77 |
+
3. 构建过程通常需要 5-15 分钟
|
| 78 |
+
4. 您可以在 "Logs" 标签页查看构建进度
|
| 79 |
+
|
| 80 |
+
## 🔧 配置说明
|
| 81 |
+
|
| 82 |
+
### 环境变量(可选)
|
| 83 |
+
|
| 84 |
+
在 Space 设置中,您可以添加以下环境变量:
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
# WordPress 配置
|
| 88 |
+
WORDPRESS_DB_NAME=wordpress
|
| 89 |
+
WORDPRESS_DB_USER=wordpress
|
| 90 |
+
WORDPRESS_DB_PASSWORD=wordpress
|
| 91 |
+
|
| 92 |
+
# 清理配置
|
| 93 |
+
FILE_RETENTION_DAYS=365
|
| 94 |
+
AUTO_CLEANUP_ENABLED=true
|
| 95 |
+
|
| 96 |
+
# 调试模式(仅开发时使用)
|
| 97 |
+
WP_DEBUG=false
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
### 自定义配置
|
| 101 |
+
|
| 102 |
+
#### 修改文件保留期限
|
| 103 |
+
|
| 104 |
+
编辑 `wp-config.php`:
|
| 105 |
+
|
| 106 |
+
```php
|
| 107 |
+
// 修改保留天数(默认365天)
|
| 108 |
+
define('FILE_RETENTION_DAYS', 180); // 改为6个月
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
#### 禁用自动清理
|
| 112 |
+
|
| 113 |
+
编辑 `wp-config.php`:
|
| 114 |
+
|
| 115 |
+
```php
|
| 116 |
+
// 禁用自动清理
|
| 117 |
+
define('AUTO_CLEANUP_ENABLED', false);
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
#### 修改内存限制
|
| 121 |
+
|
| 122 |
+
编辑 `wp-config.php`:
|
| 123 |
+
|
| 124 |
+
```php
|
| 125 |
+
// 增加内存限制
|
| 126 |
+
ini_set('memory_limit', '512M');
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
## 🔍 验证部署
|
| 130 |
+
|
| 131 |
+
### 自动测试
|
| 132 |
+
|
| 133 |
+
部署完成后,您可以运行测试脚本:
|
| 134 |
+
|
| 135 |
+
```bash
|
| 136 |
+
# 在本地测试(如果您有访问权限)
|
| 137 |
+
bash test-deployment.sh
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
### 手动验证
|
| 141 |
+
|
| 142 |
+
访问以下URL验证部署:
|
| 143 |
+
|
| 144 |
+
1. **主页**: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/`
|
| 145 |
+
2. **WordPress**: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/wordpress`
|
| 146 |
+
3. **健康检查**: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/health`
|
| 147 |
+
4. **清理状态**: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/api/cleanup/status`
|
| 148 |
+
|
| 149 |
+
### 检查清单
|
| 150 |
+
|
| 151 |
+
- [ ] 主页正常显示
|
| 152 |
+
- [ ] WordPress 安装页面可访问
|
| 153 |
+
- [ ] 健康检查 API 返回正常状态
|
| 154 |
+
- [ ] 清理状态 API 返回配置信息
|
| 155 |
+
- [ ] 可以创建 WordPress 管理员账户
|
| 156 |
+
- [ ] 可以登录 WordPress 后台
|
| 157 |
+
- [ ] 文件上传功能正常
|
| 158 |
+
- [ ] 清理统计在仪表板显示
|
| 159 |
+
|
| 160 |
+
## 🛠️ 故障排除
|
| 161 |
+
|
| 162 |
+
### 常见问题
|
| 163 |
+
|
| 164 |
+
#### 1. 构建失败
|
| 165 |
+
|
| 166 |
+
**症状**: Space 显示构建错误
|
| 167 |
+
|
| 168 |
+
**解决方案**:
|
| 169 |
+
- 检查 Dockerfile 语法
|
| 170 |
+
- 确保所有文件都已正确上传
|
| 171 |
+
- 查看构建日志中的具体错误信息
|
| 172 |
+
|
| 173 |
+
#### 2. 应用无法启动
|
| 174 |
+
|
| 175 |
+
**症状**: Space 显示 "Application Error"
|
| 176 |
+
|
| 177 |
+
**解决方案**:
|
| 178 |
+
- 检查 `start-services.sh` 脚本权限
|
| 179 |
+
- 确保端口 7860 正确配置
|
| 180 |
+
- 查看应用日志
|
| 181 |
+
|
| 182 |
+
#### 3. WordPress 数据库错误
|
| 183 |
+
|
| 184 |
+
**症状**: WordPress 显示数据库连接错误
|
| 185 |
+
|
| 186 |
+
**解决方案**:
|
| 187 |
+
- 检查 SQLite 插件是否正确安装
|
| 188 |
+
- 确认数据库目录权限
|
| 189 |
+
- 验证 `wp-config.php` 配置
|
| 190 |
+
|
| 191 |
+
#### 4. 文件上传失败
|
| 192 |
+
|
| 193 |
+
**症状**: 无法上传媒体文件
|
| 194 |
+
|
| 195 |
+
**解决方案**:
|
| 196 |
+
- 检查上传目录权限
|
| 197 |
+
- 确认磁盘空间充足
|
| 198 |
+
- 检查 PHP 上传限制
|
| 199 |
+
|
| 200 |
+
### 调试模式
|
| 201 |
+
|
| 202 |
+
启用调试模式以获取更多信息:
|
| 203 |
+
|
| 204 |
+
1. 编辑 `wp-config.php`:
|
| 205 |
+
```php
|
| 206 |
+
define('WP_DEBUG', true);
|
| 207 |
+
define('WP_DEBUG_DISPLAY', true);
|
| 208 |
+
```
|
| 209 |
+
|
| 210 |
+
2. 重新部署 Space
|
| 211 |
+
|
| 212 |
+
3. 查看错误信息
|
| 213 |
+
|
| 214 |
+
### 日志查看
|
| 215 |
+
|
| 216 |
+
如果您有容器访问权限,可以查看日志:
|
| 217 |
+
|
| 218 |
+
```bash
|
| 219 |
+
# WordPress 清理日志
|
| 220 |
+
tail -f /var/log/wordpress/cleanup.log
|
| 221 |
+
|
| 222 |
+
# Apache 错误日志
|
| 223 |
+
tail -f /var/log/apache2/error.log
|
| 224 |
+
|
| 225 |
+
# Python 应用日志
|
| 226 |
+
tail -f /var/log/python-app.log
|
| 227 |
+
```
|
| 228 |
+
|
| 229 |
+
## 📈 性能优化
|
| 230 |
+
|
| 231 |
+
### 1. 图片优化
|
| 232 |
+
|
| 233 |
+
- 上传前压缩图片
|
| 234 |
+
- 使用 WebP 格式
|
| 235 |
+
- 安装图片优化插件
|
| 236 |
+
|
| 237 |
+
### 2. 缓存配置
|
| 238 |
+
|
| 239 |
+
- 安装缓存插件(如 W3 Total Cache)
|
| 240 |
+
- 启用浏览器缓存
|
| 241 |
+
- 配置 CDN(如果需要)
|
| 242 |
+
|
| 243 |
+
### 3. 数据库优化
|
| 244 |
+
|
| 245 |
+
- 定期清理垃圾评论
|
| 246 |
+
- 限制文章修订版本
|
| 247 |
+
- 删除未使用的插件和主题
|
| 248 |
+
|
| 249 |
+
### 4. 监控和维护
|
| 250 |
+
|
| 251 |
+
- 定期检查清理日志
|
| 252 |
+
- 监控磁盘使用情况
|
| 253 |
+
- 保持 WordPress 和插件更新
|
| 254 |
+
|
| 255 |
+
## 🔒 安全建议
|
| 256 |
+
|
| 257 |
+
### 1. 强密码策略
|
| 258 |
+
|
| 259 |
+
- 使用复杂的管理员密码
|
| 260 |
+
- 启用双因素认证
|
| 261 |
+
- 定期更换密码
|
| 262 |
+
|
| 263 |
+
### 2. 插件安全
|
| 264 |
+
|
| 265 |
+
- 只安装必要的插件
|
| 266 |
+
- 保持插件更新
|
| 267 |
+
- 定期审查已安装插件
|
| 268 |
+
|
| 269 |
+
### 3. 访问控制
|
| 270 |
+
|
| 271 |
+
- 限制管理员账户数量
|
| 272 |
+
- 使用强用户名(避免 "admin")
|
| 273 |
+
- 配置 IP 白名单(如果需要)
|
| 274 |
+
|
| 275 |
+
### 4. 备份策略
|
| 276 |
+
|
| 277 |
+
- 定期导出重要内容
|
| 278 |
+
- 备份数据库文件
|
| 279 |
+
- 保存配置文件副本
|
| 280 |
+
|
| 281 |
+
## 📞 获取帮助
|
| 282 |
+
|
| 283 |
+
### 官方资源
|
| 284 |
+
|
| 285 |
+
- [Hugging Face Spaces 文档](https://huggingface.co/docs/hub/spaces)
|
| 286 |
+
- [WordPress 官方文档](https://wordpress.org/support/)
|
| 287 |
+
- [Docker 官方文档](https://docs.docker.com/)
|
| 288 |
+
|
| 289 |
+
### 社区支持
|
| 290 |
+
|
| 291 |
+
- Hugging Face 社区论坛
|
| 292 |
+
- WordPress 支持论坛
|
| 293 |
+
- GitHub Issues(如果项目开源)
|
| 294 |
+
|
| 295 |
+
### 技术支持
|
| 296 |
+
|
| 297 |
+
如果遇到技术问题,请提供以下信息:
|
| 298 |
+
|
| 299 |
+
1. Space 名称和 URL
|
| 300 |
+
2. 错误信息截图
|
| 301 |
+
3. 相关日志内容
|
| 302 |
+
4. 复现步骤
|
| 303 |
+
5. 环境配置信息
|
| 304 |
+
|
| 305 |
+
## 📄 许可证和免责声明
|
| 306 |
+
|
| 307 |
+
本部署方案基于开源软件构建,请遵守相关许可证条款:
|
| 308 |
+
|
| 309 |
+
- WordPress: GPL v2+
|
| 310 |
+
- Apache: Apache License 2.0
|
| 311 |
+
- Python: PSF License
|
| 312 |
+
- SQLite: Public Domain
|
| 313 |
+
|
| 314 |
+
**免责声明**: 本方案仅供学习和测试使用,生产环境使用前请进行充分测试和安全评估。
|
| 315 |
+
|
| 316 |
+
---
|
| 317 |
+
|
| 318 |
+
**祝您部署成功!** 🎉
|
Dockerfile
CHANGED
|
@@ -1,246 +1,70 @@
|
|
| 1 |
-
|
|
|
|
| 2 |
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
RUN apt-get update && apt-get install -y \
|
| 5 |
sqlite3 \
|
| 6 |
-
|
| 7 |
-
|
| 8 |
wget \
|
| 9 |
unzip \
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
&&
|
| 14 |
-
|
| 15 |
-
# 下载并安装WordPress核心文件
|
| 16 |
-
RUN cd /tmp && \
|
| 17 |
-
wget --timeout=30 --tries=3 https://wordpress.org/latest.tar.gz && \
|
| 18 |
-
tar -xzf latest.tar.gz && \
|
| 19 |
-
cp -r wordpress/* /var/www/html/ && \
|
| 20 |
-
rm -rf wordpress latest.tar.gz
|
| 21 |
|
| 22 |
# 下载并安装SQLite Integration插件
|
| 23 |
RUN cd /tmp && \
|
| 24 |
-
wget
|
| 25 |
-
unzip sqlite-integration.zip && \
|
| 26 |
-
mv sqlite-integration /
|
| 27 |
-
rm sqlite-integration.zip
|
| 28 |
-
|
| 29 |
-
# 复制PHP配置
|
| 30 |
-
COPY config/wp_php.ini /usr/local/etc/php/conf.d/conf.ini
|
| 31 |
-
|
| 32 |
-
# 创建SQLite数据库目录
|
| 33 |
-
RUN mkdir -p /var/www/html/wp-content/database
|
| 34 |
-
|
| 35 |
-
# 配置Apache监听7860端口
|
| 36 |
-
RUN sed -i 's/Listen 80/Listen 7860/' /etc/apache2/ports.conf && \
|
| 37 |
-
sed -i 's/:80>/:7860>/' /etc/apache2/sites-available/000-default.conf
|
| 38 |
|
| 39 |
# 创建必要的目录
|
| 40 |
-
RUN mkdir -p /var/www/html/wp-content/
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
# 创建SQLite数据库配置文件
|
| 45 |
-
RUN echo "<?php\n\
|
| 46 |
-
define('USE_MYSQL', false);\n\
|
| 47 |
-
define('DB_DIR', '/var/www/html/wp-content/database/');\n\
|
| 48 |
-
define('DB_FILE', 'wordpress.db');\n" > /var/www/html/wp-content/db.php
|
| 49 |
-
|
| 50 |
-
# 创建SQLite Integration必须使用插件加载器
|
| 51 |
-
RUN echo "<?php\n\
|
| 52 |
-
// SQLite Integration Must Use Plugin Loader\n\
|
| 53 |
-
if ( ! defined( 'ABSPATH' ) ) {\n\
|
| 54 |
-
exit;\n\
|
| 55 |
-
}\n\
|
| 56 |
-
\n\
|
| 57 |
-
// 加载SQLite Integration插件\n\
|
| 58 |
-
if ( file_exists( WP_CONTENT_DIR . '/plugins/sqlite-integration/load.php' ) ) {\n\
|
| 59 |
-
require_once WP_CONTENT_DIR . '/plugins/sqlite-integration/load.php';\n\
|
| 60 |
-
}\n" > /var/www/html/wp-content/mu-plugins/sqlite-integration-loader.php
|
| 61 |
-
|
| 62 |
-
# 创建wp-config.php用于SQLite
|
| 63 |
-
RUN echo "<?php\n\
|
| 64 |
-
define('DB_NAME', 'wordpress');\n\
|
| 65 |
-
define('DB_USER', 'root');\n\
|
| 66 |
-
define('DB_PASSWORD', '');\n\
|
| 67 |
-
define('DB_HOST', '');\n\
|
| 68 |
-
define('DB_CHARSET', 'utf8');\n\
|
| 69 |
-
define('DB_COLLATE', '');\n\
|
| 70 |
-
define('FS_METHOD', 'direct');\n\
|
| 71 |
-
define('WP_DEBUG', false);\n\
|
| 72 |
-
define('SQLITE_INTEGRATION_PLUGIN_PATH', '/var/www/html/wp-content/plugins/sqlite-integration/');\n\
|
| 73 |
-
\$table_prefix = 'wp_';\n\
|
| 74 |
-
if ( ! defined( 'ABSPATH' ) ) {\n\
|
| 75 |
-
define( 'ABSPATH', __DIR__ . '/' );\n\
|
| 76 |
-
}\n\
|
| 77 |
-
require_once ABSPATH . 'wp-settings.php';\n" > /var/www/html/wp-config.php
|
| 78 |
|
| 79 |
-
#
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
\n\
|
| 83 |
-
echo "=== WordPress GitHub Backup Loader ==="\n\
|
| 84 |
-
\n\
|
| 85 |
-
# 检查环境变量\n\
|
| 86 |
-
if [ -z "$GITHUB_TOKEN" ] || [ -z "$GITHUB_REPO" ]; then\n\
|
| 87 |
-
echo "警告: GITHUB_TOKEN 或 GITHUB_REPO 环境变量未设置,跳过GitHub备份加载"\n\
|
| 88 |
-
else\n\
|
| 89 |
-
echo "开始从GitHub加载备份数据..."\n\
|
| 90 |
-
\n\
|
| 91 |
-
# 设置GitHub API URL\n\
|
| 92 |
-
GITHUB_API="https://api.github.com/repos/$GITHUB_REPO"\n\
|
| 93 |
-
\n\
|
| 94 |
-
# 获取最近30天的备份文件
|
| 95 |
-
THIRTY_DAYS_AGO=\$\(date -d \"30 days ago\" +%Y-%m-%d\)\n\
|
| 96 |
-
\n\
|
| 97 |
-
echo "查找 $THIRTY_DAYS_AGO 之后的备份文件..."\n\
|
| 98 |
-
\n\
|
| 99 |
-
# 获取备份文件列表
|
| 100 |
-
BACKUP_RESPONSE=\$\(curl -s -H \"Authorization: token \$GITHUB_TOKEN\" \"\$GITHUB_API/contents/backups\"\)\n\
|
| 101 |
-
\n\
|
| 102 |
-
# 检查API响应是否有效\n\
|
| 103 |
-
if echo \"\$BACKUP_RESPONSE\" | jq -e . >/dev/null 2>&1; then\n\
|
| 104 |
-
# 检查是否是数组\n\
|
| 105 |
-
if echo \"\$BACKUP_RESPONSE\" | jq -e 'type == \"array\"' >/dev/null 2>&1; then\n\
|
| 106 |
-
BACKUP_FILES=\$\(echo \"\$BACKUP_RESPONSE\" | jq -r \".[] | select(.name | test(\\\"backup-[0-9]{4}-[0-9]{2}-[0-9]{2}\\\")) | .name\" | sort -r\)\n\
|
| 107 |
-
else\n\
|
| 108 |
-
echo \"GitHub API返回错误: \$\(echo \"\$BACKUP_RESPONSE\" | jq -r '.message // \"未知错误\"'\)\"\n\
|
| 109 |
-
BACKUP_FILES=\"\"\n\
|
| 110 |
-
fi\n\
|
| 111 |
-
else\n\
|
| 112 |
-
echo \"GitHub API响应格式错误\"\n\
|
| 113 |
-
BACKUP_FILES=\"\"\n\
|
| 114 |
-
fi\n\
|
| 115 |
-
\n\
|
| 116 |
-
if [ -z \"\$BACKUP_FILES\" ]; then\n\
|
| 117 |
-
echo \"��找到备份文件\"\n\
|
| 118 |
-
else\n\
|
| 119 |
-
# 获取最新的备份文件\n\
|
| 120 |
-
LATEST_BACKUP=\$\(echo \"\$BACKUP_FILES\" | head -n 1\)\n\
|
| 121 |
-
echo \"找到最新备份: \$LATEST_BACKUP\"\n\
|
| 122 |
-
\n\
|
| 123 |
-
# 下载并解压备份\n\
|
| 124 |
-
DOWNLOAD_URL=\$\(curl -s -H \"Authorization: token \$GITHUB_TOKEN\" \\\n\ \"\$GITHUB_API/contents/backups/\$LATEST_BACKUP\" | jq -r \".download_url\"\)\n\
|
| 125 |
-
\n\
|
| 126 |
-
if [ \"\$DOWNLOAD_URL\" != \"null\" ]; then\n\
|
| 127 |
-
echo \"下载备份文件...\"\n\
|
| 128 |
-
cd /var/www/html/wp-content/backup\n\
|
| 129 |
-
curl -L -o \"\$LATEST_BACKUP\" \"\$DOWNLOAD_URL\"\n\
|
| 130 |
-
\n\
|
| 131 |
-
# 解压备份\n\
|
| 132 |
-
if [[ \"\$LATEST_BACKUP\" == *.tar.gz ]]; then\n\
|
| 133 |
-
echo \"解压备份文件...\"\n\
|
| 134 |
-
tar -xzf \"\$LATEST_BACKUP\"\n\
|
| 135 |
-
\n\
|
| 136 |
-
# 恢复数据库\n\
|
| 137 |
-
if [ -f \"wordpress.db\" ]; then\n\
|
| 138 |
-
echo \"恢复SQLite数据库...\"\n\
|
| 139 |
-
cp wordpress.db /var/www/html/wp-content/database/\n\
|
| 140 |
-
fi\n\
|
| 141 |
-
\n\
|
| 142 |
-
# 恢复上传文件\n\
|
| 143 |
-
if [ -d \"uploads\" ]; then\n\
|
| 144 |
-
echo \"恢复上传文件...\"\n\
|
| 145 |
-
cp -r uploads/* /var/www/html/wp-content/uploads/\n\
|
| 146 |
-
fi\n\
|
| 147 |
-
\n\
|
| 148 |
-
echo \"备份恢复完成\"\n\
|
| 149 |
-
fi\n\
|
| 150 |
-
fi\n\
|
| 151 |
-
fi\n\
|
| 152 |
-
fi\n\
|
| 153 |
-
\n\
|
| 154 |
-
echo "=== 启动Apache ===\n"\
|
| 155 |
-
# 设置权限 (跳过chown,在HF Spaces中不需要)\n\
|
| 156 |
-
chmod -R 755 /var/www/html 2>/dev/null || true\n\
|
| 157 |
-
\n\
|
| 158 |
-
# 启动Apache\n\
|
| 159 |
-
exec apache2-foreground' > /usr/local/bin/start-wordpress.sh && \
|
| 160 |
-
chmod +x /usr/local/bin/start-wordpress.sh
|
| 161 |
|
| 162 |
-
#
|
| 163 |
-
RUN
|
| 164 |
-
set -e\n\
|
| 165 |
-
\n\
|
| 166 |
-
echo "=== WordPress GitHub Backup ==="\n\
|
| 167 |
-
\n\
|
| 168 |
-
# 检查环境变量\n\
|
| 169 |
-
if [ -z "$GITHUB_TOKEN" ] || [ -z "$GITHUB_REPO" ]; then\n\
|
| 170 |
-
echo "错误: GITHUB_TOKEN 或 GITHUB_REPO 环境变量未设置"\n\
|
| 171 |
-
exit 1\n\
|
| 172 |
-
fi\n\
|
| 173 |
-
\n\
|
| 174 |
-
# 创建备份目录\n\
|
| 175 |
-
BACKUP_DIR="/tmp/wordpress-backup"\n\
|
| 176 |
-
DATE=$(date +%Y-%m-%d-%H%M%S)\n\
|
| 177 |
-
BACKUP_NAME="backup-$DATE"\n\
|
| 178 |
-
\n\
|
| 179 |
-
mkdir -p "$BACKUP_DIR/$BACKUP_NAME"\n\
|
| 180 |
-
\n\
|
| 181 |
-
echo "创建备份: $BACKUP_NAME"\n\
|
| 182 |
-
\n\
|
| 183 |
-
# 备份SQLite数据库\n\
|
| 184 |
-
if [ -f "/var/www/html/wp-content/database/wordpress.db" ]; then\n\
|
| 185 |
-
echo "备份SQLite数据库..."\n\
|
| 186 |
-
cp /var/www/html/wp-content/database/wordpress.db "$BACKUP_DIR/$BACKUP_NAME/"\n\
|
| 187 |
-
fi\n\
|
| 188 |
-
\n\
|
| 189 |
-
# 备份上传文件\n\
|
| 190 |
-
if [ -d "/var/www/html/wp-content/uploads" ]; then\n\
|
| 191 |
-
echo "备份上传文件..."\n\
|
| 192 |
-
cp -r /var/www/html/wp-content/uploads "$BACKUP_DIR/$BACKUP_NAME/"\n\
|
| 193 |
-
fi\n\
|
| 194 |
-
\n\
|
| 195 |
-
# 创建压缩包\n\
|
| 196 |
-
cd "$BACKUP_DIR"\n\
|
| 197 |
-
tar -czf "$BACKUP_NAME.tar.gz" "$BACKUP_NAME"\n\
|
| 198 |
-
\n\
|
| 199 |
-
# 上传到GitHub\n\
|
| 200 |
-
echo "上传备份到GitHub..."\n\
|
| 201 |
-
\n\
|
| 202 |
-
# 将文件转换为base64\n\
|
| 203 |
-
FILE_CONTENT=$(base64 -w 0 "$BACKUP_NAME.tar.gz")\n\
|
| 204 |
-
\n\
|
| 205 |
-
# 上传到GitHub\n\
|
| 206 |
-
curl -X PUT \\\n\
|
| 207 |
-
-H "Authorization: token $GITHUB_TOKEN" \\\n\
|
| 208 |
-
-H "Content-Type: application/json" \\\n\
|
| 209 |
-
-d "{\\\"message\\\": \\\"WordPress backup $DATE\\\", \\\"content\\\": \\\"$FILE_CONTENT\\\"}" \\\n\
|
| 210 |
-
"https://api.github.com/repos/$GITHUB_REPO/contents/backups/$BACKUP_NAME.tar.gz"\n\
|
| 211 |
-
\n\
|
| 212 |
-
echo "备份完成: $BACKUP_NAME.tar.gz"\n\
|
| 213 |
-
\n\
|
| 214 |
-
# 清理临时文件\n\
|
| 215 |
-
rm -rf "$BACKUP_DIR"\n\
|
| 216 |
-
\n\
|
| 217 |
-
echo "备份上传到GitHub完成"' > /usr/local/bin/backup-wordpress.sh && \
|
| 218 |
-
chmod +x /usr/local/bin/backup-wordpress.sh
|
| 219 |
|
| 220 |
-
#
|
|
|
|
| 221 |
|
| 222 |
-
#
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
chmod 644 /var/log/php_errors.log
|
| 226 |
|
| 227 |
-
# 启
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
a2enmod expires
|
| 231 |
|
| 232 |
-
# 设置
|
| 233 |
-
RUN echo "
|
| 234 |
|
| 235 |
-
#
|
| 236 |
-
|
| 237 |
|
| 238 |
-
#
|
| 239 |
-
|
| 240 |
-
|
| 241 |
|
| 242 |
-
#
|
| 243 |
-
|
| 244 |
|
| 245 |
-
# 启
|
| 246 |
-
CMD ["/
|
|
|
|
| 1 |
+
# Hugging Face Spaces WordPress Dockerfile
|
| 2 |
+
# 适配单容器部署,使用SQLite数据库,包含自动清理功能
|
| 3 |
|
| 4 |
+
FROM wordpress:6.4-apache
|
| 5 |
+
|
| 6 |
+
# 设置环境变量
|
| 7 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 8 |
+
ENV WORDPRESS_DB_HOST=localhost
|
| 9 |
+
ENV WORDPRESS_DB_NAME=wordpress
|
| 10 |
+
ENV WORDPRESS_DB_USER=wordpress
|
| 11 |
+
ENV WORDPRESS_DB_PASSWORD=wordpress
|
| 12 |
+
ENV PYTHONUNBUFFERED=1
|
| 13 |
+
|
| 14 |
+
# 安装必要的包
|
| 15 |
RUN apt-get update && apt-get install -y \
|
| 16 |
sqlite3 \
|
| 17 |
+
php-sqlite3 \
|
| 18 |
+
cron \
|
| 19 |
wget \
|
| 20 |
unzip \
|
| 21 |
+
python3 \
|
| 22 |
+
python3-pip \
|
| 23 |
+
curl \
|
| 24 |
+
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
# 下载并安装SQLite Integration插件
|
| 27 |
RUN cd /tmp && \
|
| 28 |
+
wget https://downloads.wordpress.org/plugin/sqlite-database-integration.2.1.5.zip && \
|
| 29 |
+
unzip sqlite-database-integration.2.1.5.zip && \
|
| 30 |
+
mv sqlite-database-integration /usr/src/wordpress/wp-content/plugins/ && \
|
| 31 |
+
rm sqlite-database-integration.2.1.5.zip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
# 创建必要的目录
|
| 34 |
+
RUN mkdir -p /var/www/html/wp-content/database \
|
| 35 |
+
&& mkdir -p /var/log/wordpress \
|
| 36 |
+
&& mkdir -p /scripts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
# 复制Python应用文件
|
| 39 |
+
COPY app.py /app/
|
| 40 |
+
COPY requirements.txt /app/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
+
# 安装Python依赖
|
| 43 |
+
RUN pip3 install --no-cache-dir -r /app/requirements.txt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
# 复制自定义wp-config.php
|
| 46 |
+
COPY wp-config.php /usr/src/wordpress/
|
| 47 |
|
| 48 |
+
# 复制监控清理脚本
|
| 49 |
+
COPY monitor-cleanup.sh /scripts/
|
| 50 |
+
RUN chmod +x /scripts/monitor-cleanup.sh
|
|
|
|
| 51 |
|
| 52 |
+
# 复制启动脚本
|
| 53 |
+
COPY start-services.sh /scripts/
|
| 54 |
+
RUN chmod +x /scripts/start-services.sh
|
|
|
|
| 55 |
|
| 56 |
+
# 设置cron任务 - 每天凌晨2点执行清理
|
| 57 |
+
RUN echo "0 2 * * * /scripts/monitor-cleanup.sh >> /var/log/wordpress/cleanup.log 2>&1" | crontab -
|
| 58 |
|
| 59 |
+
# 暴露端口7860 (Hugging Face Spaces标准端口)
|
| 60 |
+
EXPOSE 7860
|
| 61 |
|
| 62 |
+
# 修改Apache配置以使用端口7860
|
| 63 |
+
RUN sed -i 's/Listen 80/Listen 7860/' /etc/apache2/ports.conf && \
|
| 64 |
+
sed -i 's/:80>/:7860>/' /etc/apache2/sites-available/000-default.conf
|
| 65 |
|
| 66 |
+
# 设置工作目录
|
| 67 |
+
WORKDIR /var/www/html
|
| 68 |
|
| 69 |
+
# 启动命令
|
| 70 |
+
CMD ["/scripts/start-services.sh"]
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The MIT License (MIT)
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2018 nezhar
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
app.py
CHANGED
|
@@ -1,38 +1,238 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
-
Hugging Face
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"""
|
| 6 |
|
| 7 |
import os
|
| 8 |
-
import subprocess
|
| 9 |
import time
|
| 10 |
-
import
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
try:
|
| 25 |
-
while True:
|
| 26 |
-
time.sleep(60)
|
| 27 |
-
# Optional: Add health check here
|
| 28 |
-
print("💓 WordPress container is running...")
|
| 29 |
-
except KeyboardInterrupt:
|
| 30 |
-
print("\n🛑 Shutting down WordPress...")
|
| 31 |
-
sys.exit(0)
|
| 32 |
-
else:
|
| 33 |
-
print("❌ This should run inside a Docker container")
|
| 34 |
-
print("Please deploy this to Hugging Face Spaces with Docker SDK")
|
| 35 |
-
sys.exit(1)
|
| 36 |
-
|
| 37 |
-
if __name__ == "__main__":
|
| 38 |
-
main()
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
Hugging Face Spaces WordPress 应用入口文件
|
| 4 |
+
|
| 5 |
+
这个文件是 Hugging Face Spaces 的标准入口点,
|
| 6 |
+
但实际的 WordPress 应用运行在 Docker 容器中。
|
| 7 |
+
|
| 8 |
+
该文件主要用于:
|
| 9 |
+
1. 提供应用信息
|
| 10 |
+
2. 健康检查
|
| 11 |
+
3. 重定向到 WordPress
|
| 12 |
"""
|
| 13 |
|
| 14 |
import os
|
|
|
|
| 15 |
import time
|
| 16 |
+
import subprocess
|
| 17 |
+
from flask import Flask, redirect, jsonify, render_template_string
|
| 18 |
+
|
| 19 |
+
app = Flask(__name__)
|
| 20 |
+
|
| 21 |
+
# 应用信息
|
| 22 |
+
APP_INFO = {
|
| 23 |
+
"name": "WordPress for Hugging Face Spaces",
|
| 24 |
+
"version": "1.0.0",
|
| 25 |
+
"description": "WordPress 单容器部署,使用 SQLite 数据库,包含自动清理功能",
|
| 26 |
+
"author": "Hugging Face Spaces WordPress Team",
|
| 27 |
+
"wordpress_url": "http://localhost:7860"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# HTML 模板
|
| 31 |
+
INDEX_TEMPLATE = """
|
| 32 |
+
<!DOCTYPE html>
|
| 33 |
+
<html lang="zh-CN">
|
| 34 |
+
<head>
|
| 35 |
+
<meta charset="UTF-8">
|
| 36 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 37 |
+
<title>{{ app_info.name }}</title>
|
| 38 |
+
<style>
|
| 39 |
+
body {
|
| 40 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
| 41 |
+
margin: 0;
|
| 42 |
+
padding: 20px;
|
| 43 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 44 |
+
min-height: 100vh;
|
| 45 |
+
display: flex;
|
| 46 |
+
align-items: center;
|
| 47 |
+
justify-content: center;
|
| 48 |
+
}
|
| 49 |
+
.container {
|
| 50 |
+
background: white;
|
| 51 |
+
border-radius: 10px;
|
| 52 |
+
padding: 40px;
|
| 53 |
+
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
| 54 |
+
text-align: center;
|
| 55 |
+
max-width: 600px;
|
| 56 |
+
}
|
| 57 |
+
h1 {
|
| 58 |
+
color: #333;
|
| 59 |
+
margin-bottom: 10px;
|
| 60 |
+
}
|
| 61 |
+
.version {
|
| 62 |
+
color: #666;
|
| 63 |
+
font-size: 14px;
|
| 64 |
+
margin-bottom: 20px;
|
| 65 |
+
}
|
| 66 |
+
.description {
|
| 67 |
+
color: #555;
|
| 68 |
+
line-height: 1.6;
|
| 69 |
+
margin-bottom: 30px;
|
| 70 |
+
}
|
| 71 |
+
.btn {
|
| 72 |
+
display: inline-block;
|
| 73 |
+
background: #667eea;
|
| 74 |
+
color: white;
|
| 75 |
+
padding: 12px 30px;
|
| 76 |
+
text-decoration: none;
|
| 77 |
+
border-radius: 5px;
|
| 78 |
+
font-weight: bold;
|
| 79 |
+
transition: background 0.3s;
|
| 80 |
+
margin: 10px;
|
| 81 |
+
}
|
| 82 |
+
.btn:hover {
|
| 83 |
+
background: #5a6fd8;
|
| 84 |
+
}
|
| 85 |
+
.status {
|
| 86 |
+
margin-top: 30px;
|
| 87 |
+
padding: 15px;
|
| 88 |
+
background: #f8f9fa;
|
| 89 |
+
border-radius: 5px;
|
| 90 |
+
border-left: 4px solid #28a745;
|
| 91 |
+
}
|
| 92 |
+
.features {
|
| 93 |
+
text-align: left;
|
| 94 |
+
margin: 20px 0;
|
| 95 |
+
}
|
| 96 |
+
.features ul {
|
| 97 |
+
list-style-type: none;
|
| 98 |
+
padding: 0;
|
| 99 |
+
}
|
| 100 |
+
.features li {
|
| 101 |
+
padding: 5px 0;
|
| 102 |
+
position: relative;
|
| 103 |
+
padding-left: 20px;
|
| 104 |
+
}
|
| 105 |
+
.features li:before {
|
| 106 |
+
content: "✓";
|
| 107 |
+
position: absolute;
|
| 108 |
+
left: 0;
|
| 109 |
+
color: #28a745;
|
| 110 |
+
font-weight: bold;
|
| 111 |
+
}
|
| 112 |
+
</style>
|
| 113 |
+
</head>
|
| 114 |
+
<body>
|
| 115 |
+
<div class="container">
|
| 116 |
+
<h1>{{ app_info.name }}</h1>
|
| 117 |
+
<div class="version">版本 {{ app_info.version }}</div>
|
| 118 |
+
<div class="description">{{ app_info.description }}</div>
|
| 119 |
+
|
| 120 |
+
<div class="features">
|
| 121 |
+
<h3>主要特性:</h3>
|
| 122 |
+
<ul>
|
| 123 |
+
<li>单容器 Docker 部署</li>
|
| 124 |
+
<li>SQLite 轻量级数据库</li>
|
| 125 |
+
<li>自动文件清理 (保留1年)</li>
|
| 126 |
+
<li>性能优化配置</li>
|
| 127 |
+
<li>安全防护机制</li>
|
| 128 |
+
<li>实时监控面板</li>
|
| 129 |
+
</ul>
|
| 130 |
+
</div>
|
| 131 |
+
|
| 132 |
+
<a href="/wordpress" class="btn">进入 WordPress</a>
|
| 133 |
+
<a href="/health" class="btn">系统状态</a>
|
| 134 |
+
|
| 135 |
+
<div class="status">
|
| 136 |
+
<strong>状态:</strong> WordPress 正在运行中...<br>
|
| 137 |
+
<small>如果这是首次访问,WordPress 可能需要几分钟来初始化</small>
|
| 138 |
+
</div>
|
| 139 |
+
</div>
|
| 140 |
+
</body>
|
| 141 |
+
</html>
|
| 142 |
+
"""
|
| 143 |
+
|
| 144 |
+
@app.route('/')
|
| 145 |
+
def index():
|
| 146 |
+
"""主页 - 显示应用信息"""
|
| 147 |
+
return render_template_string(INDEX_TEMPLATE, app_info=APP_INFO)
|
| 148 |
+
|
| 149 |
+
@app.route('/wordpress')
|
| 150 |
+
def wordpress():
|
| 151 |
+
"""重定向到 WordPress"""
|
| 152 |
+
return redirect('http://localhost:7860', code=302)
|
| 153 |
+
|
| 154 |
+
@app.route('/health')
|
| 155 |
+
def health():
|
| 156 |
+
"""健康检查端点"""
|
| 157 |
+
try:
|
| 158 |
+
# 检查 WordPress 容器是否运行
|
| 159 |
+
result = subprocess.run(
|
| 160 |
+
['curl', '-f', '-s', 'http://localhost:7860'],
|
| 161 |
+
capture_output=True,
|
| 162 |
+
timeout=5
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
wordpress_status = "running" if result.returncode == 0 else "stopped"
|
| 166 |
+
|
| 167 |
+
# 获取系统信息
|
| 168 |
+
disk_usage = subprocess.run(
|
| 169 |
+
['df', '-h', '/'],
|
| 170 |
+
capture_output=True,
|
| 171 |
+
text=True
|
| 172 |
+
).stdout.split('\n')[1].split()[4] if subprocess.run(['df', '-h', '/'], capture_output=True).returncode == 0 else "unknown"
|
| 173 |
+
|
| 174 |
+
return jsonify({
|
| 175 |
+
"status": "healthy",
|
| 176 |
+
"timestamp": time.time(),
|
| 177 |
+
"services": {
|
| 178 |
+
"wordpress": wordpress_status,
|
| 179 |
+
"database": "sqlite",
|
| 180 |
+
"cleanup": "enabled"
|
| 181 |
+
},
|
| 182 |
+
"system": {
|
| 183 |
+
"disk_usage": disk_usage,
|
| 184 |
+
"uptime": time.time()
|
| 185 |
+
},
|
| 186 |
+
"app_info": APP_INFO
|
| 187 |
+
})
|
| 188 |
+
except Exception as e:
|
| 189 |
+
return jsonify({
|
| 190 |
+
"status": "error",
|
| 191 |
+
"error": str(e),
|
| 192 |
+
"timestamp": time.time()
|
| 193 |
+
}), 500
|
| 194 |
+
|
| 195 |
+
@app.route('/api/info')
|
| 196 |
+
def api_info():
|
| 197 |
+
"""API 信息端点"""
|
| 198 |
+
return jsonify(APP_INFO)
|
| 199 |
+
|
| 200 |
+
@app.route('/api/cleanup/status')
|
| 201 |
+
def cleanup_status():
|
| 202 |
+
"""清理状态 API"""
|
| 203 |
+
try:
|
| 204 |
+
# 读取清理日志
|
| 205 |
+
log_file = '/var/log/wordpress/cleanup.log'
|
| 206 |
+
if os.path.exists(log_file):
|
| 207 |
+
with open(log_file, 'r') as f:
|
| 208 |
+
lines = f.readlines()
|
| 209 |
+
recent_logs = lines[-10:] if len(lines) > 10 else lines
|
| 210 |
+
else:
|
| 211 |
+
recent_logs = ["暂无清理记录"]
|
| 212 |
+
|
| 213 |
+
return jsonify({
|
| 214 |
+
"status": "success",
|
| 215 |
+
"cleanup_enabled": True,
|
| 216 |
+
"retention_days": 365,
|
| 217 |
+
"recent_logs": [line.strip() for line in recent_logs],
|
| 218 |
+
"log_file": log_file
|
| 219 |
+
})
|
| 220 |
+
except Exception as e:
|
| 221 |
+
return jsonify({
|
| 222 |
+
"status": "error",
|
| 223 |
+
"error": str(e)
|
| 224 |
+
}), 500
|
| 225 |
+
|
| 226 |
+
if __name__ == '__main__':
|
| 227 |
+
# 在 Hugging Face Spaces 中,应用应该监听端口 7860
|
| 228 |
+
port = int(os.environ.get('PORT', 7860))
|
| 229 |
+
|
| 230 |
+
print(f"启动 {APP_INFO['name']} v{APP_INFO['version']}")
|
| 231 |
+
print(f"监听端口: {port}")
|
| 232 |
+
print(f"WordPress URL: {APP_INFO['wordpress_url']}")
|
| 233 |
|
| 234 |
+
app.run(
|
| 235 |
+
host='0.0.0.0',
|
| 236 |
+
port=port,
|
| 237 |
+
debug=False
|
| 238 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,6 +1,26 @@
|
|
| 1 |
-
#
|
| 2 |
-
# This WordPress deployment primarily uses Docker,
|
| 3 |
-
# but this file is included for HF Space compatibility
|
| 4 |
|
| 5 |
-
#
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python dependencies for Hugging Face Spaces WordPress app
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
# Web framework
|
| 4 |
+
Flask==2.3.3
|
| 5 |
+
Werkzeug==2.3.7
|
| 6 |
+
|
| 7 |
+
# HTTP requests
|
| 8 |
+
requests==2.31.0
|
| 9 |
+
|
| 10 |
+
# System utilities
|
| 11 |
+
psutil==5.9.5
|
| 12 |
+
|
| 13 |
+
# JSON handling
|
| 14 |
+
jsonschema==4.19.1
|
| 15 |
+
|
| 16 |
+
# Date and time utilities
|
| 17 |
+
python-dateutil==2.8.2
|
| 18 |
+
|
| 19 |
+
# Environment variables
|
| 20 |
+
python-dotenv==1.0.0
|
| 21 |
+
|
| 22 |
+
# Logging
|
| 23 |
+
coloredlogs==15.0.1
|
| 24 |
+
|
| 25 |
+
# Security
|
| 26 |
+
cryptography==41.0.4
|
start-services.sh
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Hugging Face Spaces WordPress 服务启动脚本
|
| 4 |
+
# 管理 WordPress、Python 应用和清理服务
|
| 5 |
+
|
| 6 |
+
set -e
|
| 7 |
+
|
| 8 |
+
echo "=== 启动 WordPress for Hugging Face Spaces ==="
|
| 9 |
+
|
| 10 |
+
# 创建必要的目录
|
| 11 |
+
echo "创建必要的目录..."
|
| 12 |
+
mkdir -p /var/www/html/wp-content/database
|
| 13 |
+
mkdir -p /var/www/html/wp-content/uploads
|
| 14 |
+
mkdir -p /var/www/html/wp-content/cache
|
| 15 |
+
mkdir -p /var/log/wordpress
|
| 16 |
+
mkdir -p /var/log/apache2
|
| 17 |
+
|
| 18 |
+
# 设置权限
|
| 19 |
+
echo "设置文件权限..."
|
| 20 |
+
chown -R www-data:www-data /var/www/html
|
| 21 |
+
chmod -R 755 /var/www/html
|
| 22 |
+
chown -R www-data:www-data /var/www/html/wp-content/database
|
| 23 |
+
chmod -R 755 /var/www/html/wp-content/database
|
| 24 |
+
|
| 25 |
+
# 检查并安装 SQLite 插件
|
| 26 |
+
echo "检查 SQLite 插件..."
|
| 27 |
+
if [ ! -d "/var/www/html/wp-content/plugins/sqlite-database-integration" ]; then
|
| 28 |
+
echo "安装 SQLite 数据库集成插件..."
|
| 29 |
+
cd /tmp
|
| 30 |
+
wget -q https://downloads.wordpress.org/plugin/sqlite-database-integration.2.1.5.zip
|
| 31 |
+
unzip -q sqlite-database-integration.2.1.5.zip
|
| 32 |
+
mv sqlite-database-integration /var/www/html/wp-content/plugins/
|
| 33 |
+
chown -R www-data:www-data /var/www/html/wp-content/plugins/sqlite-database-integration
|
| 34 |
+
rm sqlite-database-integration.2.1.5.zip
|
| 35 |
+
echo "SQLite 插件安装完成"
|
| 36 |
+
else
|
| 37 |
+
echo "SQLite 插件已存在"
|
| 38 |
+
fi
|
| 39 |
+
|
| 40 |
+
# 复制 wp-config.php 如果不存在
|
| 41 |
+
if [ ! -f "/var/www/html/wp-config.php" ]; then
|
| 42 |
+
echo "复制 wp-config.php..."
|
| 43 |
+
cp /usr/src/wordpress/wp-config.php /var/www/html/
|
| 44 |
+
chown www-data:www-data /var/www/html/wp-config.php
|
| 45 |
+
fi
|
| 46 |
+
|
| 47 |
+
# 启动 cron 服务
|
| 48 |
+
echo "启动 cron 服务..."
|
| 49 |
+
service cron start
|
| 50 |
+
|
| 51 |
+
# 启动 Apache 在后台
|
| 52 |
+
echo "启动 Apache 服务..."
|
| 53 |
+
apache2ctl start
|
| 54 |
+
|
| 55 |
+
# 等待 Apache 启动
|
| 56 |
+
sleep 3
|
| 57 |
+
|
| 58 |
+
# 检查 Apache 状态
|
| 59 |
+
if pgrep apache2 > /dev/null; then
|
| 60 |
+
echo "Apache 启动成功"
|
| 61 |
+
else
|
| 62 |
+
echo "Apache 启动失败"
|
| 63 |
+
exit 1
|
| 64 |
+
fi
|
| 65 |
+
|
| 66 |
+
# 启动 Python 应用
|
| 67 |
+
echo "启动 Python 应用..."
|
| 68 |
+
cd /app
|
| 69 |
+
export FLASK_ENV=production
|
| 70 |
+
export FLASK_APP=app.py
|
| 71 |
+
|
| 72 |
+
# 在后台启动 Python 应用
|
| 73 |
+
python3 app.py &
|
| 74 |
+
PYTHON_PID=$!
|
| 75 |
+
|
| 76 |
+
echo "Python 应用启动,PID: $PYTHON_PID"
|
| 77 |
+
|
| 78 |
+
# 等待服务启动
|
| 79 |
+
sleep 5
|
| 80 |
+
|
| 81 |
+
# 健康检查
|
| 82 |
+
echo "执行健康检查..."
|
| 83 |
+
for i in {1..10}; do
|
| 84 |
+
if curl -f -s http://localhost:7860/health > /dev/null; then
|
| 85 |
+
echo "健康检查通过"
|
| 86 |
+
break
|
| 87 |
+
else
|
| 88 |
+
echo "等待服务启动... ($i/10)"
|
| 89 |
+
sleep 2
|
| 90 |
+
fi
|
| 91 |
+
|
| 92 |
+
if [ $i -eq 10 ]; then
|
| 93 |
+
echo "健康检查失败,服务可能未正常启动"
|
| 94 |
+
fi
|
| 95 |
+
done
|
| 96 |
+
|
| 97 |
+
# 显示服务状态
|
| 98 |
+
echo "=== 服务状态 ==="
|
| 99 |
+
echo "Apache: $(pgrep apache2 > /dev/null && echo '运行中' || echo '已停止')"
|
| 100 |
+
echo "Python App: $(kill -0 $PYTHON_PID 2>/dev/null && echo '运行中' || echo '已停止')"
|
| 101 |
+
echo "Cron: $(pgrep cron > /dev/null && echo '运行中' || echo '已停止')"
|
| 102 |
+
|
| 103 |
+
# 显示访问信息
|
| 104 |
+
echo "=== 访问信息 ==="
|
| 105 |
+
echo "WordPress: http://localhost:7860/wordpress"
|
| 106 |
+
echo "应用首页: http://localhost:7860/"
|
| 107 |
+
echo "健康检查: http://localhost:7860/health"
|
| 108 |
+
echo "清理状态: http://localhost:7860/api/cleanup/status"
|
| 109 |
+
|
| 110 |
+
echo "=== 启动完成 ==="
|
| 111 |
+
|
| 112 |
+
# 保持容器运行
|
| 113 |
+
echo "保持服务运行..."
|
| 114 |
+
while true; do
|
| 115 |
+
# 检查关键服务是否还在运行
|
| 116 |
+
if ! pgrep apache2 > /dev/null; then
|
| 117 |
+
echo "Apache 服务已停止,重新启动..."
|
| 118 |
+
apache2ctl start
|
| 119 |
+
fi
|
| 120 |
+
|
| 121 |
+
if ! kill -0 $PYTHON_PID 2>/dev/null; then
|
| 122 |
+
echo "Python 应用已停止,重新启动..."
|
| 123 |
+
cd /app
|
| 124 |
+
python3 app.py &
|
| 125 |
+
PYTHON_PID=$!
|
| 126 |
+
fi
|
| 127 |
+
|
| 128 |
+
if ! pgrep cron > /dev/null; then
|
| 129 |
+
echo "Cron 服务已停止,重新启动..."
|
| 130 |
+
service cron start
|
| 131 |
+
fi
|
| 132 |
+
|
| 133 |
+
sleep 30
|
| 134 |
+
done
|