Compare commits
10 Commits
b9ee37b8b4
...
84aa601243
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84aa601243 | ||
|
|
4c63a663ac | ||
|
|
7005892795 | ||
|
|
64455e5c7b | ||
|
|
2f5ceec867 | ||
|
|
16afa0d363 | ||
|
|
40384c9deb | ||
|
|
aafa8ebfc9 | ||
|
|
5e2e8a9e6a | ||
|
|
917c7c898c |
47
.env.production.example
Normal file
47
.env.production.example
Normal file
@@ -0,0 +1,47 @@
|
||||
# =============================================================================
|
||||
# 生产环境配置 — 复制为 .env.production 并填入真实值
|
||||
# =============================================================================
|
||||
|
||||
# Domain
|
||||
DOMAIN=makefire.fun
|
||||
|
||||
# Frontend host (用于后端生成邮件链接等)
|
||||
FRONTEND_HOST=https://makefire.fun
|
||||
|
||||
# Environment
|
||||
ENVIRONMENT=production
|
||||
|
||||
PROJECT_NAME="Full Stack FastAPI Project"
|
||||
STACK_NAME=full-stack-fastapi-project
|
||||
|
||||
# Backend
|
||||
BACKEND_CORS_ORIGINS="https://makefire.fun,https://api.makefire.fun"
|
||||
# ⚠️ 必须修改:运行 openssl rand -hex 32 生成
|
||||
SECRET_KEY=changethis
|
||||
FIRST_SUPERUSER=admin@makefire.fun
|
||||
# ⚠️ 必须修改:设置强密码
|
||||
FIRST_SUPERUSER_PASSWORD=changethis
|
||||
|
||||
# Emails (可选,如不需要发送邮件可留空)
|
||||
SMTP_HOST=
|
||||
SMTP_USER=
|
||||
SMTP_PASSWORD=
|
||||
EMAILS_FROM_EMAIL=info@makefire.fun
|
||||
SMTP_TLS=True
|
||||
SMTP_SSL=False
|
||||
SMTP_PORT=587
|
||||
|
||||
# Postgres — 连接 1Panel 已有的 PostgreSQL 容器
|
||||
# 在 Docker 网络 1panel-network 内,主机名为 postgresql
|
||||
POSTGRES_SERVER=postgresql
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=app
|
||||
# ⚠️ 使用已有 PG 的凭据,或为本项目创建专用用户
|
||||
POSTGRES_USER=user_ZPKMQ6
|
||||
POSTGRES_PASSWORD=password_CYmsGt
|
||||
|
||||
SENTRY_DSN=
|
||||
|
||||
# Docker images (本地构建,不需要远程 registry)
|
||||
DOCKER_IMAGE_BACKEND=backend
|
||||
DOCKER_IMAGE_FRONTEND=frontend
|
||||
79
.gitea/workflows/deploy.yml
Normal file
79
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
name: Deploy to Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create .env.production from secrets
|
||||
run: |
|
||||
cat > .env.production << 'ENVEOF'
|
||||
DOMAIN=${{ secrets.DOMAIN }}
|
||||
FRONTEND_HOST=${{ secrets.FRONTEND_HOST }}
|
||||
ENVIRONMENT=production
|
||||
PROJECT_NAME=${{ secrets.PROJECT_NAME }}
|
||||
STACK_NAME=${{ secrets.STACK_NAME }}
|
||||
BACKEND_CORS_ORIGINS=${{ secrets.BACKEND_CORS_ORIGINS }}
|
||||
SECRET_KEY=${{ secrets.SECRET_KEY }}
|
||||
FIRST_SUPERUSER=${{ secrets.FIRST_SUPERUSER }}
|
||||
FIRST_SUPERUSER_PASSWORD=${{ secrets.FIRST_SUPERUSER_PASSWORD }}
|
||||
SMTP_HOST=${{ secrets.SMTP_HOST }}
|
||||
SMTP_USER=${{ secrets.SMTP_USER }}
|
||||
SMTP_PASSWORD=${{ secrets.SMTP_PASSWORD }}
|
||||
EMAILS_FROM_EMAIL=${{ secrets.EMAILS_FROM_EMAIL }}
|
||||
SMTP_TLS=${{ secrets.SMTP_TLS }}
|
||||
SMTP_SSL=${{ secrets.SMTP_SSL }}
|
||||
SMTP_PORT=${{ secrets.SMTP_PORT }}
|
||||
POSTGRES_SERVER=${{ secrets.POSTGRES_SERVER }}
|
||||
POSTGRES_PORT=${{ secrets.POSTGRES_PORT }}
|
||||
POSTGRES_DB=${{ secrets.POSTGRES_DB }}
|
||||
POSTGRES_USER=${{ secrets.POSTGRES_USER }}
|
||||
POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }}
|
||||
SENTRY_DSN=${{ secrets.SENTRY_DSN }}
|
||||
DOCKER_IMAGE_BACKEND=${{ secrets.DOCKER_IMAGE_BACKEND }}
|
||||
DOCKER_IMAGE_FRONTEND=${{ secrets.DOCKER_IMAGE_FRONTEND }}
|
||||
ENVEOF
|
||||
|
||||
- name: Build Docker images
|
||||
run: docker compose -f compose.prod.yml build
|
||||
|
||||
- name: Stop existing services
|
||||
run: docker compose -f compose.prod.yml down --remove-orphans || true
|
||||
|
||||
- name: Start services
|
||||
run: docker compose -f compose.prod.yml up -d
|
||||
|
||||
- name: Wait for backend health check
|
||||
run: |
|
||||
echo "Waiting for backend to be healthy..."
|
||||
for i in $(seq 1 30); do
|
||||
if curl -sf http://127.0.0.1:8000/api/v1/utils/health-check/ > /dev/null 2>&1; then
|
||||
echo "✅ Backend is healthy!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Attempt $i/30 - waiting 10s..."
|
||||
sleep 10
|
||||
done
|
||||
echo "❌ Backend health check failed after 300s"
|
||||
docker compose -f compose.prod.yml logs backend
|
||||
exit 1
|
||||
|
||||
- name: Verify frontend
|
||||
run: |
|
||||
if curl -sf http://127.0.0.1:3001 > /dev/null 2>&1; then
|
||||
echo "✅ Frontend is accessible!"
|
||||
else
|
||||
echo "❌ Frontend is not accessible"
|
||||
docker compose -f compose.prod.yml logs frontend
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Cleanup old Docker images
|
||||
run: docker image prune -f || true
|
||||
6
.github/workflows/playwright.yml
vendored
6
.github/workflows/playwright.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
||||
- run: docker compose down -v --remove-orphans
|
||||
- name: Upload blob report to GitHub Actions Artifacts
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: blob-report-${{ matrix.shardIndex }}
|
||||
path: frontend/blob-report
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: bun ci
|
||||
- name: Download blob reports from GitHub Actions Artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: frontend/all-blob-reports
|
||||
pattern: blob-report-*
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
run: bunx playwright merge-reports --reporter html ./all-blob-reports
|
||||
working-directory: frontend
|
||||
- name: Upload HTML report
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: html-report--attempt-${{ github.run_attempt }}
|
||||
path: frontend/playwright-report
|
||||
|
||||
2
.github/workflows/smokeshow.yml
vendored
2
.github/workflows/smokeshow.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- run: pip install smokeshow
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: coverage-html
|
||||
path: backend/htmlcov
|
||||
|
||||
2
.github/workflows/test-backend.yml
vendored
2
.github/workflows/test-backend.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
working-directory: backend
|
||||
- run: docker compose down -v --remove-orphans
|
||||
- name: Store coverage files
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverage-html
|
||||
path: backend/htmlcov
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,3 +5,6 @@ node_modules/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
.DS_Store
|
||||
.env.production
|
||||
.venv/
|
||||
|
||||
@@ -42,4 +42,4 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
|
||||
WORKDIR /app/backend/
|
||||
|
||||
CMD ["fastapi", "run", "--workers", "4", "app/main.py"]
|
||||
CMD ["fastapi", "run", "--workers", "2", "app/main.py"]
|
||||
|
||||
26
bun.lock
26
bun.lock
@@ -25,7 +25,7 @@
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@tanstack/react-query-devtools": "^5.91.1",
|
||||
"@tanstack/react-router": "^1.157.3",
|
||||
"@tanstack/react-router": "^1.163.3",
|
||||
"@tanstack/react-router-devtools": "^1.163.3",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"axios": "1.13.5",
|
||||
@@ -388,7 +388,7 @@
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
|
||||
|
||||
"@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="],
|
||||
"@tanstack/history": ["@tanstack/history@1.161.4", "", {}, "sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww=="],
|
||||
|
||||
"@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="],
|
||||
|
||||
@@ -398,11 +398,11 @@
|
||||
|
||||
"@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.91.2", "", { "dependencies": { "@tanstack/query-devtools": "5.92.0" }, "peerDependencies": { "@tanstack/react-query": "^5.90.14", "react": "^18 || ^19" } }, "sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg=="],
|
||||
|
||||
"@tanstack/react-router": ["@tanstack/react-router@1.157.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.157.3", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-nrshpAAtYRWnvJeTwItA8WwDr5oX5zOvxxcFEWIdsscLHkKsK9ED9byV4d8VfCRey+W02blBxsCKpppJfq2rnQ=="],
|
||||
"@tanstack/react-router": ["@tanstack/react-router@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/react-store": "^0.9.1", "@tanstack/router-core": "1.163.3", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-hheBbFVb+PbxtrWp8iy6+TTRTbhx3Pn6hKo8Tv/sWlG89ZMcD1xpQWzx8ukHN9K8YWbh5rdzt4kv6u8X4kB28Q=="],
|
||||
|
||||
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.163.3", "", { "dependencies": { "@tanstack/router-devtools-core": "1.163.3" }, "peerDependencies": { "@tanstack/react-router": "^1.163.3", "@tanstack/router-core": "^1.163.3", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-42VMkV/2Z8ro7xzblPBRNZIEmCNXMzm2jD68G52p2qhjXm38wGpg46qneAESN9FtTQeVWk5aSXs47/jt7lkzmw=="],
|
||||
|
||||
"@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="],
|
||||
"@tanstack/react-store": ["@tanstack/react-store@0.9.1", "", { "dependencies": { "@tanstack/store": "0.9.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-YzJLnRvy5lIEFTLWBAZmcOjK3+2AepnBv/sr6NZmiqJvq7zTQggyK99Gw8fqYdMdHPQWXjz0epFKJXC+9V2xDA=="],
|
||||
|
||||
"@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="],
|
||||
|
||||
@@ -864,13 +864,17 @@
|
||||
|
||||
"@tailwindcss/vite/tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
|
||||
|
||||
"@tanstack/react-router/@tanstack/router-core": ["@tanstack/router-core@1.157.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-r2KY/UWC4Ocxx05G7b/tLNQ7ZGX7URvA5H5P1cNbkFmi77VbOgtbW0sfz9/+9Dyh6aqHVK/Bx5kuR5jojNvrHQ=="],
|
||||
"@tanstack/react-router/@tanstack/router-core": ["@tanstack/router-core@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-jPptiGq/w3nuPzcMC7RNa79aU+b6OjaDzWJnBcV2UAwL4ThJamRS4h42TdhJE+oF5yH9IEnCOGQdfnbw45LbfA=="],
|
||||
|
||||
"@tanstack/react-router-devtools/@tanstack/router-core": ["@tanstack/router-core@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-jPptiGq/w3nuPzcMC7RNa79aU+b6OjaDzWJnBcV2UAwL4ThJamRS4h42TdhJE+oF5yH9IEnCOGQdfnbw45LbfA=="],
|
||||
|
||||
"@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="],
|
||||
|
||||
"@tanstack/router-core/@tanstack/history": ["@tanstack/history@1.153.2", "", {}, "sha512-TVa0Wju5w6JZGq/S74Q7TQNtKXDatJaB4NYrhMZVU9ETlkgpr35NhDfOzsCJ93P0KCo1ZoDodlFp3c54/dLsyw=="],
|
||||
|
||||
"@tanstack/router-devtools/@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.157.17", "", { "dependencies": { "@tanstack/router-devtools-core": "1.157.16" }, "peerDependencies": { "@tanstack/react-router": "^1.157.17", "@tanstack/router-core": "^1.157.16", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-ajhTEQMPK9XtgVN7KqLy9JobYbyjcbuZXc76kABA8HeUJqB98rvwdpVuB106LReeIKuTc5RLOgCrdkq2A19wpg=="],
|
||||
|
||||
"@tanstack/router-devtools-core/@tanstack/router-core": ["@tanstack/router-core@1.157.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-r2KY/UWC4Ocxx05G7b/tLNQ7ZGX7URvA5H5P1cNbkFmi77VbOgtbW0sfz9/+9Dyh6aqHVK/Bx5kuR5jojNvrHQ=="],
|
||||
"@tanstack/router-devtools-core/@tanstack/router-core": ["@tanstack/router-core@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-jPptiGq/w3nuPzcMC7RNa79aU+b6OjaDzWJnBcV2UAwL4ThJamRS4h42TdhJE+oF5yH9IEnCOGQdfnbw45LbfA=="],
|
||||
|
||||
"@tanstack/router-generator/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
@@ -928,10 +932,18 @@
|
||||
|
||||
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@tanstack/react-router-devtools/@tanstack/router-core/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="],
|
||||
|
||||
"@tanstack/react-router/@tanstack/router-core/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="],
|
||||
|
||||
"@tanstack/router-devtools-core/@tanstack/router-core/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="],
|
||||
|
||||
"@tanstack/router-devtools/@tanstack/react-router-devtools/@tanstack/router-core": ["@tanstack/router-core@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-jPptiGq/w3nuPzcMC7RNa79aU+b6OjaDzWJnBcV2UAwL4ThJamRS4h42TdhJE+oF5yH9IEnCOGQdfnbw45LbfA=="],
|
||||
|
||||
"@tanstack/router-devtools/@tanstack/react-router-devtools/@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.157.16", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.157.16", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-XBJTs/kMZYK6J2zhbGucHNuypwDB1t2vi8K5To+V6dUnLGBEyfQTf01fegiF4rpL1yXgomdGnP6aTiOFgldbVg=="],
|
||||
|
||||
"c12/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"@tanstack/router-devtools/@tanstack/react-router-devtools/@tanstack/router-devtools-core/@tanstack/router-core": ["@tanstack/router-core@1.157.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-r2KY/UWC4Ocxx05G7b/tLNQ7ZGX7URvA5H5P1cNbkFmi77VbOgtbW0sfz9/+9Dyh6aqHVK/Bx5kuR5jojNvrHQ=="],
|
||||
"@tanstack/router-devtools/@tanstack/react-router-devtools/@tanstack/router-core/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="],
|
||||
}
|
||||
}
|
||||
|
||||
89
compose.prod.yml
Normal file
89
compose.prod.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
services:
|
||||
|
||||
prestart:
|
||||
image: '${DOCKER_IMAGE_BACKEND?Variable not set}:${TAG-latest}'
|
||||
build:
|
||||
context: .
|
||||
dockerfile: backend/Dockerfile
|
||||
networks:
|
||||
- 1panel-network
|
||||
command: bash scripts/prestart.sh
|
||||
env_file:
|
||||
- .env.production
|
||||
environment:
|
||||
- DOMAIN=${DOMAIN}
|
||||
- FRONTEND_HOST=${FRONTEND_HOST?Variable not set}
|
||||
- ENVIRONMENT=${ENVIRONMENT}
|
||||
- BACKEND_CORS_ORIGINS=${BACKEND_CORS_ORIGINS}
|
||||
- SECRET_KEY=${SECRET_KEY?Variable not set}
|
||||
- FIRST_SUPERUSER=${FIRST_SUPERUSER?Variable not set}
|
||||
- FIRST_SUPERUSER_PASSWORD=${FIRST_SUPERUSER_PASSWORD?Variable not set}
|
||||
- SMTP_HOST=${SMTP_HOST}
|
||||
- SMTP_USER=${SMTP_USER}
|
||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||
- EMAILS_FROM_EMAIL=${EMAILS_FROM_EMAIL}
|
||||
- POSTGRES_SERVER=${POSTGRES_SERVER}
|
||||
- POSTGRES_PORT=${POSTGRES_PORT}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
- POSTGRES_USER=${POSTGRES_USER?Variable not set}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set}
|
||||
- SENTRY_DSN=${SENTRY_DSN}
|
||||
|
||||
backend:
|
||||
image: '${DOCKER_IMAGE_BACKEND?Variable not set}:${TAG-latest}'
|
||||
restart: always
|
||||
networks:
|
||||
- 1panel-network
|
||||
depends_on:
|
||||
prestart:
|
||||
condition: service_completed_successfully
|
||||
ports:
|
||||
- "127.0.0.1:8000:8000"
|
||||
env_file:
|
||||
- .env.production
|
||||
environment:
|
||||
- DOMAIN=${DOMAIN}
|
||||
- FRONTEND_HOST=${FRONTEND_HOST?Variable not set}
|
||||
- ENVIRONMENT=${ENVIRONMENT}
|
||||
- BACKEND_CORS_ORIGINS=${BACKEND_CORS_ORIGINS}
|
||||
- SECRET_KEY=${SECRET_KEY?Variable not set}
|
||||
- FIRST_SUPERUSER=${FIRST_SUPERUSER?Variable not set}
|
||||
- FIRST_SUPERUSER_PASSWORD=${FIRST_SUPERUSER_PASSWORD?Variable not set}
|
||||
- SMTP_HOST=${SMTP_HOST}
|
||||
- SMTP_USER=${SMTP_USER}
|
||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||
- EMAILS_FROM_EMAIL=${EMAILS_FROM_EMAIL}
|
||||
- POSTGRES_SERVER=${POSTGRES_SERVER}
|
||||
- POSTGRES_PORT=${POSTGRES_PORT}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
- POSTGRES_USER=${POSTGRES_USER?Variable not set}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set}
|
||||
- SENTRY_DSN=${SENTRY_DSN}
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/utils/health-check/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
build:
|
||||
context: .
|
||||
dockerfile: backend/Dockerfile
|
||||
|
||||
frontend:
|
||||
image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
|
||||
restart: always
|
||||
networks:
|
||||
- 1panel-network
|
||||
ports:
|
||||
- "127.0.0.1:3001:80"
|
||||
build:
|
||||
context: .
|
||||
dockerfile: frontend/Dockerfile
|
||||
args:
|
||||
- VITE_API_URL=https://api.${DOMAIN?Variable not set}
|
||||
- NODE_ENV=production
|
||||
|
||||
networks:
|
||||
1panel-network:
|
||||
external: true
|
||||
452
deploy-tencent.md
Normal file
452
deploy-tencent.md
Normal file
@@ -0,0 +1,452 @@
|
||||
# 部署指南:腾讯云 + 1Panel + OpenResty + Gitea CI/CD
|
||||
|
||||
## 目录
|
||||
|
||||
1. [架构概览](#1-架构概览)
|
||||
2. [服务器准备](#2-服务器准备)
|
||||
3. [配置环境变量](#3-配置环境变量)
|
||||
4. [创建数据库](#4-创建数据库)
|
||||
5. [手动首次部署](#5-手动首次部署)
|
||||
6. [在 1Panel 中配置 OpenResty](#6-在-1panel-中配置-openresty)
|
||||
7. [DNS 解析配置](#7-dns-解析配置)
|
||||
8. [配置 Gitea Actions CI/CD](#8-配置-gitea-actions-cicd)
|
||||
9. [验证部署](#9-验证部署)
|
||||
10. [日常运维](#10-日常运维)
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构概览
|
||||
|
||||
```
|
||||
用户浏览器
|
||||
│
|
||||
▼
|
||||
OpenResty (1Panel 管理, SSL, 端口 80/443)
|
||||
│
|
||||
├── makefire.fun → 127.0.0.1:3001 (Frontend Nginx 容器)
|
||||
└── api.makefire.fun → 127.0.0.1:8000 (Backend FastAPI 容器)
|
||||
│
|
||||
▼
|
||||
PostgreSQL (1Panel 已有容器, 1panel-network)
|
||||
```
|
||||
|
||||
**关键设计决策:**
|
||||
- 后端和前端容器只绑定 `127.0.0.1`,不对外暴露,由 OpenResty 统一反代
|
||||
- 所有容器加入 `1panel-network`,可直接通过 `postgresql` 主机名访问已有数据库
|
||||
- 不使用 Traefik(用 1Panel 自带的 OpenResty 替代)
|
||||
- 不启动独立 PostgreSQL 容器(复用已有的)
|
||||
|
||||
---
|
||||
|
||||
## 2. 服务器准备
|
||||
|
||||
### 2.1 创建部署目录
|
||||
|
||||
```bash
|
||||
# SSH 登录服务器后执行
|
||||
sudo mkdir -p /opt/fastapi-app
|
||||
sudo chown $USER:$USER /opt/fastapi-app
|
||||
```
|
||||
|
||||
### 2.2 初始化 Git 仓库(在 Gitea 上)
|
||||
|
||||
1. 登录 Gitea(`http://your-server-ip:3000`)
|
||||
2. 创建新仓库,例如 `full-stack-fastapi`
|
||||
3. 在本地开发机上添加 Gitea 远程仓库:
|
||||
|
||||
```bash
|
||||
cd /Users/weifeng/Workspace/full-stack-fastapi-template
|
||||
|
||||
# 添加 Gitea 远程
|
||||
git remote add gitea http://your-server-ip:3000/your-username/full-stack-fastapi.git
|
||||
|
||||
# 推送代码
|
||||
git push gitea main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 配置环境变量
|
||||
|
||||
### 3.1 在服务器上创建生产环境文件
|
||||
|
||||
```bash
|
||||
cd /opt/fastapi-app
|
||||
|
||||
# 复制示例文件(首次需要从代码仓库获取)
|
||||
cp .env.production.example .env.production
|
||||
```
|
||||
|
||||
### 3.2 修改关键配置
|
||||
|
||||
```bash
|
||||
nano .env.production
|
||||
```
|
||||
|
||||
**必须修改的项:**
|
||||
|
||||
```bash
|
||||
# 生成强随机密钥
|
||||
SECRET_KEY=$(openssl rand -hex 32)
|
||||
echo "生成的 SECRET_KEY: $SECRET_KEY"
|
||||
|
||||
# 设置强管理员密码
|
||||
FIRST_SUPERUSER_PASSWORD=你的强密码
|
||||
```
|
||||
|
||||
> ⚠️ `SECRET_KEY` 和 `FIRST_SUPERUSER_PASSWORD` 不能使用默认值 `changethis`,否则生产环境会报错。
|
||||
|
||||
---
|
||||
|
||||
## 4. 创建数据库
|
||||
|
||||
在已有的 PostgreSQL 中为本项目创建专用数据库:
|
||||
|
||||
```bash
|
||||
# 方法一:使用 docker exec
|
||||
docker exec -it 1Panel-postgresql-bxrK psql -U user_ZPKMQ6 -c "CREATE DATABASE app;"
|
||||
|
||||
# 验证数据库是否创建成功
|
||||
docker exec -it 1Panel-postgresql-bxrK psql -U user_ZPKMQ6 -c "\l" | grep app
|
||||
```
|
||||
|
||||
如果你想创建专用用户(更安全,可选):
|
||||
|
||||
```bash
|
||||
docker exec -it 1Panel-postgresql-bxrK psql -U user_ZPKMQ6 -c "
|
||||
CREATE USER fastapi_user WITH PASSWORD 'your_strong_password';
|
||||
GRANT ALL PRIVILEGES ON DATABASE app TO fastapi_user;
|
||||
ALTER DATABASE app OWNER TO fastapi_user;
|
||||
"
|
||||
```
|
||||
|
||||
> 如果使用专用用户,记得更新 `.env.production` 中的 `POSTGRES_USER` 和 `POSTGRES_PASSWORD`。
|
||||
|
||||
---
|
||||
|
||||
## 5. 手动首次部署
|
||||
|
||||
### 5.1 克隆代码到服务器
|
||||
|
||||
```bash
|
||||
cd /opt/fastapi-app
|
||||
git clone http://localhost:3000/your-username/full-stack-fastapi.git .
|
||||
# 或者如果已经有代码
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
### 5.2 复制环境变量文件
|
||||
|
||||
确保 `.env.production` 在 `/opt/fastapi-app/` 目录下。
|
||||
|
||||
### 5.3 构建和启动
|
||||
|
||||
```bash
|
||||
cd /opt/fastapi-app
|
||||
|
||||
# 构建镜像
|
||||
docker compose -f compose.prod.yml build
|
||||
|
||||
# 启动服务
|
||||
docker compose -f compose.prod.yml up -d
|
||||
|
||||
# 查看日志
|
||||
docker compose -f compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
### 5.4 验证容器状态
|
||||
|
||||
```bash
|
||||
# 查看运行状态
|
||||
docker compose -f compose.prod.yml ps
|
||||
|
||||
# 测试后端
|
||||
curl http://127.0.0.1:8000/api/v1/utils/health-check/
|
||||
|
||||
# 测试前端
|
||||
curl -I http://127.0.0.1:3001
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 在 1Panel 中配置 OpenResty
|
||||
|
||||
### 6.1 创建前端网站
|
||||
|
||||
1. 打开 1Panel → **网站** → **创建网站**
|
||||
2. 选择 **反向代理**
|
||||
3. 配置:
|
||||
- **主域名**: `makefire.fun`
|
||||
- **代理地址**: `http://127.0.0.1:3001`
|
||||
4. 点击创建
|
||||
|
||||
### 6.2 创建后端 API 网站
|
||||
|
||||
1. **网站** → **创建网站** → **反向代理**
|
||||
2. 配置:
|
||||
- **主域名**: `api.makefire.fun`
|
||||
- **代理地址**: `http://127.0.0.1:8000`
|
||||
3. 点击创建
|
||||
|
||||
### 6.3 配置 SSL 证书
|
||||
|
||||
对每个网站:
|
||||
|
||||
1. 点击网站名称进入设置
|
||||
2. 选择 **HTTPS** 标签
|
||||
3. 选择 **申请证书** → **Let's Encrypt**
|
||||
4. 勾选 **自动续签**
|
||||
5. 勾选 **HTTP → HTTPS 强制跳转**
|
||||
|
||||
### 6.4 修改后端网站配置(可选优化)
|
||||
|
||||
进入 `api.makefire.fun` 网站设置 → **配置文件**,在 `location /` 块中添加:
|
||||
|
||||
```nginx
|
||||
# WebSocket 支持
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# 请求体大小限制
|
||||
client_max_body_size 10m;
|
||||
|
||||
# 超时
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
```
|
||||
|
||||
> 完整参考配置见项目根目录的 `openresty-example.conf`。
|
||||
|
||||
---
|
||||
|
||||
## 7. DNS 解析配置
|
||||
|
||||
在你的域名 DNS 管理处(腾讯云 DNS 或其他)添加:
|
||||
|
||||
| 记录类型 | 主机记录 | 记录值 | TTL |
|
||||
|---------|---------|--------|-----|
|
||||
| A | @ | 你的服务器 IP | 600 |
|
||||
| A | api | 你的服务器 IP | 600 |
|
||||
|
||||
> 如果使用腾讯云域名,进入 **DNS 解析 DNSPod** 配置。
|
||||
|
||||
---
|
||||
|
||||
## 8. 配置 Gitea Actions CI/CD
|
||||
|
||||
### 8.1 安装 Gitea Actions Runner
|
||||
|
||||
```bash
|
||||
# 1. 下载 Gitea Actions Runner
|
||||
# 访问 https://gitea.com/gitea/act_runner/releases 获取最新版本
|
||||
wget https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
|
||||
chmod +x act_runner-0.2.11-linux-amd64
|
||||
sudo mv act_runner-0.2.11-linux-amd64 /usr/local/bin/act_runner
|
||||
|
||||
# 2. 生成配置文件
|
||||
cd /opt
|
||||
act_runner generate-config > act_runner_config.yaml
|
||||
```
|
||||
|
||||
### 8.2 修改 Runner 配置
|
||||
|
||||
编辑 `/opt/act_runner_config.yaml`,关键修改:
|
||||
|
||||
```yaml
|
||||
runner:
|
||||
# 标签,决定 workflow 中 runs-on 可以匹配的值
|
||||
labels:
|
||||
- "ubuntu-latest:host"
|
||||
# ↑ 使用 host 模式,直接在服务器上运行(不在 Docker 中套 Docker)
|
||||
```
|
||||
|
||||
> **为什么用 `host` 模式?** 因为 workflow 需要执行 `docker compose` 命令来管理服务器上的容器。若在容器中运行,需要额外配置 Docker-in-Docker,对低内存服务器更加不友好。
|
||||
|
||||
### 8.3 注册 Runner
|
||||
|
||||
```bash
|
||||
# 1. 在 Gitea 中获取 Runner Token
|
||||
# 进入仓库 → Settings → Actions → Runners → 点击 "Create new runner"
|
||||
# 复制显示的 Token
|
||||
|
||||
# 2. 注册
|
||||
act_runner register \
|
||||
--instance http://localhost:3000 \
|
||||
--token YOUR_RUNNER_TOKEN \
|
||||
--name my-runner \
|
||||
--labels "ubuntu-latest:host" \
|
||||
--config /opt/act_runner_config.yaml \
|
||||
--no-interactive
|
||||
|
||||
# 3. 启动(测试)
|
||||
act_runner daemon --config /opt/act_runner_config.yaml
|
||||
```
|
||||
|
||||
### 8.4 设置为系统服务(推荐)
|
||||
|
||||
```bash
|
||||
sudo tee /etc/systemd/system/gitea-runner.service << 'EOF'
|
||||
[Unit]
|
||||
Description=Gitea Actions Runner
|
||||
After=network.target docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/fastapi-app
|
||||
ExecStart=/usr/local/bin/act_runner daemon --config /opt/act_runner_config.yaml
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable gitea-runner
|
||||
sudo systemctl start gitea-runner
|
||||
|
||||
# 查看状态
|
||||
sudo systemctl status gitea-runner
|
||||
```
|
||||
|
||||
### 8.5 配置 Gitea Secrets
|
||||
|
||||
在 Gitea 仓库中配置环境变量密钥:
|
||||
|
||||
1. 进入仓库 → **Settings** → **Actions** → **Secrets**
|
||||
2. 添加以下 Secrets:
|
||||
|
||||
| Secret 名称 | 值 |
|
||||
|-------------|-----|
|
||||
| `DOMAIN` | `makefire.fun` |
|
||||
| `FRONTEND_HOST` | `https://makefire.fun` |
|
||||
| `PROJECT_NAME` | `Full Stack FastAPI Project` |
|
||||
| `STACK_NAME` | `full-stack-fastapi-project` |
|
||||
| `BACKEND_CORS_ORIGINS` | `https://makefire.fun,https://api.makefire.fun` |
|
||||
| `SECRET_KEY` | *(用 `openssl rand -hex 32` 生成)* |
|
||||
| `FIRST_SUPERUSER` | `admin@makefire.fun` |
|
||||
| `FIRST_SUPERUSER_PASSWORD` | *(你的强密码)* |
|
||||
| `SMTP_HOST` | *(留空或填写)* |
|
||||
| `SMTP_USER` | *(留空或填写)* |
|
||||
| `SMTP_PASSWORD` | *(留空或填写)* |
|
||||
| `EMAILS_FROM_EMAIL` | `info@makefire.fun` |
|
||||
| `SMTP_TLS` | `True` |
|
||||
| `SMTP_SSL` | `False` |
|
||||
| `SMTP_PORT` | `587` |
|
||||
| `POSTGRES_SERVER` | `postgresql` |
|
||||
| `POSTGRES_PORT` | `5432` |
|
||||
| `POSTGRES_DB` | `app` |
|
||||
| `POSTGRES_USER` | `user_ZPKMQ6` |
|
||||
| `POSTGRES_PASSWORD` | `password_CYmsGt` |
|
||||
| `SENTRY_DSN` | *(留空)* |
|
||||
| `DOCKER_IMAGE_BACKEND` | `backend` |
|
||||
| `DOCKER_IMAGE_FRONTEND` | `frontend` |
|
||||
|
||||
### 8.6 启用 Gitea Actions
|
||||
|
||||
1. 进入仓库 → **Settings** → **Repository**
|
||||
2. 确保 **Actions** 功能已启用
|
||||
3. 如果 Gitea 全局未启用 Actions,需要在 Gitea 配置文件中添加:
|
||||
|
||||
```ini
|
||||
; 在 /opt/1panel/apps/gitea/gitea/data/gitea/conf/app.ini 中
|
||||
[actions]
|
||||
ENABLED = true
|
||||
```
|
||||
|
||||
修改后重启 Gitea 容器:
|
||||
|
||||
```bash
|
||||
docker restart 1Panel-gitea-FSXv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 验证部署
|
||||
|
||||
### 9.1 本地访问测试
|
||||
|
||||
```bash
|
||||
# 后端健康检查
|
||||
curl http://127.0.0.1:8000/api/v1/utils/health-check/
|
||||
|
||||
# 前端页面
|
||||
curl -I http://127.0.0.1:3001
|
||||
```
|
||||
|
||||
### 9.2 域名访问测试
|
||||
|
||||
```bash
|
||||
# 前端
|
||||
curl -I https://makefire.fun
|
||||
|
||||
# 后端 API 文档
|
||||
curl -I https://api.makefire.fun/docs
|
||||
|
||||
# 后端健康检查
|
||||
curl https://api.makefire.fun/api/v1/utils/health-check/
|
||||
```
|
||||
|
||||
### 9.3 CI/CD 测试
|
||||
|
||||
```bash
|
||||
# 在本地开发机上
|
||||
cd /Users/weifeng/Workspace/full-stack-fastapi-template
|
||||
echo "# test" >> README.md
|
||||
git add .
|
||||
git commit -m "test: trigger CI/CD"
|
||||
git push gitea main
|
||||
```
|
||||
|
||||
然后在 Gitea 仓库的 **Actions** 标签中查看运行状态。
|
||||
|
||||
---
|
||||
|
||||
## 10. 日常运维
|
||||
|
||||
### 查看日志
|
||||
|
||||
```bash
|
||||
cd /opt/fastapi-app
|
||||
docker compose -f compose.prod.yml logs -f backend # 后端日志
|
||||
docker compose -f compose.prod.yml logs -f frontend # 前端日志
|
||||
docker compose -f compose.prod.yml logs -f # 全部日志
|
||||
```
|
||||
|
||||
### 重启服务
|
||||
|
||||
```bash
|
||||
docker compose -f compose.prod.yml restart backend
|
||||
docker compose -f compose.prod.yml restart frontend
|
||||
```
|
||||
|
||||
### 手动重新部署
|
||||
|
||||
```bash
|
||||
cd /opt/fastapi-app
|
||||
git pull origin main
|
||||
docker compose -f compose.prod.yml build
|
||||
docker compose -f compose.prod.yml down
|
||||
docker compose -f compose.prod.yml up -d
|
||||
```
|
||||
|
||||
### 清理 Docker 资源
|
||||
|
||||
```bash
|
||||
# 清理无用镜像(释放磁盘空间)
|
||||
docker image prune -f
|
||||
docker system prune -f
|
||||
```
|
||||
|
||||
### 数据库备份
|
||||
|
||||
```bash
|
||||
# 备份
|
||||
docker exec 1Panel-postgresql-bxrK pg_dump -U user_ZPKMQ6 app > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# 恢复
|
||||
docker exec -i 1Panel-postgresql-bxrK psql -U user_ZPKMQ6 app < backup_20260311.sql
|
||||
```
|
||||
@@ -29,7 +29,7 @@
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@tanstack/react-query-devtools": "^5.91.1",
|
||||
"@tanstack/react-router": "^1.157.3",
|
||||
"@tanstack/react-router": "^1.163.3",
|
||||
"@tanstack/react-router-devtools": "^1.163.3",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"axios": "1.13.5",
|
||||
|
||||
111
openresty-example.conf
Normal file
111
openresty-example.conf
Normal file
@@ -0,0 +1,111 @@
|
||||
# =============================================================================
|
||||
# OpenResty / Nginx 反向代理配置示例
|
||||
# 此文件仅供参考,实际配置在 1Panel 网站管理中完成
|
||||
# =============================================================================
|
||||
#
|
||||
# 在 1Panel 中需要创建 2 个网站:
|
||||
# 1. makefire.fun → 前端
|
||||
# 2. api.makefire.fun → 后端 API
|
||||
#
|
||||
# 两个网站都需要:
|
||||
# - 开启 SSL (1Panel 可自动申请 Let's Encrypt 证书)
|
||||
# - 开启 HTTP → HTTPS 强制跳转
|
||||
#
|
||||
# 以下是每个网站的反向代理配置内容:
|
||||
|
||||
# =============================================
|
||||
# 网站 1: makefire.fun (前端)
|
||||
# =============================================
|
||||
# 在 1Panel 中: 网站 → 创建网站 → 反向代理
|
||||
# 代理地址: http://127.0.0.1:3001
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl http2;
|
||||
server_name makefire.fun;
|
||||
|
||||
# SSL 证书 (由 1Panel 自动管理,以下路径仅为示例)
|
||||
# ssl_certificate /path/to/cert.pem;
|
||||
# ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
# HTTP → HTTPS 跳转
|
||||
if ($scheme = http) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# 前端反向代理
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SPA 路由支持 — 当后端 nginx 返回 404 时,由前端处理
|
||||
proxy_intercept_errors on;
|
||||
error_page 404 = /index.html;
|
||||
}
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://127.0.0.1:3001;
|
||||
proxy_set_header Host $host;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
}
|
||||
|
||||
# =============================================
|
||||
# 网站 2: api.makefire.fun (后端 API)
|
||||
# =============================================
|
||||
# 在 1Panel 中: 网站 → 创建网站 → 反向代理
|
||||
# 代理地址: http://127.0.0.1:8000
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl http2;
|
||||
server_name api.makefire.fun;
|
||||
|
||||
# SSL 证书 (由 1Panel 自动管理)
|
||||
# ssl_certificate /path/to/cert.pem;
|
||||
# ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
# HTTP → HTTPS 跳转
|
||||
if ($scheme = http) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# API 反向代理
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket 支持 (如后续需要)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# 超时设置
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# 请求体大小限制 (文件上传等)
|
||||
client_max_body_size 10m;
|
||||
}
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
}
|
||||
@@ -17,6 +17,12 @@
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆ Bump actions/download-artifact from 7 to 8. PR [#2208](https://github.com/fastapi/full-stack-fastapi-template/pull/2208) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/upload-artifact from 6 to 7. PR [#2207](https://github.com/fastapi/full-stack-fastapi-template/pull/2207) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump @tanstack/react-router from 1.157.3 to 1.163.3. PR [#2215](https://github.com/fastapi/full-stack-fastapi-template/pull/2215) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump @tanstack/react-router-devtools from 1.159.10 to 1.163.3. PR [#2212](https://github.com/fastapi/full-stack-fastapi-template/pull/2212) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump @tanstack/react-query from 5.90.20 to 5.90.21. PR [#2213](https://github.com/fastapi/full-stack-fastapi-template/pull/2213) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump @types/node from 25.1.0 to 25.3.2. PR [#2214](https://github.com/fastapi/full-stack-fastapi-template/pull/2214) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump tailwindcss from 4.1.18 to 4.2.0. PR [#2198](https://github.com/fastapi/full-stack-fastapi-template/pull/2198) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump axios from 1.13.4 to 1.13.5. PR [#2199](https://github.com/fastapi/full-stack-fastapi-template/pull/2199) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump @vitejs/plugin-react-swc from 4.2.2 to 4.2.3. PR [#2200](https://github.com/fastapi/full-stack-fastapi-template/pull/2200) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
Reference in New Issue
Block a user