Full production-ready docker-compose stack (db, kong, auth, rest, realtime, storage, imgproxy, meta, functions, studio) targeting api.caterium.ru, plus bootstrap script for a fresh Cloud Server, Caddy reverse-proxy config (HTTPS, WebSocket, upload limits), and dump/restore/verify/storage-sync scripts for moving off the managed Supabase project (cksuehzcimitsxmeloes). Does not touch public/ or any live runtime behavior — frontend cutover is documented separately in frontend-cutover.md and only applied after Etap 8 verification. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
5.8 KiB
Markdown
73 lines
5.8 KiB
Markdown
# Self-hosted Supabase for Caterium (Timeweb Cloud Server)
|
|
|
|
Target: `https://api.caterium.ru` — replaces `https://cksuehzcimitsxmeloes.supabase.co`.
|
|
|
|
This directory is deployable as-is on a fresh Ubuntu 22.04/24.04 **Timeweb Cloud Server (VPS with root)**.
|
|
It CANNOT run on the existing `timeweb-caterium` shared-hosting SSH account (`ci503744@vh470.timeweb.ru`) —
|
|
that account has no root, sudo is disabled (`no_new_privileges`), and there is no Docker daemon. Shared
|
|
hosting is fine for serving the static frontend (`public/`) but architecturally cannot host Postgres/Kong/
|
|
GoTrue/PostgREST/Realtime/Storage containers.
|
|
|
|
## What's here
|
|
|
|
| File | Purpose |
|
|
|---|---|
|
|
| `bootstrap-server.sh` | Run once (as root) on a fresh Cloud Server. Installs Docker, Docker Compose plugin, Caddy, ufw rules, clones this config, brings the stack up. |
|
|
| `docker-compose.yml` | The Supabase stack: db, kong, auth, rest, realtime, storage, meta, functions, studio, imgproxy. |
|
|
| `.env.example` | Every secret/setting the stack needs. Copy to `.env`, fill in, `chmod 600`. Never commit the real `.env`. |
|
|
| `volumes/api/kong.yml` | Kong declarative routing for `/rest/v1`, `/auth/v1`, `/storage/v1`, `/realtime/v1`, `/functions/v1`. |
|
|
| `volumes/db/init/` | One-time SQL run by the Postgres container on first boot (roles, `pg_cron`/extensions, JWT hook wiring). |
|
|
| `Caddyfile` | Reverse proxy for `api.caterium.ru`: automatic HTTPS (Let's Encrypt), WebSocket upgrade for Realtime, large upload limits for Storage, header forwarding. |
|
|
| `scripts/01-dump-old.sh` | Runs against the OLD Supabase project. Produces `roles.sql`, `schema.sql`, `data.sql` via `supabase db dump`. |
|
|
| `scripts/02-restore-new.sh` | Restores those dumps into the new self-hosted Postgres via `psql`. |
|
|
| `scripts/03-verify-counts.sql` | Row-count comparison old vs new (auth.users, orders, order_items, clients, catalog_items, storage.objects). |
|
|
| `scripts/04-deploy-edge-function.sh` | Copies `supabase/functions/caterium-create-employee` and `caterium-platform-auth-admin` into the running `functions` container's mounted volume and reloads it. |
|
|
| `scripts/05-storage-sync.sh` | Copies Storage objects (binary files) from the old project's Storage S3-compatible/API to the new bucket, preserving paths. |
|
|
|
|
## Order of operations
|
|
|
|
1. Provision the Cloud Server (see "Manual step required" below). Point DNS `api.caterium.ru` A-record at its IP.
|
|
2. `scp` this whole `ops/supabase-selfhosted/` directory to the server, or `git clone` the repo there.
|
|
3. `sudo bash bootstrap-server.sh` — installs Docker/Caddy, brings up the stack with placeholder secrets.
|
|
4. Fill in real secrets in `.env` (JWT secret, DB password, SMTP, dashboard user/pass) — generate fresh ones with
|
|
`openssl rand -base64 32` unless told to reuse the old JWT secret. `docker compose up -d` again to apply.
|
|
5. Run `scripts/01-dump-old.sh` (needs `OLD_DB_URL` — the old project's Postgres connection string with password,
|
|
from Supabase Dashboard → Project Settings → Database → Connection string → URI, "session pooler" disabled,
|
|
direct connection).
|
|
6. Run `scripts/02-restore-new.sh` against the new stack's `db` container.
|
|
7. Run `scripts/03-verify-counts.sql` old vs new and compare against the expected counts (14 / 11 / 53 / 52 / 460 / 18).
|
|
8. Run `scripts/05-storage-sync.sh` to copy the 18 Storage objects and their metadata/policies.
|
|
9. Run `scripts/04-deploy-edge-function.sh` to bring `caterium-create-employee` online, verify with a test call.
|
|
10. Only after 5-9 pass: flip `DEFAULT_SUPABASE_URL` in `public/app-runtime.js`, ship the `localStorage` migration
|
|
shim (see `ops/supabase-selfhosted/frontend-cutover.md`), commit to `main`, let CI promote to `production`.
|
|
|
|
## Manual step required right now (nothing beyond this is blocked)
|
|
|
|
I do not have a Timeweb Cloud API token or root SSH credentials to any Timeweb **Cloud Server** (VPS) — only to
|
|
the existing shared-hosting account used for the static frontend, which cannot run Docker. To unblock steps 1-10:
|
|
|
|
**Either**
|
|
- **(A)** In the Timeweb Cloud panel (https://timeweb.cloud/), create a Cloud Server: Ubuntu 22.04, minimum
|
|
2 vCPU / 4 GB RAM / 50 GB NVMe (recommended: 4 vCPU / 8 GB for headroom), public IPv4, and add my SSH public
|
|
key as an authorized key OR give me the root password so I can add my own key. Then tell me the server's IP.
|
|
- **(B)** Generate a Timeweb Cloud API token (panel → API → "Токены доступа" → create token with Cloud Servers
|
|
write scope) and give it to me; I will provision the server via the Timeweb API myself
|
|
(`POST https://api.timeweb.cloud/api/v1/servers`).
|
|
|
|
Whichever you pick, also add a DNS A-record: `api.caterium.ru` → the new server's IP (in whatever DNS provider
|
|
currently hosts `caterium.ru`'s zone — outside Cloudflare per your instruction not to put Cloudflare in the
|
|
backend path).
|
|
|
|
**Separately**, to actually migrate the data (step 5), I need the OLD Supabase project's direct Postgres
|
|
connection string with the real database password (Supabase Dashboard → Project Settings → Database →
|
|
Connection string → URI, non-pooled). I cannot retrieve this myself — it's not in any file on this machine and
|
|
I won't ask you to paste a password into a browser form on my behalf. Paste the connection string here in chat,
|
|
or set it as `OLD_DB_URL` in the shell before I run `scripts/01-dump-old.sh` for you. If you'd rather I don't
|
|
see the raw password in chat, run `scripts/01-dump-old.sh` yourself with `OLD_DB_URL` exported and send me the
|
|
three resulting `.sql` files (or their location on this machine) and I'll take it from there.
|
|
|
|
I will use a **freshly generated JWT secret** for the new stack (per your instruction that this is acceptable) —
|
|
existing sessions will be invalidated and all 14 users will need to log in once more with their existing
|
|
email+password (which migrate unchanged, since `auth.users.encrypted_password` is copied byte-for-byte from
|
|
the dump).
|