PersonalWebApplication/docs/superpowers/plans/2026-06-18-deploy.md
cc f88686cd21 docs(photo-wall): server-side image storage + deploy notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:33:07 +08:00

8.0 KiB
Raw Blame 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:

npm install

Expected: node_modules/ populated, no errors.

  • Step 2: Build the frontend
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
Get-ChildItem Client\dist

Expected: index.html, assets/, favicon.svg, icons.svg present.

  • Step 4: Commit the main.rs port change
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:

cd /mnt/f/Code/InternetProject/Server
  • Step 2: Check Rust toolchain is installed
rustc --version

If not installed:

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
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
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:

ssh root@8.130.143.54 "mkdir -p /opt/internet-project/static"

Expected: no output, exit 0.

  • Step 2: Upload the Rust binary
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
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
ssh root@8.130.143.54 "chmod +x /opt/internet-project/RustServer"
  • Step 5: Verify remote layout
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

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
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
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
curl http://8.130.143.54:8548/api/web/stats

Expected: JSON with system metrics (CPU, memory, etc.).


Operations Reference

Stop server:

ssh root@8.130.143.54 "pkill RustServer"

View live logs:

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:

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)。这引入了后端改动,需全量重部署(非 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/)—— 图片按用户存到其下子目录,首次上传自动创建。

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).