init: 从 /root/zikai 根目录迁入
把原本散落在 /root/zikai 的 FastAPI 服务整理到 server/ 子目录, 开启独立 git 与 venv。运行时数据(config.yaml / keys / uploads) 按 .gitignore 留在工作目录但不入仓。
This commit is contained in:
135
README.md
Normal file
135
README.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# zikai file service
|
||||
|
||||
A Python web service (FastAPI) for **f.zikai.wang** that provides host
|
||||
monitoring and large-file upload over **both HTTP and SFTP**. It follows a
|
||||
Spring-style layered architecture (`controllers` → `services` → `dao`, plus
|
||||
`models` and `schemas`), ships with auto-generated API docs, and runs entirely
|
||||
from a self-contained `.venv`.
|
||||
|
||||
## Features
|
||||
|
||||
- `GET /api/system/status` — CPU, memory, and per-disk usage (via `psutil`).
|
||||
- `POST /api/files/upload` — **streamed** multipart upload (flat memory, multi-GB friendly), with SHA-256.
|
||||
- `GET /api/files`, `GET /api/files/{id}`, `GET /api/files/{id}/download`.
|
||||
- **Embedded SFTP server** (asyncssh) supporting **password + public-key** auth, sharing the same storage as HTTP.
|
||||
- `/docs` (Swagger UI) and `/redoc` — interactive, auto-lists all APIs.
|
||||
- Metadata persisted in an **independent MySQL database** (`zikai_filesvc`).
|
||||
- `start.sh` / `stop.sh` lifecycle; `setup.sh` for one-time provisioning.
|
||||
|
||||
## Architecture (Spring-style layers)
|
||||
|
||||
```
|
||||
app/
|
||||
├── controllers/ # FastAPI routers — HTTP boundary (like @RestController)
|
||||
├── services/ # business logic (SystemService, UploadService, SFTP server)
|
||||
├── dao/ # data access objects — the only layer that issues SQL/ORM
|
||||
├── models/ # SQLAlchemy ORM entities
|
||||
├── schemas/ # pydantic DTOs (request/response validation)
|
||||
├── database.py # engine, session, Base, get_db() dependency
|
||||
├── config.py # typed Settings loaded from config.yaml
|
||||
└── scripts/ # init_db.py — DB provisioning
|
||||
```
|
||||
|
||||
Request flow: **controller** → **service** → **dao** → **ORM model** → MySQL.
|
||||
The DB session is injected by FastAPI's `get_db` dependency and passed down.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cd /root/zikai
|
||||
./setup.sh # one-time: venv, deps, provision DB + user, SFTP host key
|
||||
./start.sh # start HTTP (127.0.0.1:6867) + SFTP (0.0.0.0:2022)
|
||||
./stop.sh # stop both
|
||||
```
|
||||
|
||||
`setup.sh` is re-runnable. It creates the `.venv`, installs `requirements.txt`,
|
||||
copies `config.example.yaml` → `config.yaml` (if absent), provisions a **new
|
||||
independent MySQL database and app user** via the local root socket, and
|
||||
generates the SFTP host key.
|
||||
|
||||
## Access
|
||||
|
||||
| Where | URL |
|
||||
|------|-----|
|
||||
| Status page (HTML) | https://f.zikai.wang/api/system/status |
|
||||
| Status page (JSON) | https://f.zikai.wang/api/system/status?format=json (or `Accept: application/json`) |
|
||||
| API docs (Swagger) | https://f.zikai.wang/docs **(HTTP Basic Auth — see `docs:` in config.yaml)** |
|
||||
| API docs (ReDoc) | https://f.zikai.wang/redoc (same auth) |
|
||||
| Upload | `curl -F file=@big.iso https://f.zikai.wang/api/files/upload` |
|
||||
| SFTP | `sftp -P 2022 uploader@f.zikai.wang` |
|
||||
|
||||
`/api/system/status` content-negotiates: browsers (`Accept: text/html`) get a
|
||||
human-readable page with progress bars; API clients get JSON. Force one with
|
||||
`?format=html` or `?format=json`.
|
||||
|
||||
`/docs`, `/redoc`, and `/openapi.json` require HTTP Basic Auth — the browser
|
||||
will prompt you. Username + plaintext password live in `config.yaml` under
|
||||
`docs:`. `/health` and `/` remain public.
|
||||
|
||||
Apache (`/etc/apache2/sites-available/f.zikai.wang-le-ssl.conf`) proxies
|
||||
`f.zikai.wang` → `127.0.0.1:6867` with `ProxyPreserveHost On`, so the service
|
||||
only binds the loopback.
|
||||
|
||||
> **Large/slow HTTP uploads:** Apache's proxy leg inherits the global `Timeout 300`.
|
||||
> For multi-GB transfers over a slow link, prefer **SFTP** (it bypasses the HTTP
|
||||
> proxy entirely). To raise the HTTP ceiling you can add `ProxyTimeout`/`Timeout`
|
||||
> in the Apache vhost.
|
||||
|
||||
## Configuration
|
||||
|
||||
All runtime config lives in **`config.yaml`** (git-ignored). See
|
||||
`config.example.yaml` for the full schema. Notable keys:
|
||||
|
||||
- `server` — bind host/port (keep `127.0.0.1:6867` to match Apache).
|
||||
- `database` — host/port/user/password/database. The password is auto-generated
|
||||
and written here by `setup.sh`/`init_db.py`.
|
||||
- `storage.upload_dir`, `storage.chunk_bytes` (default 1 MiB streaming chunk).
|
||||
- `sftp` — enabled, host/port, host key + authorized_keys paths, and `users`.
|
||||
|
||||
### Setting the /docs admin password
|
||||
|
||||
Edit `config.yaml` directly — no hashing required:
|
||||
|
||||
```yaml
|
||||
docs:
|
||||
enabled: true
|
||||
username: admin
|
||||
password: "your-plaintext-password"
|
||||
realm: "zikai docs"
|
||||
```
|
||||
|
||||
Then `./stop.sh && ./start.sh`. The file is root-owned and stays on this
|
||||
host; comparison is constant-time (`secrets.compare_digest`).
|
||||
|
||||
### Setting SFTP credentials
|
||||
|
||||
**Password auth** — generate a bcrypt hash and put it in `config.yaml`:
|
||||
|
||||
```bash
|
||||
.venv/bin/python -c "import bcrypt;print(bcrypt.hashpw(b'yourpass',bcrypt.gensalt()).decode())"
|
||||
# paste the output into sftp.users[].password_hash, then ./stop.sh && ./start.sh
|
||||
```
|
||||
|
||||
**Public-key auth** — append each client's public key (OpenSSH format) to
|
||||
`keys/authorized_keys` (one per line). Clients in `sftp.users[]` may then log
|
||||
in with either method.
|
||||
|
||||
### Regenerating the DB password
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m app.scripts.init_db # new random password
|
||||
KEEP_DB_PASSWORD=1 .venv/bin/python -m app.scripts.init_db # keep current
|
||||
```
|
||||
|
||||
## SFTP notes
|
||||
|
||||
- The SFTP server can't traverse Apache's HTTP proxy, so it binds `0.0.0.0:2022`
|
||||
directly. **Open port 2022** in your firewall for external clients
|
||||
(FileZilla/WinSCP/scp).
|
||||
- Sessions are chrooted to the upload root (`uploads/`), shared with HTTP.
|
||||
- Only users listed in `sftp.users` may connect; only SFTP (no shell/exec) is allowed.
|
||||
|
||||
## Logs & pidfiles
|
||||
|
||||
- HTTP logs → `logs/app.log`; SFTP logs → `logs/sftp.log`.
|
||||
- Pidfiles: `app.pid`, `sftp.pid` (used by `stop.sh`).
|
||||
Reference in New Issue
Block a user