PersonalWebApplication/docs/superpowers/plans/2026-06-18-deploy.md

319 lines
10 KiB
Markdown
Raw Permalink Normal View History

# InternetProject Deployment Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Deploy the React + Rust full-stack app to `root@8.130.143.54`, accessible at `http://8.130.143.54:8548`.
**Architecture:** Rust binary (`RustServer`) serves both the REST API and React static files from a single process. React is built locally, Rust is cross-compiled in WSL, both artifacts are uploaded via scp and started with nohup.
**Tech Stack:** React 19 + Vite 8 (frontend), Rust + Axum 0.8 (backend), Ubuntu 22.04 (server), WSL2 mirrored network (build env)
## Global Constraints
- Server: `root@8.130.143.54`, Ubuntu 22.04, x86_64
- Deploy path: `/opt/internet-project/` on server
- Static files served from: `/opt/internet-project/static/`
- Port: `8548` (via `PORT=8548` env var at runtime)
- WSL mirrored network + `autoProxy=true` — no manual proxy config needed
- `main.rs` already updated to read `PORT` env var (default `8080`)
- Do NOT install any toolchain on the remote server
---
### Task 1: Build React Frontend
**Files:**
- Build: `Client/``Client/dist/`
**Interfaces:**
- Produces: `Client/dist/index.html` + `Client/dist/assets/*` (consumed by Task 3)
- [ ] **Step 1: Install dependencies (if not already installed)**
Run in PowerShell from `F:\Code\InternetProject\Client`:
```powershell
npm install
```
Expected: `node_modules/` populated, no errors.
- [ ] **Step 2: Build the frontend**
```powershell
npm run build
```
Expected output ends with something like:
```
dist/index.html x.xx kB
dist/assets/index-[hash].js xxx.xx kB
✓ built in x.xxs
```
- [ ] **Step 3: Verify dist output**
```powershell
Get-ChildItem Client\dist
```
Expected: `index.html`, `assets/`, `favicon.svg`, `icons.svg` present.
- [ ] **Step 4: Commit the main.rs port change**
```powershell
git add Server/src/main.rs
git commit -m "feat: read PORT from env var, default 8080"
```
---
### Task 2: Build Rust Binary in WSL
**Files:**
- Build: `Server/``Server/target/release/RustServer`
**Interfaces:**
- Produces: `/mnt/f/Code/InternetProject/Server/target/release/RustServer` — Linux x86_64 ELF binary (consumed by Task 3)
- [ ] **Step 1: Open WSL and navigate to project**
In a WSL terminal:
```bash
cd /mnt/f/Code/InternetProject/Server
```
- [ ] **Step 2: Check Rust toolchain is installed**
```bash
rustc --version
```
If not installed:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
```
Expected: `rustc 1.xx.x (...)` printed.
- [ ] **Step 3: Build release binary**
```bash
cargo build --release
```
First build takes 25 minutes (downloads + compiles dependencies). Expected final line:
```
Finished `release` profile [optimized] target(s) in Xs
```
- [ ] **Step 4: Verify binary exists and is Linux ELF**
```bash
file target/release/RustServer
```
Expected:
```
target/release/RustServer: ELF 64-bit LSB pie executable, x86-64, ...
```
---
### Task 3: Upload Artifacts to Server
**Files:**
- Remote create: `/opt/internet-project/` (directory)
- Remote create: `/opt/internet-project/RustServer` (binary)
- Remote create: `/opt/internet-project/static/` (frontend files)
**Interfaces:**
- Consumes: `Server/target/release/RustServer` (from Task 2), `Client/dist/*` (from Task 1)
- Produces: server-side deploy directory ready to run (consumed by Task 4)
- [ ] **Step 1: Create deploy directory on server**
Run in WSL:
```bash
ssh root@8.130.143.54 "mkdir -p /opt/internet-project/static"
```
Expected: no output, exit 0.
- [ ] **Step 2: Upload the Rust binary**
```bash
scp /mnt/f/Code/InternetProject/Server/target/release/RustServer \
root@8.130.143.54:/opt/internet-project/RustServer
```
Expected: progress bar, then returns to prompt.
- [ ] **Step 3: Upload frontend static files**
```bash
scp -r /mnt/f/Code/InternetProject/Client/dist/* \
root@8.130.143.54:/opt/internet-project/static/
```
Expected: multiple files transferred (index.html, assets/, etc.).
- [ ] **Step 4: Make binary executable**
```bash
ssh root@8.130.143.54 "chmod +x /opt/internet-project/RustServer"
```
- [ ] **Step 5: Verify remote layout**
```bash
ssh root@8.130.143.54 "ls -lh /opt/internet-project/ && ls /opt/internet-project/static/"
```
Expected:
```
total XX
-rwxr-xr-x 1 root root XXM ... RustServer
drwxr-xr-x 2 root root ... static/
assets favicon.svg icons.svg index.html
```
---
### Task 4: Start the Server and Verify
**Files:**
- Remote: `/opt/internet-project/server.log` (created on start)
**Interfaces:**
- Consumes: deploy directory from Task 3
- Produces: running service at `http://8.130.143.54:8548`
- [ ] **Step 1: Start server with nohup**
```bash
ssh root@8.130.143.54 "cd /opt/internet-project && nohup PORT=8548 ./RustServer > server.log 2>&1 &"
```
Expected: no output (background process started).
- [ ] **Step 2: Check server started successfully**
```bash
ssh root@8.130.143.54 "sleep 1 && cat /opt/internet-project/server.log"
```
Expected:
```
backend listening on http://0.0.0.0:8548
```
- [ ] **Step 3: Verify API endpoint responds**
```bash
curl http://8.130.143.54:8548/api/client/health
```
Expected: HTTP 200 with a JSON response (or empty 200).
- [ ] **Step 4: Verify frontend loads**
Open `http://8.130.143.54:8548` in a browser. Expected: React app renders correctly (login page / blog page visible).
- [ ] **Step 5: Verify API stats endpoint**
```bash
curl http://8.130.143.54:8548/api/web/stats
```
Expected: JSON with system metrics (CPU, memory, etc.).
---
## Operations Reference
**Stop server:**
```bash
ssh root@8.130.143.54 "pkill RustServer"
```
**View live logs:**
```bash
ssh root@8.130.143.54 "tail -f /opt/internet-project/server.log"
```
**Redeploy after code changes:**
Re-run Tasks 14. For frontend-only changes, skip Task 2.
**Frontend-only redeploy (re-verified 2026-06-24 — 照片墙 `#photo` 上线即走此路径):**
The active WSL checkout is at `/home/cc/InternetProject` (not the `/mnt/f/...`
path in the original tasks above). Since the Rust process serves `static/` from
disk, a frontend-only change needs **no server restart** — just rebuild and
replace the static files:
```bash
cd /home/cc/InternetProject/Client
npm run build
# clear stale hashed assets so old bundles don't accumulate
ssh root@8.130.143.54 "rm -rf /opt/internet-project/static/assets && mkdir -p /opt/internet-project/static"
scp -r dist/* root@8.130.143.54:/opt/internet-project/static/
# verify live
curl -s http://8.130.143.54:8548/ | grep -o '<title>[^<]*</title>'
curl -s -o /dev/null -w '%{http_code}\n' http://8.130.143.54:8548/api/client/health
```
**Restart the Rust binary (backend changes):**
A helper exists on the server: `/opt/internet-project/restart_rust.sh`. The
previous binary is kept as `RustServer.bak` for rollback.
**照片墙服务器存图2026-06-24后端改动**
照片墙从纯前端 localStorage 改为按用户存服务器(`#photo` 入口,详见
[photo-wall.md](../../photo-wall.md))。这引入了后端改动,需**全量重部署**(非
frontend-only重编 Rust → 传二进制 → `restart_rust.sh` 重启。新增两个运行时配置:
- `JWT_SECRET`(写在 `/opt/internet-project/weather.env`)—— 登录 token 改为 HS256
JWT 的签名密钥,未设则用内置开发密钥并告警。**token 格式变了,上线后用户需重登一次。**
- `PHOTO_DIR`(可选,默认 `photo-wall`,即 `/opt/internet-project/photo-wall/`)——
图片按用户存到其下子目录,首次上传自动创建。
**特殊文件夹视频媒体(规划,后端改动 + ffmpeg 运行时依赖):**
特殊文件夹支持视频上传后,服务器需要安装 `ffmpeg` 并确保 Rust 服务进程能在 `PATH` 中调用。
这次改动会新增 `/api/web/folder/{name}/media*` 接口和 multipart 上传,需**全量重部署**
重编 Rust → 传二进制和前端 `dist/*``restart_rust.sh` 重启。
服务器安装检查:
```bash
ssh root@8.130.143.54 "ffmpeg -version | head -1"
```
如未安装,按服务器系统包管理器安装,例如 Debian/Ubuntu
```bash
ssh root@8.130.143.54 "apt-get update && apt-get install -y ffmpeg"
```
2026-07-09 23:55:17 +08:00
如果通过 Nginx 的 80 端口访问线上站点,还要把反代请求体上限放大到与 Rust
multipart 路由一致,否则 30MB 级视频会先被 Nginx 默认上限拦截并返回 413
```nginx
server {
listen 80;
server_name _;
client_max_body_size 700m;
location / {
proxy_pass http://127.0.0.1:8548;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
修改后验证并重载:
```bash
ssh root@8.130.143.54 "nginx -t && systemctl reload nginx"
```
转码目标固定为 720p 档、24fps、视频约 900kbps、音频 96kbps、MP4 faststart
2026-07-09 23:55:17 +08:00
用于适配 3M 带宽播放。不提供显式视频下载入口;`controlsList="nodownload"` 只是 UI 降噪,
不是防下载安全边界。
**写博客2026-06-27后端改动**
个人博客(登录后默认页,`#post/<id>` 文章路由,详见 [blog.md](../../blog.md))引入了后端
改动(新增 `posts.rs` + 5 个 `/api/web/posts*` 接口、CORS 放行 PUT需**全量重部署**
(重编 Rust → 传二进制 → `restart_rust.sh` 重启),非 frontend-only。新增一个可选运行时配置
- `BLOG_DIR`(可选,默认 `blog`,即 `/opt/internet-project/blog/`)—— 文章按用户存到其下
子目录,每篇一个 `<hex>.json`,首次写文章自动创建。
- 复用现有 `weather.env``DATABASE_URL`(登录校验)与 `JWT_SECRET`token 签名),
无需新增密钥。
> Startpage backgrounds: large PNG/JPG source images are pre-compressed to WebP
> (quality ~82) before building — keeps each background under ~600 KB for the
> 3 Mbps server link. Two sets live under `Client/src/assets/startpage/`:
> `landscape/` and `portrait/` (same filenames `No.1~5.webp` + `Night.webp`).
> As of 2026-06-23 both sets are fully populated; `sharp` is the converter (no
> system `cwebp`/ImageMagick in this WSL — install it on the fly if needed).