findplate provision <dokploy|s3|dns|turbo|backup|all> [--dry-run] [--domain example.com]Everything points at your own infra. Set it once with findplate config:
findplate config set dokployUrl https://dokploy.example.com
findplate config set dnsProvider cloudflare # or vercel
findplate config set s3Endpoint https://s3.example.com
findplate config set turboCache https://cache.example.com # optional, Vercel's cache otherwise
findplate config set githubOwner your-nameSecrets only come from the environment (or a hidden prompt in a terminal). They are piped to gh, never printed and never written to .findplate/.
| Target | What it does | Secrets read |
|---|---|---|
dokploy | one Dokploy project per environment (<name>-production, <name>-preview) | DOKPLOY_API_KEY |
s3 | a bucket and an access key per environment, saved as GitHub secrets | GARAGE_ADMIN_TOKEN with GARAGE_ADMIN_URL, or S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY for any S3 api |
dns | records for the apex (web), dashboard, api, docs and *.preview | VERCEL_TOKEN or CLOUDFLARE_API_TOKEN |
turbo | TURBO_TEAM, TURBO_API and TURBO_TOKEN in the repo's GitHub settings | TURBO_TOKEN |
backup | adds .github/workflows/backup.yml and BACKUP_DATABASE_URL | BACKUP_DATABASE_URL |
--dry-run prints the plan and changes nothing. Every step checks what already exists before it creates anything, and finished steps are recorded in .findplate/provision.json, so rerunning is safe.
Other flags: --repo owner/name (default githubOwner/<project name>), --envs production,preview, --dir.
DNS
web and dashboard point at Vercel (cname.vercel-dns.com), api, docs and *.preview at the host of your Dokploy url. Set SERVER_HOST to use another host or an IP. Existing records with the same name and type are left alone.
Backups
The backup workflow runs nightly at 03:17 UTC: pg_dump | gzip into backups/db-YYYY-MM-DD.sql.gz in the production bucket. Run it by hand from the Actions tab (workflow_dispatch). Expire old dumps with a lifecycle rule on the bucket, the workflow never deletes anything.
Restore
aws s3 ls s3://<bucket>/backups/ --endpoint-url $S3_ENDPOINT
aws s3 cp s3://<bucket>/backups/db-2026-01-01.sql.gz . --endpoint-url $S3_ENDPOINT
gunzip -c db-2026-01-01.sql.gz | psql "$DATABASE_URL"Restore into an empty database, or drop the schema first. Try it on a scratch database before you need it.
Database and S3 browsers
DOKPLOY_ENVIRONMENT_ID=... BROWSER_PASSWORD=... findplate provision browsers --domain example.comDeploys two extra Dokploy compose apps in the preview environment, at db.preview.example.com and s3.preview.example.com (set PREVIEW_DOMAIN to change the base). The *.preview dns record from provision dns already covers them.
dbis pgweb started with--readonly. SetBROWSER_DATABASE_URLto open one database straight away, or leave it empty and paste a preview database url in the connect form.s3is s3manager pointed ats3Endpoint, usingS3_ACCESS_KEY_IDandS3_SECRET_ACCESS_KEY.
--readonly only guards pgweb itself, so give BROWSER_DATABASE_URL a read-only postgres role. Both sit behind Dokploy's basic auth (BROWSER_USER, default preview, and BROWSER_PASSWORD), so they are never public. Put the preview server on a tailnet if you want them off the internet entirely. Rerunning updates the compose files and redeploys, the domain and auth are only created once. The images use latest, pin a tag in Dokploy once you have one you trust.
The compose, domain and security calls are isolated in composeApi. compose.create, compose.update and compose.deploy follow the Dokploy reference, security.create and the compose list inside project.all are assumed.
What is verified
The Garage admin paths (/v2/CreateBucket, CreateKey, AllowBucketKey, ListBuckets, ListKeys) come from its OpenAPI spec, and the S3 calls use AWS signature v4. Dokploy's x-api-key header, project.all and project.create are documented, the response shape of project.all is assumed and lives in one function, dokployApi.