Spaces:
Paused
Paused
| title: MyAPI Hub | |
| emoji: π | |
| colorFrom: indigo | |
| colorTo: purple | |
| sdk: docker | |
| app_port: 7860 | |
| pinned: false | |
| license: apache-2.0 | |
| short_description: sub2api + bundled PG/Redis sidecar with bucket dumps | |
| # MyAPI Hub on Hugging Face Spaces | |
| Single-container deployment of [Wei-Shaw/sub2api](https://github.com/Wei-Shaw/sub2api) | |
| that bundles **PostgreSQL 18** and **Redis** as sidecars inside the same Space. | |
| PGDATA lives on the Space's ephemeral disk; `pg_dump` runs on a timer and writes | |
| to a mounted **Hugging Face bucket** for persistence across rebuilds. | |
| ## Architecture | |
| ``` | |
| βββββββββββββ HF Space container (single image) ββββββββββββββ | |
| β supervisord β | |
| β ββ postgres (127.0.0.1:5432, PGDATA=/var/lib/...) β | |
| β ββ redis (127.0.0.1:6379, in-memory) β | |
| β ββ backup.sh (every BACKUP_INTERVAL_MIN min) β | |
| β β pg_dump | gzip β /backup/pg-<ts>.sql.gz β | |
| β β /backup/latest.sql.gz β | |
| β ββ sub2api (0.0.0.0:7860, talks to localhost PG/Redis)β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ /backup is FUSE-mounted | |
| hf://buckets/<you>/sub2api-pgdump | |
| ``` | |
| On cold boot, if PGDATA is empty *and* `/backup/latest.sql.gz` exists, the | |
| entrypoint restores it before launching the app. | |
| ## Why not mount the bucket as PGDATA directly? | |
| HF buckets are S3-style storage exposed via a FUSE filesystem. PostgreSQL | |
| requires real `fsync` semantics for durability; running PGDATA on FUSE risks | |
| silent corruption. We therefore keep live PGDATA on the Space disk and only | |
| write **dumps** to the bucket (a workload FUSE handles safely). | |
| ## 1. Prerequisites | |
| ```bash | |
| hf auth login # HF token with write to your namespace | |
| hf buckets create <you>/sub2api-pgdump --private | |
| hf spaces volumes set <you>/myapi-hub \ | |
| -v hf://buckets/<you>/sub2api-pgdump:/backup | |
| ``` | |
| Free accounts get **100 GB private storage**, far more than needed for dump | |
| snapshots (a hobby DB compresses to a few MB). | |
| ## 2. Required Space secrets | |
| In **Settings β Variables and secrets** add as **secrets**: | |
| ``` | |
| POSTGRES_PASSWORD = <strong random β used by both PG and sub2api> | |
| JWT_SECRET = <openssl rand -hex 32> # MUST be stable | |
| TOTP_ENCRYPTION_KEY = <openssl rand -hex 32> # MUST be stable | |
| ADMIN_EMAIL = you@example.com | |
| ADMIN_PASSWORD = <leave empty to auto-generate; check logs> | |
| DATABASE_PASSWORD = <same value as POSTGRES_PASSWORD> | |
| ``` | |
| Optional **variables** (defaults in parentheses): | |
| ``` | |
| POSTGRES_USER = sub2api | |
| POSTGRES_DB = sub2api | |
| BACKUP_INTERVAL_MIN = 30 # how often to dump | |
| BACKUP_KEEP = 24 # how many timestamped dumps to retain | |
| DATABASE_USER = sub2api # same as POSTGRES_USER | |
| DATABASE_DBNAME = sub2api # same as POSTGRES_DB | |
| LOG_LEVEL = info | |
| ``` | |
| Do **not** override `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_SSLMODE`, | |
| `REDIS_HOST`, `REDIS_PORT`, `REDIS_ENABLE_TLS` β they are set in the Dockerfile | |
| for the in-container loopback. | |
| ## 3. Deploy | |
| Push `Dockerfile`, `entrypoint.sh`, `backup.sh`, `supervisord.conf`, `README.md` | |
| to the Space repo. First build runs `initdb`, creates the database, and starts | |
| the four sidecar processes. Subsequent rebuilds will restore from the latest | |
| bucket dump if the ephemeral disk was wiped. | |
| ## 4. Operating | |
| - **List dumps:** `hf buckets list <you>/sub2api-pgdump` | |
| - **Download latest dump locally:** `hf buckets cp hf://buckets/<you>/sub2api-pgdump/latest.sql.gz ./` | |
| - **Force a manual dump:** restart the Space (next cycle fires after `BACKUP_WARMUP_SEC`), or open a shell via dev mode and run `/usr/local/bin/backup.sh once`. | |
| - **Disaster recovery:** download `latest.sql.gz`, restore into any Postgres with `gunzip -c latest.sql.gz | psql -d <db>`. | |
| ## 5. Caveats | |
| - **RPO β BACKUP_INTERVAL_MIN.** Crash between dumps loses up to that many minutes of writes. | |
| - **No external PG access.** Postgres binds `127.0.0.1` inside the Space; only the bundled sub2api can reach it. For psql from outside, use the dump file or run a tunnel (cloudflared/chisel) β not provided here. | |
| - **Cold start = potential restore.** Free Spaces sleep after inactivity and may evict the ephemeral disk on hardware moves. The restore step runs only when PGDATA is empty, so warm restarts are fast. | |
| - **Redis is non-persistent.** AOF/RDB disabled by design (sessions are cheap to re-create). Restart logs users out. | |
| - **Pin secrets.** `JWT_SECRET` / `TOTP_ENCRYPTION_KEY` must not change across rebuilds, or all sessions / 2FA invalidate. | |
| ## License | |
| Apache-2.0 (inherits from upstream sub2api). | |