# MinIO + NGINX + Cloudflare WAN path for SyncGames SSOT. Laptop and phone use this HTTPS endpoint only (no LAN/VPN requirement). ## Topology ``` Clients → https://syncgames-s3. → Cloudflare DNS (+ optional Access) → cloudflared Tunnel → NGINX on NAS → MinIO S3 API :9000 ``` Keep MinIO Console (often `:9001`) on a separate vhost or LAN-only. SyncGames clients need the **S3 API** only. ## MinIO Prefer Docker on the NAS: [deploy/docker/](../deploy/docker/) (`docker compose up -d`). Manual checklist: 1. Bind API to `127.0.0.1:9000` (Compose does this). 2. Create bucket `syncgames` (private) — `docker compose --profile init run --rm createbuckets`. 3. Create an access key / secret for SyncGames devices (rotate periodically). 4. Set `MINIO_SERVER_URL=https://syncgames-s3.` so redirects/presigns use the public name if you use them (SyncGames prefers path-style without relying on redirects). ## NGINX (anti-grief checklist) Example vhost: [deploy/nginx/syncgames-s3.conf](../deploy/nginx/syncgames-s3.conf) Required behaviors: | Setting | Why | |---------|-----| | Preserve `Host` as public hostname | SigV4 signing | | `proxy_request_buffering off` | Avoid truncated large PUTs | | `client_max_body_size 512m;` (or higher) | Emulator dumps | | `proxy_http_version 1.1` | Keepalive / chunked | | `ignore_invalid_headers off` | S3 headers with underscores | | Forward `Authorization`, `X-Amz-*`, `Content-Length`, `X-Forwarded-Proto` | API correctness | | **No** `auth_basic` | Breaks AWS SDKs — use Cloudflare Access instead | ## Cloudflare 1. Create Tunnel hostname `syncgames-s3.` → `http://127.0.0.1:80` (or whatever port NGINX listens on for that vhost). 2. Prefer Cloudflare Access (email OTP / your IdP) for defense-in-depth. 3. Orange-cloud proxy is fine for typical Souls/ER save sizes. If a huge upload fails (~100MB free-plan body limits can apply depending on product), check Cloudflare docs / plan or temporarily use a larger object split strategy. ## Client configuration In `agent.toml`: ```toml endpoint_url = "https://syncgames-s3.example.com" bucket = "syncgames" region = "us-east-1" path_style = true access_key = "..." secret_key = "..." ``` Android settings screen uses the same values. ## Validation ```bash syncgames doctor ``` Performs HEAD/list on the bucket and a tiny PUT/GET/DELETE probe object under `games/_probe/`. Failures usually mean Host/header/buffering misconfig on NGINX or Access blocking SDK traffic (use a Service Token or bypass path carefully for API clients if Access challenges browsers only — for programmatic S3, Access service tokens or skip Access on the API hostname and rely on MinIO keys + Cloudflare WAF IP restrictions). ### Cloudflare Access vs S3 SDKs Browser Access login does **not** work for boto3/Android AWS SDK. Pick one: 1. **Access Service Auth** (service token headers) injected by agents — advanced, document if you enable it; or 2. **No Access on the S3 API hostname**, protect with strong MinIO keys + tunnel (not publicly documented); or 3. Separate hostname for human console only behind Access. Recommended v1: tunnel + strong MinIO keys; optional IP allowlist / WAF; Access only on MinIO **Console** vhost if exposed.