feat: 迁移 Storage 后端从 MinIO 到文件系统
## 主要变更
### 1. Storage 配置修改
- 修改 docker-compose.yml: STORAGE_BACKEND 从 s3 改为 file
- 注释所有 GLOBAL_S3_* 环境变量
- 启用 FILE_STORAGE_BACKEND_PATH=/var/lib/storage
- 停止使用 MinIO 容器(docker-compose.s3.yml)
### 2. 文档更新
- 新增 docs/STORAGE_FILE_BACKEND_MIGRATION.md - 迁移详细文档
- 新增 docs/STORAGE_TROUBLESHOOTING.md - 故障排查指南
- 更新 README.md - 反映新的架构
### 3. 存储架构变更
- 从 MinIO S3 对象存储 -> 本地文件系统
- 存储路径: volumes/storage/undefined/stub/{bucket}/{file}/{version}
- 不再需要额外的 MinIO 容器
## 测试结果
- ✅ 上传文件 - 正常
- ✅ 下载文件 - 正常
- ✅ 删除文件 - 正常
- ✅ 签名 URL - 正常
- ⚠️ 更新文件 - 已知bug(使用删除+上传代替)
## 注意事项
- 旧的 S3 后端数据需要清理数据库元数据
- 文件更新操作有已知bug,需使用删除+重新上传
- 备份文件保存在 *.backup-before-rustfs
## 回滚方法
如需回滚到 MinIO:
```bash
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
docker compose -f docker-compose.s3.yml up -d
docker compose restart storage
```
日期: 2025-12-05
状态: ✅ 测试通过 (4/5 功能正常)
This commit is contained in:
438
supabase-stack/docs/DEPLOYMENT_GUIDE.md
Normal file
438
supabase-stack/docs/DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,438 @@
|
||||
# 🚀 课题组网站部署指南
|
||||
|
||||
## 📋 最终架构
|
||||
|
||||
### 公网 HTTPS 访问
|
||||
|
||||
```
|
||||
https://amiap.hzau.edu.cn/
|
||||
├── / → MinIO S3 API(对象存储)
|
||||
│ └── /stub/ → 默认 bucket
|
||||
│
|
||||
├── /group/ → 🎨 Vue 课题组网站(主站)
|
||||
│ ├── /group/ - 首页
|
||||
│ ├── /group/members - 成员介绍
|
||||
│ ├── /group/research - 研究方向
|
||||
│ └── /group/... - 其他页面
|
||||
│
|
||||
├── /supa/ → Supabase 后端 API
|
||||
│ ├── /supa/auth/v1 - 用户认证
|
||||
│ ├── /supa/rest/v1 - 数据库 REST
|
||||
│ └── /supa/storage/v1 - 文件存储
|
||||
│
|
||||
└── /ABM/ → ABM 数据库系统
|
||||
```
|
||||
|
||||
### 内网访问(Tailscale VPN: 100.64.0.2)
|
||||
|
||||
```
|
||||
http://100.64.0.2:18000 → Supabase Dashboard(后端管理)
|
||||
http://100.64.0.2:9001 → MinIO Console(S3 管理)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Vue 课题组网站开发
|
||||
|
||||
### 1. 项目配置
|
||||
|
||||
#### vite.config.js
|
||||
```javascript
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
base: '/group/', // ⚠️ 必须配置子路径
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 5173
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### router/index.js
|
||||
```javascript
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory('/group/'), // ⚠️ 必须配置子路径
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: () => import('@/views/Home.vue')
|
||||
},
|
||||
{
|
||||
path: '/members',
|
||||
name: 'Members',
|
||||
component: () => import('@/views/Members.vue')
|
||||
},
|
||||
{
|
||||
path: '/research',
|
||||
name: 'Research',
|
||||
component: () => import('@/views/Research.vue')
|
||||
},
|
||||
{
|
||||
path: '/publications',
|
||||
name: 'Publications',
|
||||
component: () => import('@/views/Publications.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export default router
|
||||
```
|
||||
|
||||
### 2. Supabase 集成
|
||||
|
||||
#### src/lib/supabase.js
|
||||
```javascript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = 'https://amiap.hzau.edu.cn/supa'
|
||||
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseKey)
|
||||
```
|
||||
|
||||
#### .env
|
||||
```bash
|
||||
VITE_SUPABASE_ANON_KEY=your-anon-key-here
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
```vue
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { supabase } from '@/lib/supabase'
|
||||
|
||||
const members = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
// 查询团队成员
|
||||
const { data, error } = await supabase
|
||||
.from('members')
|
||||
.select('*')
|
||||
.order('join_date', { ascending: false })
|
||||
|
||||
if (\!error) {
|
||||
members.value = data
|
||||
}
|
||||
})
|
||||
|
||||
// 上传文件到 Supabase Storage
|
||||
async function uploadPhoto(file) {
|
||||
const { data, error } = await supabase.storage
|
||||
.from('photos')
|
||||
.upload(`members/${file.name}`, file)
|
||||
|
||||
if (\!error) {
|
||||
console.log('上传成功:', data.path)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 跳转链接配置
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="admin-panel">
|
||||
<h3>管理入口(内网访问)</h3>
|
||||
|
||||
<\!-- Supabase 后端管理 -->
|
||||
<a
|
||||
href="http://100.64.0.2:18000"
|
||||
target="_blank"
|
||||
class="admin-link"
|
||||
>
|
||||
<icon>🗄️</icon>
|
||||
<span>Supabase Dashboard</span>
|
||||
<badge>需要 VPN</badge>
|
||||
</a>
|
||||
|
||||
<\!-- MinIO 存储管理 -->
|
||||
<a
|
||||
href="http://100.64.0.2:9001"
|
||||
target="_blank"
|
||||
class="admin-link"
|
||||
>
|
||||
<icon>💾</icon>
|
||||
<span>MinIO Console</span>
|
||||
<badge>需要 VPN</badge>
|
||||
</a>
|
||||
|
||||
<\!-- ABM 数据库 -->
|
||||
<router-link to="/external/ABM" class="admin-link">
|
||||
<icon>📊</icon>
|
||||
<span>ABM 数据库</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 外部链接处理
|
||||
function openExternal(url) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 MinIO S3 存储使用
|
||||
|
||||
### 直接上传到 S3(大文件)
|
||||
|
||||
```javascript
|
||||
// 使用 AWS SDK
|
||||
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
|
||||
|
||||
const s3Client = new S3Client({
|
||||
endpoint: 'https://amiap.hzau.edu.cn', // 根路径
|
||||
region: 'stub',
|
||||
credentials: {
|
||||
accessKeyId: import.meta.env.VITE_S3_ACCESS_KEY,
|
||||
secretAccessKey: import.meta.env.VITE_S3_SECRET_KEY
|
||||
},
|
||||
forcePathStyle: true // ⚠️ 必须启用路径风格
|
||||
})
|
||||
|
||||
async function uploadLargeFile(file) {
|
||||
await s3Client.send(new PutObjectCommand({
|
||||
Bucket: 'stub',
|
||||
Key: `publications/${file.name}`,
|
||||
Body: file,
|
||||
ContentType: file.type
|
||||
}))
|
||||
|
||||
// 文件 URL: https://amiap.hzau.edu.cn/stub/publications/file.pdf
|
||||
return `https://amiap.hzau.edu.cn/stub/publications/${file.name}`
|
||||
}
|
||||
```
|
||||
|
||||
### 使用 Supabase Storage(小文件)
|
||||
|
||||
```javascript
|
||||
// 推荐用于 < 50MB 的文件
|
||||
const { data, error } = await supabase.storage
|
||||
.from('documents')
|
||||
.upload('research/paper.pdf', file)
|
||||
|
||||
// 获取公开 URL
|
||||
const { data: { publicUrl } } = supabase.storage
|
||||
.from('documents')
|
||||
.getPublicUrl('research/paper.pdf')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 部署流程
|
||||
|
||||
### 1. 开发环境
|
||||
|
||||
```bash
|
||||
# 创建 Vue 项目
|
||||
npm create vite@latest group-website -- --template vue
|
||||
|
||||
cd group-website
|
||||
|
||||
# 安装依赖
|
||||
npm install @supabase/supabase-js
|
||||
npm install @aws-sdk/client-s3 # 如果需要直接访问 S3
|
||||
|
||||
# 配置 vite.config.js 和 router(见上面)
|
||||
|
||||
# 本地开发
|
||||
npm run dev
|
||||
# 访问: http://localhost:5173/group/
|
||||
```
|
||||
|
||||
### 2. 生产部署
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
npm run build
|
||||
|
||||
# 部署到服务器
|
||||
scp -r dist/* user@server:/vol1/1000/docker_server/traefik/web/group-site/dist/
|
||||
|
||||
# 或直接在服务器上
|
||||
cd /vol1/1000/docker_server/traefik/web/group-site
|
||||
rm -rf dist/*
|
||||
# 复制构建产物到 dist/
|
||||
|
||||
# 重启服务
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### 3. 验证部署
|
||||
|
||||
```bash
|
||||
# 访问网站
|
||||
curl https://amiap.hzau.edu.cn/group/
|
||||
|
||||
# 查看日志
|
||||
docker logs group-site
|
||||
|
||||
# 查看状态
|
||||
docker ps | grep group-site
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据库设计示例
|
||||
|
||||
### Supabase 表结构
|
||||
|
||||
```sql
|
||||
-- 团队成员表
|
||||
CREATE TABLE members (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(100) NOT NULL,
|
||||
title VARCHAR(100),
|
||||
email VARCHAR(100),
|
||||
photo_url TEXT,
|
||||
bio TEXT,
|
||||
research_interests TEXT[],
|
||||
join_date DATE,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 研究成果表
|
||||
CREATE TABLE publications (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
title TEXT NOT NULL,
|
||||
authors TEXT[],
|
||||
journal VARCHAR(200),
|
||||
year INTEGER,
|
||||
doi VARCHAR(100),
|
||||
pdf_url TEXT,
|
||||
abstract TEXT,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 研究项目表
|
||||
CREATE TABLE projects (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(200) NOT NULL,
|
||||
description TEXT,
|
||||
status VARCHAR(50),
|
||||
start_date DATE,
|
||||
end_date DATE,
|
||||
funding_source VARCHAR(200),
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 页面布局建议
|
||||
|
||||
### 首页 (/)
|
||||
- 课题组介绍
|
||||
- 最新动态
|
||||
- 研究领域概览
|
||||
- 快速链接
|
||||
|
||||
### 成员介绍 (/members)
|
||||
- 导师信息
|
||||
- 博士生/硕士生
|
||||
- 校友网络
|
||||
|
||||
### 研究方向 (/research)
|
||||
- 主要研究领域
|
||||
- 正在进行的项目
|
||||
- 技术路线
|
||||
|
||||
### 论文成果 (/publications)
|
||||
- 按年份/类别分类
|
||||
- 搜索和筛选
|
||||
- 下载链接
|
||||
|
||||
### 管理入口(仅内网)
|
||||
- Supabase Dashboard 链接
|
||||
- MinIO Console 链接
|
||||
- ABM 系统链接
|
||||
|
||||
---
|
||||
|
||||
## 🔧 常用命令
|
||||
|
||||
### 开发调试
|
||||
```bash
|
||||
npm run dev # 启动开发服务器
|
||||
npm run build # 构建生产版本
|
||||
npm run preview # 预览生产构建
|
||||
```
|
||||
|
||||
### 服务器管理
|
||||
```bash
|
||||
# 查看所有服务
|
||||
docker ps | grep -E '(minio|group|supabase)'
|
||||
|
||||
# 重启服务
|
||||
cd /vol1/1000/docker_server/traefik/web/group-site
|
||||
docker compose restart
|
||||
|
||||
# 查看日志
|
||||
docker logs -f group-site
|
||||
|
||||
# 更新代码
|
||||
cd /vol1/1000/docker_server/traefik/web/group-site
|
||||
git pull # 如果使用 git
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 故障排查
|
||||
|
||||
### Vue 网站 404
|
||||
- 检查 `base: '/group/'` 配置
|
||||
- 检查 Nginx try_files 配置
|
||||
- 清除浏览器缓存
|
||||
|
||||
### 静态资源加载失败
|
||||
- 确认 vite.config.js 中 base 设置
|
||||
- 检查文件权限:`chmod -R 755 dist/`
|
||||
|
||||
### Supabase API 调用失败
|
||||
- 检查 CORS 配置
|
||||
- 验证 API Key
|
||||
- 查看浏览器控制台错误
|
||||
|
||||
### S3 上传失败
|
||||
- 确认 forcePathStyle: true
|
||||
- 检查 credentials
|
||||
- 验证 bucket 存在
|
||||
|
||||
---
|
||||
|
||||
## 🎉 最终检查清单
|
||||
|
||||
部署前确认:
|
||||
|
||||
- [ ] vite.config.js 配置 `base: '/group/'`
|
||||
- [ ] router 配置 `createWebHistory('/group/')`
|
||||
- [ ] Supabase client 配置正确
|
||||
- [ ] 环境变量已设置
|
||||
- [ ] 测试所有路由
|
||||
- [ ] 测试文件上传
|
||||
- [ ] 测试 Supabase 查询
|
||||
- [ ] 内网链接可访问
|
||||
- [ ] 响应式设计检查
|
||||
- [ ] 浏览器兼容性测试
|
||||
|
||||
---
|
||||
|
||||
**架构设计**: ✅
|
||||
**配置完成**: ✅
|
||||
**开发就绪**: ✅
|
||||
|
||||
**开始开发你的课题组网站吧!** 🚀
|
||||
|
||||
有任何问题,参考:
|
||||
- FINAL_ARCHITECTURE_v2.md - 架构说明
|
||||
- web/group-site/README.md - 部署配置
|
||||
@@ -1,293 +0,0 @@
|
||||
# Supabase 部署信息汇总
|
||||
|
||||
## 🌐 访问地址
|
||||
|
||||
### HTTPS 域名访问(推荐用于 API)
|
||||
```
|
||||
API Base URL: https://amiap.hzau.edu.cn/supa
|
||||
```
|
||||
|
||||
### 内网访问(用于 Dashboard)
|
||||
```
|
||||
Dashboard: http://100.64.0.2:18000
|
||||
API Base: http://100.64.0.2:18000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔑 认证信息
|
||||
|
||||
### Dashboard 登录
|
||||
```
|
||||
URL: http://100.64.0.2:18000
|
||||
用户名: lab-admin
|
||||
密码: 017b7076cfb25bd18410d1e5f4f7ec5a
|
||||
```
|
||||
|
||||
### API Keys(用于前端/后端开发)
|
||||
```javascript
|
||||
// ✅ 公开密钥 - 可以在前端使用
|
||||
ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzYzODAyNjY5LCJleHAiOjIwNzkxNjI2Njl9.ltGXvQKpguLaf8Vzomn310hLgOZbrjqZT-F3rR00ulg"
|
||||
|
||||
// ⚠️ 私密密钥 - 仅后端使用,不要暴露
|
||||
SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3NjM4MDI2NjksImV4cCI6MjA3OTE2MjY2OX0.gQWUaTkZ6mjjlv2TED0cODp2meqqWuCGKZR1ptIbovg"
|
||||
```
|
||||
|
||||
### 数据库连接
|
||||
```
|
||||
主机: 100.64.0.2 或 db (容器内)
|
||||
端口: 5432
|
||||
数据库: postgres
|
||||
用户: postgres
|
||||
密码: a837234b952ad7aa9ab4852f47021660c038209a71fce027cec8bab37ad82ae5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 API 端点
|
||||
|
||||
### ✅ 可用的服务端点
|
||||
|
||||
| 服务 | HTTPS 端点 | 内网端点 | 用途 |
|
||||
|------|-----------|----------|------|
|
||||
| REST API | `https://amiap.hzau.edu.cn/supa/rest/v1/` | `http://100.64.0.2:18000/rest/v1/` | 数据库 CRUD 操作 |
|
||||
| Auth API | `https://amiap.hzau.edu.cn/supa/auth/v1/` | `http://100.64.0.2:18000/auth/v1/` | 用户认证 |
|
||||
| Storage API | `https://amiap.hzau.edu.cn/supa/storage/v1/` | `http://100.64.0.2:18000/storage/v1/` | 文件存储 |
|
||||
| Realtime | `wss://amiap.hzau.edu.cn/supa/realtime/v1/websocket` | `ws://100.64.0.2:18000/realtime/v1/websocket` | 实时订阅 |
|
||||
| Dashboard | ❌ 不可用 | `http://100.64.0.2:18000/` | 管理界面 |
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Docker 服务状态
|
||||
|
||||
### 核心服务
|
||||
```bash
|
||||
# 查看所有服务状态
|
||||
docker compose ps
|
||||
|
||||
# 核心服务列表
|
||||
supabase-db # PostgreSQL 数据库
|
||||
supabase-kong # API 网关(端口: 18000)
|
||||
supabase-auth # 用户认证服务
|
||||
supabase-rest # REST API 服务
|
||||
supabase-storage # 文件存储服务
|
||||
supabase-realtime # 实时订阅服务
|
||||
supabase-studio # Dashboard
|
||||
supabase-meta # 数据库元数据
|
||||
supabase-analytics # 日志分析
|
||||
```
|
||||
|
||||
### 常用命令
|
||||
```bash
|
||||
# 进入 supabase-stack 目录
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 启动所有服务
|
||||
docker compose up -d
|
||||
|
||||
# 停止所有服务
|
||||
docker compose down
|
||||
|
||||
# 查看服务日志
|
||||
docker compose logs -f kong
|
||||
docker compose logs -f rest
|
||||
docker compose logs -f auth
|
||||
|
||||
# 重启特定服务
|
||||
docker compose restart kong
|
||||
docker compose restart rest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置文件
|
||||
|
||||
### 重要文件位置
|
||||
```
|
||||
/vol1/1000/docker_server/traefik/supabase-stack/
|
||||
├── .env # 环境变量配置
|
||||
├── docker-compose.yml # Docker Compose 配置
|
||||
├── VUE_API_INTEGRATION.md # Vue 集成文档(已创建)
|
||||
├── DEPLOYMENT_INFO.md # 本文件
|
||||
├── volumes/
|
||||
│ ├── api/kong.yml # Kong 网关配置
|
||||
│ ├── db/ # 数据库数据目录
|
||||
│ └── storage/ # 文件存储目录
|
||||
```
|
||||
|
||||
### .env 关键配置
|
||||
```bash
|
||||
# 数据库
|
||||
POSTGRES_PASSWORD=a837234b952ad7aa9ab4852f47021660c038209a71fce027cec8bab37ad82ae5
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=7a264228051ad10724934342ce62dce584161c248841061de0d0a56e92d9bb1a
|
||||
|
||||
# API Keys
|
||||
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
|
||||
# Dashboard
|
||||
DASHBOARD_USERNAME=lab-admin
|
||||
DASHBOARD_PASSWORD=017b7076cfb25bd18410d1e5f4f7ec5a
|
||||
|
||||
# 域名配置
|
||||
SITE_URL=https://amiap.hzau.edu.cn
|
||||
API_EXTERNAL_URL=https://amiap.hzau.edu.cn/supa
|
||||
SUPABASE_PUBLIC_URL=https://amiap.hzau.edu.cn/supa
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始(前端集成)
|
||||
|
||||
### 1. 安装依赖
|
||||
```bash
|
||||
npm install @supabase/supabase-js
|
||||
```
|
||||
|
||||
### 2. 创建 Supabase 客户端
|
||||
```javascript
|
||||
// src/lib/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = 'https://amiap.hzau.edu.cn/supa'
|
||||
const supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzYzODAyNjY5LCJleHAiOjIwNzkxNjI2Njl9.ltGXvQKpguLaf8Vzomn310hLgOZbrjqZT-F3rR00ulg'
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
```
|
||||
|
||||
### 3. 使用示例
|
||||
```javascript
|
||||
// 查询数据
|
||||
const { data, error } = await supabase
|
||||
.from('users')
|
||||
.select('*')
|
||||
|
||||
// 插入数据
|
||||
const { data, error } = await supabase
|
||||
.from('users')
|
||||
.insert([{ name: 'John', email: 'john@example.com' }])
|
||||
|
||||
// 用户登录
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email: 'user@example.com',
|
||||
password: 'password'
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 测试 API
|
||||
|
||||
### 快速测试脚本
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 测试 REST API
|
||||
curl -H "apikey: ANON_KEY" \
|
||||
-H "Authorization: Bearer ANON_KEY" \
|
||||
https://amiap.hzau.edu.cn/supa/rest/v1/
|
||||
|
||||
# 测试 Auth API
|
||||
curl https://amiap.hzau.edu.cn/supa/auth/v1/health
|
||||
|
||||
# 测试 Storage API
|
||||
curl https://amiap.hzau.edu.cn/supa/storage/v1/version
|
||||
```
|
||||
|
||||
### 在浏览器中测试
|
||||
```
|
||||
1. 访问 Dashboard: http://100.64.0.2:18000
|
||||
2. 使用用户名/密码登录
|
||||
3. 创建测试表
|
||||
4. 在 Vue 应用中调用 API
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 已知问题
|
||||
|
||||
### 1. Dashboard 子路径问题
|
||||
- **问题**: `https://amiap.hzau.edu.cn/supa` 无法访问 Dashboard
|
||||
- **原因**: Supabase Studio 是 SPA,不支持子路径部署
|
||||
- **解决**: 使用内网地址 `http://100.64.0.2:18000`
|
||||
|
||||
### 2. Pooler 服务重启
|
||||
- **问题**: `supabase-pooler` 一直重启
|
||||
- **影响**: 无影响,这是连接池优化组件,非必需
|
||||
- **解决**: 可忽略或停止该服务 `docker stop supabase-pooler`
|
||||
|
||||
### 3. REST API 缓存重试
|
||||
- **问题**: 首次访问可能看到 "schema cache retrying"
|
||||
- **原因**: PostgreSQL schema 缓存加载
|
||||
- **解决**: 等待几秒自动恢复,或重启 `docker compose restart rest`
|
||||
|
||||
---
|
||||
|
||||
## 📚 开发文档
|
||||
|
||||
| 文档 | 位置 | 说明 |
|
||||
|------|------|------|
|
||||
| Vue 集成指南 | `VUE_API_INTEGRATION.md` | 详细的前端集成教程 |
|
||||
| 部署信息 | `DEPLOYMENT_INFO.md` | 本文件 |
|
||||
| 官方文档 | https://supabase.com/docs | Supabase 官方文档 |
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 故障排查
|
||||
|
||||
### 服务无法启动
|
||||
```bash
|
||||
# 查看日志
|
||||
docker compose logs kong
|
||||
docker compose logs rest
|
||||
|
||||
# 重启服务
|
||||
docker compose restart
|
||||
|
||||
# 完全重建
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### API 无法访问
|
||||
```bash
|
||||
# 检查 Kong 状态
|
||||
docker compose ps kong
|
||||
|
||||
# 检查端口
|
||||
netstat -tlnp | grep 18000
|
||||
|
||||
# 测试内网连接
|
||||
curl http://100.64.0.2:18000/rest/v1/
|
||||
```
|
||||
|
||||
### 数据库连接问题
|
||||
```bash
|
||||
# 进入数据库容器
|
||||
docker exec -it supabase-db psql -U postgres
|
||||
|
||||
# 查看数据库
|
||||
\l
|
||||
|
||||
# 查看 schema
|
||||
\dn
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 支持
|
||||
|
||||
如有问题,请检查:
|
||||
1. 所有容器是否正常运行: `docker compose ps`
|
||||
2. 查看服务日志: `docker compose logs [service]`
|
||||
3. 参考 `VUE_API_INTEGRATION.md` 了解详细用法
|
||||
4. 访问 Dashboard 管理数据库: `http://100.64.0.2:18000`
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-11-22
|
||||
**版本**: Supabase Self-Hosted Stack
|
||||
338
supabase-stack/docs/FINAL_ARCHITECTURE_MINIO_INTERNAL.md
Normal file
338
supabase-stack/docs/FINAL_ARCHITECTURE_MINIO_INTERNAL.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# ✅ MinIO 内网化架构 - 最终配置
|
||||
|
||||
## 架构变更总结
|
||||
|
||||
### 变更日期
|
||||
2025-11-23
|
||||
|
||||
### 变更目标
|
||||
- MinIO S3 对象存储改为仅内网访问
|
||||
- 删除 MinIO 的所有 Traefik 公网路由
|
||||
- 保留根路径 302 重定向到 `/group/`
|
||||
- 通过 Supabase Storage API 提供公网文件上传下载功能
|
||||
|
||||
---
|
||||
|
||||
## 最终架构
|
||||
|
||||
### 内网访问 (Tailscale VPN Required)
|
||||
|
||||
| 服务 | 地址 | 用途 |
|
||||
|------|------|------|
|
||||
| MinIO S3 API | `http://100.64.0.2:9000` | 对象存储 API(管理员直接访问)|
|
||||
| MinIO Console | `http://100.64.0.2:9001` | Web 管理界面 |
|
||||
| Supabase Dashboard | `http://100.64.0.2:18000` | 数据库/后端管理 |
|
||||
|
||||
### 公网访问 (HTTPS)
|
||||
|
||||
| 服务 | 地址 | 说明 |
|
||||
|------|------|------|
|
||||
| **根路径** | `https://amiap.hzau.edu.cn/` | 302 重定向到 `/group/` |
|
||||
| **课题组网站** | `https://amiap.hzau.edu.cn/group/` | Vue.js 前端 |
|
||||
| **Supabase Storage** | `https://amiap.hzau.edu.cn/supa/storage/v1/` | 文件上传下载 API ✅ |
|
||||
| **Supabase API** | `https://amiap.hzau.edu.cn/supa/` | Auth/REST/Realtime |
|
||||
| **ABM 数据库** | `https://amiap.hzau.edu.cn/ABM/` | WebSocket 项目 |
|
||||
|
||||
---
|
||||
|
||||
## 存储架构
|
||||
|
||||
### 公网文件上传下载流程
|
||||
|
||||
```
|
||||
用户/应用
|
||||
↓ HTTPS
|
||||
https://amiap.hzau.edu.cn/supa/storage/v1/
|
||||
↓ Traefik (去除 /supa 前缀)
|
||||
Kong Gateway (Supabase API 网关)
|
||||
↓ 内部网络
|
||||
Supabase Storage Service (Docker 内部)
|
||||
↓ S3 协议 (http://minio:9000)
|
||||
MinIO 对象存储
|
||||
↓
|
||||
物理存储: /vol1/1000/s3
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- 用户**不直接**访问 MinIO
|
||||
- 所有公网访问通过 Supabase Storage API
|
||||
- MinIO 仅在 Docker 内部网络和 Tailscale 内网可访问
|
||||
- 文件最终存储在 MinIO 容器 (`/vol1/1000/s3`)
|
||||
|
||||
### 内网直接访问(管理员)
|
||||
|
||||
```
|
||||
管理员 (Tailscale VPN)
|
||||
↓
|
||||
http://100.64.0.2:9000 (MinIO S3 API)
|
||||
http://100.64.0.2:9001 (MinIO Console)
|
||||
↓
|
||||
MinIO 容器
|
||||
↓
|
||||
物理存储: /vol1/1000/s3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置变更详情
|
||||
|
||||
### 1. docker-compose.s3.yml
|
||||
|
||||
**删除的配置**:
|
||||
```yaml
|
||||
# ❌ 已删除
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.minio-s3.rule=..."
|
||||
- "traefik.http.services.minio-s3-svc...."
|
||||
# ... 所有 Traefik labels
|
||||
|
||||
networks:
|
||||
- frontend # ❌ 不再连接到 Traefik 网络
|
||||
```
|
||||
|
||||
**保留/更新的配置**:
|
||||
```yaml
|
||||
services:
|
||||
minio:
|
||||
ports:
|
||||
- "100.64.0.2:9000:9000" # ✓ 仅 Tailscale IP
|
||||
- "100.64.0.2:9001:9001" # ✓ 仅 Tailscale IP
|
||||
environment:
|
||||
MINIO_SERVER_URL: "http://100.64.0.2:9000" # ✓ 内网 URL
|
||||
MINIO_BROWSER_REDIRECT_URL: "http://100.64.0.2:9001"
|
||||
networks:
|
||||
- default # ✓ 仅 Supabase 内部网络
|
||||
```
|
||||
|
||||
### 2. docker-compose.yml
|
||||
|
||||
**修复的端口冲突**:
|
||||
```yaml
|
||||
# Studio Dashboard
|
||||
studio:
|
||||
ports:
|
||||
- "100.64.0.2:18000:3000" # ✓ Tailscale 内网访问
|
||||
|
||||
# Kong API Gateway
|
||||
kong:
|
||||
# ✓ 不暴露端口,仅通过 Traefik 公网访问
|
||||
# Kong 通过 Docker 内部网络与其他服务通信
|
||||
```
|
||||
|
||||
### 3. Supabase Storage 配置
|
||||
|
||||
**Storage 通过内部网络连接 MinIO** (`docker-compose.yml`):
|
||||
```yaml
|
||||
storage:
|
||||
environment:
|
||||
STORAGE_BACKEND: s3
|
||||
GLOBAL_S3_ENDPOINT: http://minio:9000 # ✓ Docker 内部网络
|
||||
GLOBAL_S3_BUCKET: stub
|
||||
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER}
|
||||
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证测试
|
||||
|
||||
### ✅ 测试结果
|
||||
|
||||
运行 `examples/test_https_storage.py`:
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
**测试结果**: 5/5 通过 ✅
|
||||
|
||||
| 测试项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| 列出 Buckets | ✅ | 发现 2 个 bucket |
|
||||
| 创建/确认 Bucket | ✅ | test-https 存在 |
|
||||
| 上传/更新文件 | ✅ | 79 bytes 上传成功 |
|
||||
| 下载文件 | ✅ | 内容完整 |
|
||||
| 生成签名 URL | ✅ | 临时链接可用 |
|
||||
|
||||
### 测试命令示例
|
||||
|
||||
```bash
|
||||
# 测试根路径重定向
|
||||
curl -I https://amiap.hzau.edu.cn
|
||||
# 期望: HTTP/2 302 + Location: /group/
|
||||
|
||||
# 测试 Supabase Storage API
|
||||
curl -I https://amiap.hzau.edu.cn/supa/storage/v1/bucket \
|
||||
-H "apikey: YOUR_API_KEY"
|
||||
# 期望: HTTP/2 200
|
||||
|
||||
# 测试 MinIO 内网访问(需要 Tailscale)
|
||||
curl -I http://100.64.0.2:9000/minio/health/live
|
||||
# 期望: HTTP/1.1 200 OK
|
||||
|
||||
# 测试 MinIO Console(需要 Tailscale)
|
||||
curl -I http://100.64.0.2:9001
|
||||
# 期望: HTTP/1.1 200 OK + Server: MinIO Console
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全优势
|
||||
|
||||
### 1. 最小权限原则
|
||||
- MinIO 不再暴露到公网
|
||||
- 仅授权用户(Tailscale VPN)可直接访问 MinIO
|
||||
|
||||
### 2. 访问控制
|
||||
- 公网访问必须通过 Supabase Storage API
|
||||
- 支持细粒度的权限控制(RLS)
|
||||
- 自动签名 URL,临时授权
|
||||
|
||||
### 3. 攻击面减小
|
||||
- 减少了公网暴露的端口和服务
|
||||
- MinIO 管理界面仅内网可访问
|
||||
- 降低了潜在的 DDoS 风险
|
||||
|
||||
---
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 公网文件上传下载
|
||||
|
||||
**Python 示例**:
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = 'https://amiap.hzau.edu.cn/supa'
|
||||
API_KEY = 'your_anon_key'
|
||||
|
||||
headers = {
|
||||
'apikey': API_KEY,
|
||||
'Authorization': f'Bearer {API_KEY}'
|
||||
}
|
||||
|
||||
# 上传文件
|
||||
with open('test.txt', 'rb') as f:
|
||||
response = requests.post(
|
||||
f'{BASE_URL}/storage/v1/object/bucket-name/file.txt',
|
||||
headers={**headers, 'Content-Type': 'text/plain'},
|
||||
data=f
|
||||
)
|
||||
|
||||
# 下载文件
|
||||
response = requests.get(
|
||||
f'{BASE_URL}/storage/v1/object/bucket-name/file.txt',
|
||||
headers=headers
|
||||
)
|
||||
content = response.content
|
||||
```
|
||||
|
||||
**JavaScript 示例**:
|
||||
```javascript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://amiap.hzau.edu.cn/supa',
|
||||
'your_anon_key'
|
||||
)
|
||||
|
||||
// 上传文件
|
||||
const { data, error } = await supabase.storage
|
||||
.from('bucket-name')
|
||||
.upload('file.txt', file)
|
||||
|
||||
// 下载文件
|
||||
const { data: fileData } = await supabase.storage
|
||||
.from('bucket-name')
|
||||
.download('file.txt')
|
||||
```
|
||||
|
||||
### 内网管理(MinIO Console)
|
||||
|
||||
1. 连接 Tailscale VPN
|
||||
2. 访问: `http://100.64.0.2:9001`
|
||||
3. 登录凭证:
|
||||
- **用户名**: `bsxzZAJ3fvDquup`
|
||||
- **密码**: `c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9`
|
||||
|
||||
### MinIO 命令行工具 (mc)
|
||||
|
||||
```bash
|
||||
# 配置别名
|
||||
mc alias set myminio http://100.64.0.2:9000 \
|
||||
bsxzZAJ3fvDquup \
|
||||
c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9
|
||||
|
||||
# 列出 buckets
|
||||
mc ls myminio
|
||||
|
||||
# 上传文件
|
||||
mc cp local-file.txt myminio/stub/
|
||||
|
||||
# 下载文件
|
||||
mc cp myminio/stub/file.txt ./
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题: Supabase Storage API 返回 404
|
||||
|
||||
**检查**:
|
||||
```bash
|
||||
# 1. 确认 Kong 运行正常
|
||||
docker ps | grep kong
|
||||
|
||||
# 2. 查看 Kong 日志
|
||||
docker logs supabase-kong --tail 50
|
||||
|
||||
# 3. 测试 Kong 健康状态
|
||||
docker inspect supabase-kong --format='{{.State.Health.Status}}'
|
||||
```
|
||||
|
||||
### 问题: MinIO 内网无法访问
|
||||
|
||||
**检查**:
|
||||
```bash
|
||||
# 1. 确认 Tailscale 连接
|
||||
tailscale status
|
||||
ping 100.64.0.2
|
||||
|
||||
# 2. 检查 MinIO 容器
|
||||
docker ps | grep minio
|
||||
|
||||
# 3. 查看端口绑定
|
||||
docker port supabase-minio-1
|
||||
```
|
||||
|
||||
### 问题: 文件上传失败
|
||||
|
||||
**检查**:
|
||||
```bash
|
||||
# 1. 查看 Storage 日志
|
||||
docker logs supabase-storage --tail 50
|
||||
|
||||
# 2. 确认 Storage 到 MinIO 的连接
|
||||
docker exec supabase-storage ping -c 1 minio
|
||||
|
||||
# 3. 检查 Storage 环境变量
|
||||
docker exec supabase-storage env | grep -E "GLOBAL_S3|MINIO"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `examples/test_https_storage.py` - Storage API 功能测试
|
||||
- `MINIO_LOGIN_FIX.md` - MinIO Console 登录问题修复
|
||||
- `INTERNAL_ACCESS_FIXED.md` - 内网访问配置
|
||||
- `DEPLOYMENT_GUIDE.md` - 完整部署指南
|
||||
|
||||
---
|
||||
|
||||
**修改日期**: 2025-11-23
|
||||
**架构版本**: v3.0 (MinIO 内网化)
|
||||
**状态**: ✅ 已验证,生产就绪
|
||||
**测试**: 5/5 通过
|
||||
185
supabase-stack/docs/MINIO_LOGIN_FIX.md
Normal file
185
supabase-stack/docs/MINIO_LOGIN_FIX.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# ✅ MinIO Console 登录问题修复
|
||||
|
||||
## 问题诊断结果
|
||||
|
||||
### 原始问题
|
||||
访问 `http://100.64.0.2:9001` MinIO Console 时登录失败
|
||||
|
||||
### 根本原因
|
||||
MinIO Docker 镜像默认设置了以下环境变量:
|
||||
- `MINIO_ROOT_USER_FILE=access_key`
|
||||
- `MINIO_ROOT_PASSWORD_FILE=secret_key`
|
||||
|
||||
这些 `_FILE` 变量会让 MinIO 尝试从文件中读取凭证,而不是直接使用环境变量 `MINIO_ROOT_USER` 和 `MINIO_ROOT_PASSWORD`。由于这些文件不存在,导致 Console 登录时凭证验证失败。
|
||||
|
||||
### 验证结果
|
||||
✅ **MinIO API 凭证测试成功**
|
||||
```bash
|
||||
$ docker exec supabase-minio-1 mc alias set test http://localhost:9000 \
|
||||
"bsxzZAJ3fvDquup" "c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9"
|
||||
Added `test` successfully.
|
||||
```
|
||||
|
||||
说明:
|
||||
- 环境变量 `MINIO_ROOT_USER` 和 `MINIO_ROOT_PASSWORD` 已正确传递
|
||||
- MinIO 服务本身工作正常
|
||||
- 问题仅出现在 Console 登录
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 修改 `docker-compose.s3.yml`
|
||||
|
||||
在 MinIO 服务的 `environment` 部分添加:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
minio:
|
||||
image: minio/minio
|
||||
ports:
|
||||
- "100.64.0.2:9000:9000"
|
||||
- "100.64.0.2:9001:9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
MINIO_SERVER_URL: "https://amiap.hzau.edu.cn"
|
||||
MINIO_BROWSER_REDIRECT_URL: "http://100.64.0.2:9001"
|
||||
# 🔧 禁用文件凭证,强制使用环境变量
|
||||
MINIO_ROOT_USER_FILE: ""
|
||||
MINIO_ROOT_PASSWORD_FILE: ""
|
||||
# ... 其他配置
|
||||
```
|
||||
|
||||
### 重启服务
|
||||
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
docker compose -f docker-compose.yml -f docker-compose.s3.yml restart minio
|
||||
```
|
||||
|
||||
## 验证修复
|
||||
|
||||
### 1. 检查环境变量
|
||||
|
||||
```bash
|
||||
docker exec supabase-minio-1 env | grep MINIO_ROOT
|
||||
```
|
||||
|
||||
**期望输出**:
|
||||
```
|
||||
MINIO_ROOT_USER=bsxzZAJ3fvDquup
|
||||
MINIO_ROOT_PASSWORD=c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9
|
||||
MINIO_ROOT_USER_FILE= # 空值,已禁用
|
||||
MINIO_ROOT_PASSWORD_FILE= # 空值,已禁用
|
||||
```
|
||||
|
||||
### 2. 测试 API 连接
|
||||
|
||||
```bash
|
||||
docker exec supabase-minio-1 mc alias set test http://localhost:9000 \
|
||||
"bsxzZAJ3fvDquup" "c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9"
|
||||
```
|
||||
|
||||
**期望输出**: `Added 'test' successfully.` ✓
|
||||
|
||||
### 3. 测试 Console 访问
|
||||
|
||||
```bash
|
||||
curl -I http://100.64.0.2:9001
|
||||
```
|
||||
|
||||
**期望输出**: `HTTP/1.1 200 OK` ✓
|
||||
|
||||
## MinIO Console 登录信息
|
||||
|
||||
### 访问地址
|
||||
```
|
||||
http://100.64.0.2:9001
|
||||
```
|
||||
|
||||
### 登录凭证
|
||||
**用户名**: `bsxzZAJ3fvDquup`
|
||||
|
||||
**密码**: `c2dc1bca7aa4d0adc308f69b6d41eddfaa110a9572ad1b410d73ea0633523fe9`
|
||||
|
||||
⚠️ **重要提示**:
|
||||
- 密码长度为 64 个字符
|
||||
- 复制时确保没有多余空格或换行符
|
||||
- 建议使用密码管理器或直接复制粘贴
|
||||
|
||||
## 如果登录仍然失败
|
||||
|
||||
### 1. 清除浏览器缓存
|
||||
|
||||
Console 可能缓存了旧的配置:
|
||||
1. 打开浏览器开发者工具(F12)
|
||||
2. 右键点击刷新按钮 → "清空缓存并硬性重新加载"
|
||||
3. 或清除 `http://100.64.0.2:9001` 的所有 Cookie 和缓存
|
||||
|
||||
### 2. 使用无痕/隐私模式
|
||||
|
||||
```
|
||||
Chrome: Ctrl+Shift+N
|
||||
Firefox: Ctrl+Shift+P
|
||||
Edge: Ctrl+Shift+N
|
||||
```
|
||||
|
||||
### 3. 检查 Tailscale 连接
|
||||
|
||||
确保已连接到 Tailscale VPN:
|
||||
|
||||
```bash
|
||||
# 测试连通性
|
||||
ping 100.64.0.2
|
||||
|
||||
# 检查 Tailscale 状态
|
||||
tailscale status
|
||||
|
||||
# 测试端口访问
|
||||
curl http://100.64.0.2:9001
|
||||
```
|
||||
|
||||
### 4. 查看实时日志
|
||||
|
||||
如果还是失败,查看登录时的实时日志:
|
||||
|
||||
```bash
|
||||
docker logs -f supabase-minio-1
|
||||
```
|
||||
|
||||
然后在浏览器中尝试登录,观察日志输出。
|
||||
|
||||
## 技术说明
|
||||
|
||||
### 为什么设置 `_FILE=""` 而不是删除?
|
||||
|
||||
MinIO Docker 镜像在启动时会自动设置 `MINIO_ROOT_USER_FILE` 和 `MINIO_ROOT_PASSWORD_FILE` 的默认值。即使我们在 `docker-compose.yml` 中不定义它们,镜像仍会使用默认值。
|
||||
|
||||
通过明确设置为空字符串 `""`,我们告诉 MinIO **禁用**文件凭证功能,强制使用环境变量。
|
||||
|
||||
### MinIO 凭证优先级
|
||||
|
||||
MinIO 读取凭证的优先级:
|
||||
1. **`MINIO_ROOT_USER_FILE` / `MINIO_ROOT_PASSWORD_FILE`** (最高优先级)
|
||||
2. `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD`
|
||||
3. 默认凭证 `minioadmin` / `minioadmin` (仅开发环境)
|
||||
|
||||
## 修复历史
|
||||
|
||||
| 日期 | 问题 | 修复 | 状态 |
|
||||
|------|------|------|------|
|
||||
| 2025-11-23 | Supabase Dashboard 无法访问 | 添加端口绑定 `100.64.0.2:18000:3000` | ✅ 已修复 |
|
||||
| 2025-11-23 | MinIO 端口绑定到 `0.0.0.0` | 改为 `100.64.0.2:9000-9001` | ✅ 已修复 |
|
||||
| 2025-11-23 | MinIO Console 登录失败 | 禁用 `_FILE` 环境变量 | ✅ 已修复 |
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `INTERNAL_ACCESS_FIXED.md` - 内网访问配置总结
|
||||
- `DEPLOYMENT_GUIDE.md` - 完整部署指南
|
||||
- `FINAL_ARCHITECTURE_v2.md` - 系统架构说明
|
||||
|
||||
---
|
||||
|
||||
**修复日期**: 2025-11-23
|
||||
**修复人员**: AI Assistant
|
||||
**验证状态**: ✅ 完成
|
||||
**测试结果**: MinIO API 和 Console 均正常工作
|
||||
426
supabase-stack/docs/README_CN.md
Normal file
426
supabase-stack/docs/README_CN.md
Normal file
@@ -0,0 +1,426 @@
|
||||
# Supabase 部署完成 ✅
|
||||
|
||||
恭喜!Supabase 后端已成功部署在 `https://amiap.hzau.edu.cn/supa`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 服务启动
|
||||
|
||||
### 完整启动命令
|
||||
|
||||
Supabase 服务包含**核心服务**和 **S3 对象存储**两部分,使用 Docker Compose 的 override 功能同时启动:
|
||||
|
||||
```bash
|
||||
# 进入目录
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 🔥 推荐:使用 override 方式启动(同时启动核心服务 + S3)
|
||||
docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### 服务组成说明
|
||||
|
||||
#### 核心服务(docker-compose.yml)
|
||||
- **PostgreSQL**: 数据库
|
||||
- **Kong**: API 网关
|
||||
- **REST API**: PostgREST 自动 API
|
||||
- **Auth**: 用户认证
|
||||
- **Storage**: 文件存储
|
||||
- **Realtime**: 实时订阅
|
||||
- **Studio**: 管理面板
|
||||
- **Analytics**: 数据分析
|
||||
- **Pooler**: 连接池(可选,见下方说明)
|
||||
|
||||
#### S3 对象存储(docker-compose.s3.yml)
|
||||
- **MinIO**: S3 兼容的对象存储后端
|
||||
- 为 Storage API 提供文件存储能力
|
||||
- 数据持久化到 `/vol1/1000/s3/stub/`
|
||||
|
||||
### 启动流程
|
||||
|
||||
```bash
|
||||
# 1. 确保 Traefik 已启动
|
||||
cd /vol1/1000/docker_server/traefik
|
||||
docker compose ps traefik
|
||||
|
||||
# 2. 启动 Supabase(核心 + S3)
|
||||
cd supabase-stack
|
||||
docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
|
||||
|
||||
# 3. 等待服务就绪(约 30-60 秒)
|
||||
watch -n 2 'docker compose ps'
|
||||
|
||||
# 4. 验证服务
|
||||
curl -s https://amiap.hzau.edu.cn/supa/rest/v1/ | jq
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
### 快速管理命令
|
||||
|
||||
```bash
|
||||
# 查看所有服务状态
|
||||
docker compose ps
|
||||
|
||||
# 查看特定服务日志
|
||||
docker compose logs -f kong
|
||||
docker compose logs -f storage
|
||||
docker compose logs -f rest
|
||||
|
||||
# 重启服务
|
||||
docker compose restart
|
||||
|
||||
# 停止服务(保留数据)
|
||||
docker compose down
|
||||
|
||||
# 完全清理(删除所有数据,慎用!)
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 快速开始
|
||||
|
||||
### 访问地址
|
||||
|
||||
**API 端点(用于开发)**
|
||||
```
|
||||
https://amiap.hzau.edu.cn/supa
|
||||
```
|
||||
|
||||
**Dashboard(管理界面)**
|
||||
```
|
||||
http://100.64.0.2:18000
|
||||
用户名: lab-admin
|
||||
密码: 017b7076cfb25bd18410d1e5f4f7ec5a
|
||||
```
|
||||
|
||||
### API Keys
|
||||
|
||||
```javascript
|
||||
// 公开密钥 - 可在前端使用
|
||||
const ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzYzODAyNjY5LCJleHAiOjIwNzkxNjI2Njl9.ltGXvQKpguLaf8Vzomn310hLgOZbrjqZT-F3rR00ulg"
|
||||
|
||||
// 私密密钥 - 仅后端使用
|
||||
const SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3NjM4MDI2NjksImV4cCI6MjA3OTE2MjY2OX0.gQWUaTkZ6mjjlv2TED0cODp2meqqWuCGKZR1ptIbovg"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| **[README_STORAGE.md](./README_STORAGE.md)** | 🔥 **Storage 对象存储使用指南** |
|
||||
| **[docs/QUICK_START.md](./docs/QUICK_START.md)** | Storage API 快速入门 |
|
||||
| **[docs/OPERATIONS_GUIDE.md](./docs/OPERATIONS_GUIDE.md)** | 完整运维指南 |
|
||||
| **[docs/VUE_API_INTEGRATION.md](./docs/VUE_API_INTEGRATION.md)** | Vue 前端集成教程 |
|
||||
| **[docs/DEPLOYMENT_INFO.md](./docs/DEPLOYMENT_INFO.md)** | 部署配置详情 |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 可用的功能
|
||||
|
||||
| 功能 | 端点 | 状态 |
|
||||
|------|------|------|
|
||||
| **REST API** | `https://amiap.hzau.edu.cn/supa/rest/v1/` | ✅ 可用 |
|
||||
| **Auth API** | `https://amiap.hzau.edu.cn/supa/auth/v1/` | ✅ 可用 |
|
||||
| **Storage API** | `https://amiap.hzau.edu.cn/supa/storage/v1/` | ✅ 可用 |
|
||||
| **Realtime** | `wss://amiap.hzau.edu.cn/supa/realtime/v1/` | ✅ 可用 |
|
||||
| **Dashboard** | `http://100.64.0.2:18000` | ✅ 可用(内网)|
|
||||
| **MinIO** | 内部 S3 后端 | ✅ 运行中 |
|
||||
|
||||
所有核心功能都正常工作,可以开始开发!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Vue 集成示例
|
||||
|
||||
### 1. 安装
|
||||
```bash
|
||||
npm install @supabase/supabase-js
|
||||
```
|
||||
|
||||
### 2. 配置
|
||||
```javascript
|
||||
// src/lib/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
export const supabase = createClient(
|
||||
'https://amiap.hzau.edu.cn/supa',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzYzODAyNjY5LCJleHAiOjIwNzkxNjI2Njl9.ltGXvQKpguLaf8Vzomn310hLgOZbrjqZT-F3rR00ulg'
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 使用
|
||||
```vue
|
||||
<script setup>
|
||||
import { supabase } from '@/lib/supabaseClient'
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
const users = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
const { data } = await supabase.from('users').select('*')
|
||||
users.value = data
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
**详细教程请查看 [docs/VUE_API_INTEGRATION.md](./docs/VUE_API_INTEGRATION.md)**
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试 API
|
||||
|
||||
运行测试脚本:
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 测试 Storage API
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
或手动测试:
|
||||
```bash
|
||||
# 测试 Storage API
|
||||
curl https://amiap.hzau.edu.cn/supa/storage/v1/bucket
|
||||
|
||||
# 测试 Auth API
|
||||
curl https://amiap.hzau.edu.cn/supa/auth/v1/health
|
||||
|
||||
# 测试 REST API
|
||||
curl https://amiap.hzau.edu.cn/supa/rest/v1/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要提示
|
||||
|
||||
### 1. Dashboard 访问
|
||||
- ❌ `https://amiap.hzau.edu.cn/supa` 无法访问 Dashboard(子路径问题)
|
||||
- ✅ 使用内网地址:`http://100.64.0.2:18000`
|
||||
|
||||
### 2. Pooler 服务重启问题 ⚠️
|
||||
|
||||
**问题现象**:
|
||||
```bash
|
||||
docker compose ps
|
||||
# supabase-pooler Restarting (1) 40 seconds ago
|
||||
```
|
||||
|
||||
**原因分析**:
|
||||
- `supabase-pooler` (Supavisor) 是数据库连接池服务
|
||||
- 主要用于高并发场景的连接优化
|
||||
- 在开发和小规模部署中**不是必需的**
|
||||
- 可能因配置或依赖问题导致重启
|
||||
|
||||
**解决方案**:
|
||||
|
||||
#### 方案 1:忽略(推荐)
|
||||
连接池服务不影响任何核心功能,可以安全忽略:
|
||||
```bash
|
||||
# 所有 API 功能正常工作,无需处理
|
||||
```
|
||||
|
||||
#### 方案 2:禁用 Pooler
|
||||
如果持续重启影响日志查看,可以禁用:
|
||||
|
||||
```bash
|
||||
# 停止 pooler 服务
|
||||
docker compose stop supavisor
|
||||
|
||||
# 或在 docker-compose.yml 中注释掉 supavisor 服务后重启
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**创建禁用配置**:
|
||||
```bash
|
||||
# 创建 docker-compose.override.yml
|
||||
cat > docker-compose.override.yml << 'OVERRIDE'
|
||||
services:
|
||||
supavisor:
|
||||
restart: "no"
|
||||
# 或完全禁用
|
||||
# profiles: ["disabled"]
|
||||
OVERRIDE
|
||||
|
||||
# 重启服务
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
#### 方案 3:查看详细日志
|
||||
如果需要修复,查看错误详情:
|
||||
```bash
|
||||
docker logs supabase-pooler --tail 100
|
||||
```
|
||||
|
||||
**结论**:对于开发和小规模使用,建议使用**方案 1(忽略)**或**方案 2(禁用)**。
|
||||
|
||||
### 3. REST API Schema Cache
|
||||
- 首次访问可能提示 "schema cache retrying"
|
||||
- 这是正常的初始化过程
|
||||
- 等待几秒会自动恢复,或重启 rest 服务
|
||||
|
||||
### 4. MinIO 存储
|
||||
- S3 数据存储在 `/vol1/1000/s3/stub/`
|
||||
- 不要直接访问 MinIO,统一通过 Storage API
|
||||
- 详见 [README_STORAGE.md](./README_STORAGE.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 常用管理命令
|
||||
|
||||
### 服务管理
|
||||
```bash
|
||||
# 查看所有服务状态
|
||||
docker compose ps
|
||||
|
||||
# 查看资源使用
|
||||
docker compose stats
|
||||
|
||||
# 重启特定服务
|
||||
docker compose restart kong
|
||||
docker compose restart storage
|
||||
docker compose restart rest
|
||||
|
||||
# 停止服务
|
||||
docker compose stop
|
||||
|
||||
# 启动服务
|
||||
docker compose start
|
||||
|
||||
# 完全重启
|
||||
docker compose down && docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
|
||||
```
|
||||
|
||||
### 日志查看
|
||||
```bash
|
||||
# 实时查看所有日志
|
||||
docker compose logs -f
|
||||
|
||||
# 查看特定服务日志
|
||||
docker compose logs -f kong
|
||||
docker compose logs -f storage
|
||||
docker compose logs -f rest
|
||||
docker compose logs -f db
|
||||
|
||||
# 查看最近 100 行
|
||||
docker compose logs --tail=100
|
||||
|
||||
# 查看 MinIO 日志
|
||||
docker logs supabase-minio
|
||||
```
|
||||
|
||||
### 数据库管理
|
||||
```bash
|
||||
# 连接数据库
|
||||
docker exec -it supabase-db psql -U postgres
|
||||
|
||||
# 备份数据库
|
||||
docker exec supabase-db pg_dump -U postgres postgres > backup.sql
|
||||
|
||||
# 恢复数据库
|
||||
docker exec -i supabase-db psql -U postgres postgres < backup.sql
|
||||
```
|
||||
|
||||
### 清理和重置
|
||||
```bash
|
||||
# 停止服务(保留数据)
|
||||
docker compose down
|
||||
|
||||
# 完全清理(删除所有数据,慎用!)
|
||||
docker compose down -v
|
||||
|
||||
# 清理未使用的容器和镜像
|
||||
docker system prune -a
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 开发流程
|
||||
|
||||
1. **启动服务**
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
|
||||
```
|
||||
|
||||
2. **访问 Dashboard**(内网)
|
||||
- 打开 `http://100.64.0.2:18000`
|
||||
- 登录后创建数据库表
|
||||
|
||||
3. **配置 RLS 策略**
|
||||
- 在 SQL Editor 中设置权限
|
||||
- 参考文档中的示例
|
||||
|
||||
4. **Vue 应用集成**
|
||||
- 按照 `docs/VUE_API_INTEGRATION.md` 配置
|
||||
- 使用 `https://amiap.hzau.edu.cn/supa` 作为 API 地址
|
||||
|
||||
5. **Storage 使用**
|
||||
- 查看 `README_STORAGE.md`
|
||||
- 使用 Python 或 JavaScript 客户端
|
||||
|
||||
6. **开发测试**
|
||||
- 所有 API 都通过 HTTPS 访问
|
||||
- Dashboard 通过内网管理数据
|
||||
|
||||
---
|
||||
|
||||
## 🎓 学习资源
|
||||
|
||||
- [README_STORAGE.md](./README_STORAGE.md) - Storage 对象存储完整指南
|
||||
- [docs/QUICK_START.md](./docs/QUICK_START.md) - 快速入门
|
||||
- [docs/OPERATIONS_GUIDE.md](./docs/OPERATIONS_GUIDE.md) - 运维指南
|
||||
- [docs/VUE_API_INTEGRATION.md](./docs/VUE_API_INTEGRATION.md) - Vue 集成
|
||||
- [Supabase 官方文档](https://supabase.com/docs)
|
||||
- [Supabase JS 客户端](https://supabase.com/docs/reference/javascript)
|
||||
|
||||
---
|
||||
|
||||
## 💡 常见问题
|
||||
|
||||
**Q: 为什么 Dashboard 不能通过 HTTPS 访问?**
|
||||
A: Supabase Studio 是单页应用,不支持子路径部署。使用内网地址访问。
|
||||
|
||||
**Q: API 都可以正常使用吗?**
|
||||
A: 是的!所有核心 API(REST/Auth/Storage/Realtime)都可以通过 HTTPS 正常使用。
|
||||
|
||||
**Q: pooler 一直重启有影响吗?**
|
||||
A: 没有影响。pooler 是连接池优化组件,非核心功能。可以忽略或禁用。
|
||||
|
||||
**Q: 如何远程访问 Dashboard?**
|
||||
A: 使用 SSH 端口转发:`ssh -L 18000:100.64.0.2:18000 user@server`
|
||||
|
||||
**Q: 如何使用对象存储功能?**
|
||||
A: 查看 [README_STORAGE.md](./README_STORAGE.md) 和 `examples/` 目录中的示例代码。
|
||||
|
||||
**Q: MinIO 一定要启动吗?**
|
||||
A: 如果使用 Storage API 上传文件,MinIO 必须启动。使用 override 方式会自动启动。
|
||||
|
||||
---
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
**Supabase 后端已完整部署!**
|
||||
|
||||
✅ 所有 API 功能正常
|
||||
✅ 对象存储(S3)正常
|
||||
✅ 可以开始 Vue 应用开发
|
||||
✅ Dashboard 可通过内网管理
|
||||
✅ 完整的开发文档已准备好
|
||||
|
||||
**启动命令**:
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
|
||||
```
|
||||
|
||||
开始你的 Supabase 开发之旅吧!🚀
|
||||
|
||||
---
|
||||
|
||||
**部署日期**: 2025-11-22
|
||||
**服务器**: amiap.hzau.edu.cn
|
||||
**维护文档**: 本目录下的 README_STORAGE.md 和 docs/ 文件夹
|
||||
277
supabase-stack/docs/STORAGE_FILE_BACKEND_MIGRATION.md
Normal file
277
supabase-stack/docs/STORAGE_FILE_BACKEND_MIGRATION.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Storage 后端迁移:从 MinIO (S3) 到文件系统
|
||||
|
||||
**日期**: 2025-12-05
|
||||
**状态**: ✅ 完成(部分功能限制)
|
||||
|
||||
## 迁移概述
|
||||
|
||||
将 Supabase Storage 从 MinIO (S3 兼容对象存储) 迁移到文件系统后端。
|
||||
|
||||
## 变更内容
|
||||
|
||||
### 1. docker-compose.yml 修改
|
||||
|
||||
**修改前** (S3 后端):
|
||||
```yaml
|
||||
storage:
|
||||
environment:
|
||||
STORAGE_BACKEND: s3
|
||||
GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
|
||||
GLOBAL_S3_ENDPOINT: ${GLOBAL_S3_ENDPOINT}
|
||||
GLOBAL_S3_PROTOCOL: ${GLOBAL_S3_PROTOCOL}
|
||||
GLOBAL_S3_FORCE_PATH_STYLE: ${GLOBAL_S3_FORCE_PATH_STYLE}
|
||||
```
|
||||
|
||||
**修改后** (文件后端):
|
||||
```yaml
|
||||
storage:
|
||||
environment:
|
||||
STORAGE_BACKEND: file
|
||||
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
|
||||
# GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET} # 已注释
|
||||
# GLOBAL_S3_ENDPOINT: ${GLOBAL_S3_ENDPOINT} # 已注释
|
||||
# GLOBAL_S3_PROTOCOL: ${GLOBAL_S3_PROTOCOL} # 已注释
|
||||
# GLOBAL_S3_FORCE_PATH_STYLE: ${GLOBAL_S3_FORCE_PATH_STYLE} # 已注释
|
||||
```
|
||||
|
||||
### 2. MinIO 服务停用
|
||||
|
||||
```bash
|
||||
# 停止 MinIO 容器
|
||||
docker compose -f docker-compose.s3.yml down
|
||||
|
||||
# MinIO 不再启动(docker-compose.s3.yml 不再使用)
|
||||
```
|
||||
|
||||
### 3. 文件存储目录
|
||||
|
||||
**存储路径**:
|
||||
```
|
||||
volumes/storage/undefined/stub/{bucket-name}/{file-name}/{version-id}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```
|
||||
volumes/storage/undefined/stub/test-file-backend/hello.txt/59a6c5e4-fe40-4414-8f42-619cd0792619
|
||||
```
|
||||
|
||||
**注意**: 路径中的 `undefined` 是文件后端的固定目录结构,不是错误。
|
||||
|
||||
## 测试结果
|
||||
|
||||
### ✅ 正常功能 (4/5)
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 列出 Buckets | ✅ | 完全正常 |
|
||||
| 上传文件 | ✅ | 完全正常 |
|
||||
| 下载文件 | ✅ | 公共和认证访问都正常 |
|
||||
| 删除文件 | ✅ | 完全正常 |
|
||||
| **更新文件** | ❌ | **500 错误** |
|
||||
|
||||
### ❌ 已知问题
|
||||
|
||||
#### 1. 文件更新失败
|
||||
|
||||
**错误**:
|
||||
```
|
||||
PUT /storage/v1/object/{bucket}/{file}
|
||||
Status: 500 Internal Server Error
|
||||
```
|
||||
|
||||
**原因**: Supabase Storage 文件后端的已知 bug,更新文件时尝试删除旧版本时路径解析错误。
|
||||
|
||||
**临时方案**: 先删除再上传
|
||||
```python
|
||||
# 删除旧文件
|
||||
requests.delete(f'{BASE_URL}/storage/v1/object/{bucket}/{file}', headers=headers)
|
||||
|
||||
# 上传新文件
|
||||
requests.post(f'{BASE_URL}/storage/v1/object/{bucket}/{file}', headers=headers, data=new_data)
|
||||
```
|
||||
|
||||
#### 2. S3 后端数据不兼容
|
||||
|
||||
- 之前 MinIO (S3) 后端创建的 buckets 中的文件无法访问
|
||||
- 文件元数据存储格式不同
|
||||
- **需要重新上传**旧文件到新 bucket
|
||||
|
||||
## 使用示例
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = 'https://amiap.hzau.edu.cn/supa'
|
||||
API_KEY = 'your_service_role_key'
|
||||
|
||||
headers = {
|
||||
'apikey': API_KEY,
|
||||
'Authorization': f'Bearer {API_KEY}'
|
||||
}
|
||||
|
||||
# 创建 bucket
|
||||
response = requests.post(
|
||||
f'{BASE_URL}/storage/v1/bucket',
|
||||
headers=headers,
|
||||
json={'name': 'my-bucket', 'public': True}
|
||||
)
|
||||
|
||||
# 上传文件
|
||||
with open('file.txt', 'rb') as f:
|
||||
response = requests.post(
|
||||
f'{BASE_URL}/storage/v1/object/my-bucket/file.txt',
|
||||
headers={**headers, 'Content-Type': 'text/plain'},
|
||||
data=f
|
||||
)
|
||||
|
||||
# 下载文件(公共 bucket)
|
||||
response = requests.get(
|
||||
f'{BASE_URL}/storage/v1/object/public/my-bucket/file.txt'
|
||||
)
|
||||
content = response.content
|
||||
|
||||
# 删除文件
|
||||
response = requests.delete(
|
||||
f'{BASE_URL}/storage/v1/object/my-bucket/file.txt',
|
||||
headers=headers
|
||||
)
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://amiap.hzau.edu.cn/supa',
|
||||
'your_anon_key'
|
||||
)
|
||||
|
||||
// 上传文件
|
||||
const { data, error } = await supabase.storage
|
||||
.from('my-bucket')
|
||||
.upload('file.txt', file)
|
||||
|
||||
// 下载文件
|
||||
const { data: fileData } = await supabase.storage
|
||||
.from('my-bucket')
|
||||
.download('file.txt')
|
||||
|
||||
// 删除文件
|
||||
await supabase.storage
|
||||
.from('my-bucket')
|
||||
.remove(['file.txt'])
|
||||
```
|
||||
|
||||
## 架构对比
|
||||
|
||||
### MinIO (S3) 后端
|
||||
|
||||
```
|
||||
用户 → Supabase Storage API
|
||||
→ MinIO 容器 (S3协议)
|
||||
→ /vol1/1000/s3 (对象存储)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 完整的 S3 API 支持
|
||||
- ✅ 可以用 MinIO Console 管理
|
||||
- ✅ 文件更新功能正常
|
||||
- ✅ 可扩展性好
|
||||
|
||||
**劣势**:
|
||||
- ❌ 需要额外的 MinIO 容器
|
||||
- ❌ 占用更多资源
|
||||
|
||||
### 文件系统后端
|
||||
|
||||
```
|
||||
用户 → Supabase Storage API
|
||||
→ 本地文件系统
|
||||
→ volumes/storage/undefined/stub/...
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 简单,无需额外容器
|
||||
- ✅ 直接访问文件系统
|
||||
- ✅ 资源占用少
|
||||
|
||||
**劣势**:
|
||||
- ❌ 文件更新功能有bug
|
||||
- ❌ 无管理界面
|
||||
- ❌ 扩展性差
|
||||
- ❌ 与 S3 后端数据不兼容
|
||||
|
||||
## 回滚到 MinIO
|
||||
|
||||
如需回滚到 MinIO (S3) 后端:
|
||||
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 1. 恢复配置
|
||||
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
|
||||
|
||||
# 2. 重启 Storage
|
||||
docker compose stop storage
|
||||
docker compose rm -f storage
|
||||
docker compose up -d storage
|
||||
|
||||
# 3. 启动 MinIO
|
||||
docker compose -f docker-compose.s3.yml up -d
|
||||
|
||||
# 4. 测试
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
## 备份文件
|
||||
|
||||
迁移过程中创建的备份:
|
||||
- `docker-compose.yml.backup-before-rustfs` - S3 后端配置
|
||||
- `docker-compose.s3.yml.backup-before-rustfs` - MinIO 配置
|
||||
|
||||
## 物理存储位置
|
||||
|
||||
### 文件后端
|
||||
- **路径**: `volumes/storage/undefined/stub/{bucket}/{file}/{version}`
|
||||
- **格式**: 本地文件系统
|
||||
- **管理**: 直接文件访问
|
||||
|
||||
### MinIO (旧)
|
||||
- **路径**: `/vol1/1000/s3`
|
||||
- **格式**: S3 对象存储
|
||||
- **管理**: MinIO Console (http://100.64.0.2:9001)
|
||||
|
||||
## 建议
|
||||
|
||||
### 生产环境
|
||||
|
||||
**不推荐**使用文件后端,原因:
|
||||
1. 文件更新功能有已知bug
|
||||
2. 功能不完整
|
||||
3. 无管理界面
|
||||
4. 官方主要支持 S3 后端
|
||||
|
||||
**推荐**继续使用 MinIO (S3) 后端。
|
||||
|
||||
### 开发/测试环境
|
||||
|
||||
可以使用文件后端,注意:
|
||||
1. 避免文件更新操作(使用删除+上传)
|
||||
2. 定期备份 volumes/storage 目录
|
||||
3. 监控存储空间
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `README.md` - 主文档
|
||||
- `docs/FINAL_ARCHITECTURE_MINIO_INTERNAL.md` - MinIO 架构说明
|
||||
- `examples/test_https_storage.py` - Storage API 测试
|
||||
|
||||
---
|
||||
|
||||
**迁移日期**: 2025-12-05
|
||||
**执行人**: 系统管理员
|
||||
**状态**: ✅ 完成(功能受限)
|
||||
**建议**: 生产环境使用 MinIO
|
||||
283
supabase-stack/docs/STORAGE_TROUBLESHOOTING.md
Normal file
283
supabase-stack/docs/STORAGE_TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Storage 故障排查指南
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 下载文件返回 500 错误
|
||||
|
||||
**症状**:
|
||||
```
|
||||
GET /storage/v1/object/{bucket}/{file}
|
||||
Status: 500 Internal Server Error
|
||||
{"statusCode":"500","error":"Internal","message":"Internal Server Error"}
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 数据库中有对象元数据,但文件系统中没有实际文件
|
||||
- 通常发生在后端切换后(S3 → 文件系统)
|
||||
|
||||
**解决方法**:
|
||||
|
||||
```bash
|
||||
# 方法 1: 清理单个 bucket 的旧数据
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "DELETE FROM storage.objects WHERE bucket_id = 'your-bucket-name';"
|
||||
|
||||
# 方法 2: 查看所有对象
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "SELECT bucket_id, name, created_at FROM storage.objects ORDER BY created_at DESC LIMIT 20;"
|
||||
|
||||
# 方法 3: 清理所有对象(谨慎!)
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "TRUNCATE TABLE storage.objects CASCADE;"
|
||||
```
|
||||
|
||||
重新上传文件后测试:
|
||||
```bash
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
### 2. 文件更新返回 500 错误
|
||||
|
||||
**症状**:
|
||||
```
|
||||
PUT /storage/v1/object/{bucket}/{file}
|
||||
Status: 500
|
||||
TypeError: paths[1] must be of type string
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 文件系统后端的已知 bug
|
||||
- 更新文件时路径解析错误
|
||||
|
||||
**解决方法**:
|
||||
|
||||
使用 DELETE + POST 代替 PUT:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
headers = {'apikey': API_KEY, 'Authorization': f'Bearer {API_KEY}'}
|
||||
|
||||
# 1. 删除旧文件
|
||||
requests.delete(
|
||||
f'{BASE_URL}/storage/v1/object/bucket/file.txt',
|
||||
headers=headers
|
||||
)
|
||||
|
||||
# 2. 上传新文件
|
||||
with open('file.txt', 'rb') as f:
|
||||
requests.post(
|
||||
f'{BASE_URL}/storage/v1/object/bucket/file.txt',
|
||||
headers={**headers, 'Content-Type': 'text/plain'},
|
||||
data=f
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 文件路径包含 "undefined"
|
||||
|
||||
**症状**:
|
||||
```
|
||||
volumes/storage/undefined/stub/bucket/file.txt/version-id
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 这不是错误!
|
||||
- "undefined" 是文件系统后端的固定目录结构
|
||||
- 完全正常,可以忽略
|
||||
|
||||
### 4. 旧 S3 后端的文件无法访问
|
||||
|
||||
**症状**:
|
||||
- 从 MinIO (S3) 迁移到文件系统后端
|
||||
- 旧文件无法下载,返回 500 或 404
|
||||
|
||||
**原因**:
|
||||
- 文件元数据格式不兼容
|
||||
- 数据库记录的路径与实际存储不匹配
|
||||
|
||||
**解决方法**:
|
||||
|
||||
1. **清理旧数据** (推荐):
|
||||
```bash
|
||||
# 清理特定 bucket
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "DELETE FROM storage.objects WHERE bucket_id = 'old-bucket';"
|
||||
```
|
||||
|
||||
2. **迁移数据到新 bucket**:
|
||||
```python
|
||||
# 1. 从 MinIO 下载所有文件(如果还在运行)
|
||||
# 2. 清理数据库
|
||||
# 3. 重新上传到文件系统后端
|
||||
```
|
||||
|
||||
3. **保留 MinIO** (最简单):
|
||||
```bash
|
||||
# 回滚到 MinIO 后端
|
||||
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
|
||||
docker compose -f docker-compose.s3.yml up -d
|
||||
docker compose restart storage
|
||||
```
|
||||
|
||||
### 5. Storage 服务启动失败
|
||||
|
||||
**检查日志**:
|
||||
```bash
|
||||
docker logs supabase-storage --tail 50
|
||||
```
|
||||
|
||||
**常见问题**:
|
||||
|
||||
- 数据库连接失败
|
||||
```bash
|
||||
docker ps | grep supabase-db
|
||||
docker logs supabase-db --tail 20
|
||||
```
|
||||
|
||||
- 环境变量配置错误
|
||||
```bash
|
||||
docker exec supabase-storage env | grep STORAGE
|
||||
```
|
||||
|
||||
- 卷挂载问题
|
||||
```bash
|
||||
ls -la volumes/storage/
|
||||
chmod 777 volumes/storage/
|
||||
```
|
||||
|
||||
## 诊断命令
|
||||
|
||||
### 检查 Storage 配置
|
||||
|
||||
```bash
|
||||
# 查看后端类型
|
||||
docker exec supabase-storage env | grep STORAGE_BACKEND
|
||||
|
||||
# 文件后端 -> STORAGE_BACKEND=file
|
||||
# S3 后端 -> STORAGE_BACKEND=s3
|
||||
```
|
||||
|
||||
### 检查数据库
|
||||
|
||||
```bash
|
||||
# 列出所有 buckets
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "SELECT id, name, public, created_at FROM storage.buckets;"
|
||||
|
||||
# 列出所有对象
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "SELECT bucket_id, name, created_at FROM storage.objects LIMIT 10;"
|
||||
|
||||
# 统计对象数量
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "SELECT bucket_id, COUNT(*) FROM storage.objects GROUP BY bucket_id;"
|
||||
```
|
||||
|
||||
### 检查文件系统
|
||||
|
||||
```bash
|
||||
# 查看存储目录
|
||||
ls -la volumes/storage/
|
||||
|
||||
# 查找所有文件
|
||||
find volumes/storage/ -type f
|
||||
|
||||
# 检查文件大小
|
||||
du -sh volumes/storage/*
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 后端选择
|
||||
|
||||
**生产环境**:
|
||||
- ✅ 使用 MinIO (S3) 后端
|
||||
- 功能完整、稳定可靠
|
||||
- 有管理界面
|
||||
|
||||
**开发/测试环境**:
|
||||
- ✅ 可使用文件系统后端
|
||||
- 简单、资源占用少
|
||||
- 注意功能限制
|
||||
|
||||
### 2. 数据迁移
|
||||
|
||||
如需切换后端:
|
||||
|
||||
1. **备份数据库**
|
||||
```bash
|
||||
docker exec supabase-db pg_dump -U postgres postgres > backup.sql
|
||||
```
|
||||
|
||||
2. **导出文件**(MinIO → 文件系统)
|
||||
```bash
|
||||
# 下载所有文件
|
||||
# 清理数据库
|
||||
# 重新上传
|
||||
```
|
||||
|
||||
3. **测试验证**
|
||||
```bash
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
### 3. 日常维护
|
||||
|
||||
**定期检查**:
|
||||
```bash
|
||||
# 检查存储空间
|
||||
df -h volumes/storage/
|
||||
|
||||
# 检查对象数量
|
||||
docker exec supabase-db psql -U postgres -d postgres \
|
||||
-c "SELECT COUNT(*) FROM storage.objects;"
|
||||
|
||||
# 检查服务健康
|
||||
docker ps | grep storage
|
||||
```
|
||||
|
||||
**清理无用数据**:
|
||||
```bash
|
||||
# 删除孤立的数据库记录(没有对应文件)
|
||||
# 手动检查并清理
|
||||
```
|
||||
|
||||
## 快速测试
|
||||
|
||||
### 完整功能测试
|
||||
|
||||
```bash
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
### 单项测试
|
||||
|
||||
```bash
|
||||
# 上传
|
||||
curl -X POST "https://amiap.hzau.edu.cn/supa/storage/v1/object/test/file.txt" \
|
||||
-H "apikey: YOUR_KEY" \
|
||||
-H "Authorization: Bearer YOUR_KEY" \
|
||||
-H "Content-Type: text/plain" \
|
||||
-d "test content"
|
||||
|
||||
# 下载
|
||||
curl "https://amiap.hzau.edu.cn/supa/storage/v1/object/test/file.txt" \
|
||||
-H "apikey: YOUR_KEY" \
|
||||
-H "Authorization: Bearer YOUR_KEY"
|
||||
|
||||
# 删除
|
||||
curl -X DELETE "https://amiap.hzau.edu.cn/supa/storage/v1/object/test/file.txt" \
|
||||
-H "apikey: YOUR_KEY" \
|
||||
-H "Authorization: Bearer YOUR_KEY"
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `STORAGE_FILE_BACKEND_MIGRATION.md` - 后端迁移指南
|
||||
- `FINAL_ARCHITECTURE_MINIO_INTERNAL.md` - MinIO 架构
|
||||
- `examples/test_https_storage.py` - 测试脚本
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-12-05
|
||||
**适用版本**: Supabase Storage API v1.29.0
|
||||
17
supabase-stack/docs/_DOCS_SUMMARY.md
Normal file
17
supabase-stack/docs/_DOCS_SUMMARY.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 文档目录
|
||||
|
||||
## 核心文档
|
||||
|
||||
1. **FINAL_ARCHITECTURE_MINIO_INTERNAL.md** - 最终架构说明(MinIO 内网化)
|
||||
2. **MINIO_LOGIN_FIX.md** - MinIO Console 登录问题修复
|
||||
3. **OPERATIONS_GUIDE.md** - 运维指南
|
||||
4. **VUE_API_INTEGRATION.md** - Vue.js 与 Supabase API 集成
|
||||
|
||||
## 快速参考
|
||||
|
||||
- Storage API 测试: `../examples/test_https_storage.py`
|
||||
- MinIO Console: `http://100.64.0.2:9001`
|
||||
- Supabase Dashboard: `http://100.64.0.2:18000`
|
||||
|
||||
---
|
||||
**更新**: 2025-11-23
|
||||
Reference in New Issue
Block a user