-
Notifications
You must be signed in to change notification settings - Fork 367
Upgrade self host docs + migrate docs #2847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,262 @@ | ||
| --- | ||
| nextjs: | ||
| metadata: | ||
| title: 'Self Hosting Instant on AWS' | ||
| description: 'Run Instant with multiple backend servers and Aurora PostgreSQL.' | ||
| --- | ||
|
|
||
| For more serious projects where you need higher availability and point in time | ||
| restores we recommend starting with two backend servers and | ||
| Aurora PostgreSQL. This is the same general architecture Instant Cloud used and | ||
| lets you scale the backend and database separately. | ||
|
|
||
| The resources and instance types are up to you. The important parts are how the | ||
| Instant containers connect to PostgreSQL, object storage, and each other. | ||
|
|
||
| ## Architecture | ||
|
|
||
| Instant does not require a particular AWS container platform. Your deployment | ||
| needs: | ||
|
|
||
| - HTTPS traffic routed to every healthy backend | ||
| - At least two backend tasks for redundancy | ||
| - Private DNS resolving `tasks.<service-name>` to all backend tasks | ||
| - Shared environment variables, secrets, and `override.edn` | ||
| - Aurora PostgreSQL 17 with logical replication | ||
| - Private S3 object storage | ||
| - A separately deployed dashboard | ||
|
|
||
| Set `SWARM_SERVICE_NAME` to the service name used in private DNS. Backend tasks | ||
| must be able to communicate over ports 5701–5708 and 5801–5808. | ||
|
|
||
| Do not set `PRODUCTION=true`; that selects Instant Cloud configuration rather | ||
| than self-hosted configuration. | ||
|
|
||
| ## Configure AWS access | ||
|
|
||
| Before creating resources, choose an AWS CLI profile and Region, then confirm | ||
| that they point to the account where you intend to deploy: | ||
|
|
||
| ``` | ||
| aws sts get-caller-identity --profile your-profile | ||
| aws configure get region --profile your-profile | ||
| ``` | ||
|
|
||
| If AWS is not configured yet, use any AWS-supported authentication method to | ||
| create a CLI profile. An agent can help with this process. Use the selected | ||
| profile and Region consistently throughout the deployment. | ||
|
|
||
| ## Configure Aurora PostgreSQL | ||
|
|
||
| Instant requires PostgreSQL 17 with logical replication and `pg_hint_plan`. | ||
| Create an Aurora PostgreSQL 17 cluster and apply these settings in a custom DB | ||
| cluster parameter group: | ||
|
|
||
| ```text | ||
| rds.logical_replication = 1 | ||
| shared_preload_libraries = pg_stat_statements,pg_hint_plan | ||
| max_replication_slots = 10 | ||
| max_wal_senders = 10 | ||
| random_page_cost = 1.1 | ||
| rds.force_ssl = 0 | ||
| ``` | ||
|
|
||
| Keep any existing entries in `shared_preload_libraries`. The replication | ||
| settings require a reboot. | ||
|
|
||
| {% callout type="note" %} | ||
| Instant opens its migration connection without TLS, so Aurora PostgreSQL 17 | ||
| requires `rds.force_ssl = 0`. Restrict port 5432 to the backend servers. | ||
| {% /callout %} | ||
|
|
||
| Create a database and login for Instant. The login needs the RDS replication | ||
| role: | ||
|
|
||
| ```sql | ||
| CREATE ROLE instant LOGIN PASSWORD 'replace-with-a-generated-password'; | ||
| GRANT rds_replication TO instant; | ||
| CREATE DATABASE instant OWNER instant; | ||
| ``` | ||
|
|
||
| Use the Aurora writer endpoint in `DATABASE_URL`: | ||
|
|
||
| ```shell | ||
| DATABASE_URL=postgresql://instant:PERCENT_ENCODED_PASSWORD@WRITER_ENDPOINT:5432/instant | ||
| ``` | ||
|
|
||
| Each backend opens `CONNECTION_POOL_SIZE` database connections. Make sure | ||
| Aurora's `max_connections` can support every backend instance with room for | ||
| migrations and administration. Increase `max_replication_slots` and | ||
| `max_wal_senders` if you run more than ten backend instances. | ||
|
|
||
| ## Configure S3 | ||
|
|
||
| Create a private S3 bucket for Instant Storage. The backend needs permission to | ||
| list the bucket and to read, write, delete, and manage multipart uploads for its | ||
| objects. | ||
|
|
||
| Set these values on every backend server: | ||
|
|
||
| ```shell | ||
| AWS_REGION=your-region | ||
| S3_BUCKET=instant-bucket | ||
| AWS_ACCESS_KEY_ID=replace-with-the-storage-access-key | ||
| AWS_SECRET_ACCESS_KEY=replace-with-the-storage-secret-key | ||
| ``` | ||
|
|
||
| Be sure to configure CORS on the bucket so Instant apps can upload files directly from the browser. | ||
|
|
||
| Leave `S3_ENDPOINT` and `S3_PUBLIC_ENDPOINT` unset when using AWS S3. Instant | ||
| currently needs static IAM credentials to sign S3 URLs, so provide an access | ||
| key even when the application servers also have an instance role. | ||
|
|
||
| ## Share the encryption configuration | ||
|
|
||
| Every backend instance must use the same `override.edn`. Instant uses this file | ||
| to encrypt secrets and sign webhooks. Generate it once: | ||
|
|
||
| ```sh {% showCopy=true %} | ||
| mkdir instant-config | ||
| docker run --rm \ | ||
| -v "$PWD/instant-config:/out" \ | ||
| ghcr.io/instantdb/server:latest \ | ||
| /app/start.sh generate-override-config /out/override.edn | ||
| ``` | ||
|
|
||
| Store it with your other deployment secrets and mount it at | ||
| `/app/resources/config/override.edn` on every backend. Do not generate a | ||
| different file for each server. | ||
|
|
||
| ## Deploy Instant | ||
|
|
||
| ### Run the backend servers | ||
|
|
||
| Deploy the backend image on your preferred container platform: | ||
|
|
||
| ``` | ||
| ghcr.io/instantdb/server:latest | ||
| ``` | ||
|
|
||
| Start with two backend tasks in the same Availability Zone as the Aurora writer. | ||
| Route public backend traffic through the load balancer and use `/health/system` | ||
| for health checks. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| Every backend task must use the same environment variables and the same | ||
| `override.edn`. Mount it at: | ||
|
|
||
| ``` | ||
| /app/resources/config/override.edn | ||
| ``` | ||
|
|
||
| At minimum, configure: | ||
|
|
||
| ``` | ||
| WAL_HISTORY_STORAGE=pg | ||
| DATABASE_URL=postgresql://instant:PERCENT_ENCODED_PASSWORD@WRITER_ENDPOINT:5432/instant | ||
| CONNECTION_POOL_SIZE=20 | ||
|
|
||
| INSTANT_BACKEND_URL=https://api.myinstant.com | ||
| INSTANT_DASHBOARD_URL=https://dash.myinstant.com | ||
|
|
||
| AWS_REGION=your-region | ||
| S3_BUCKET=instant-bucket | ||
| AWS_ACCESS_KEY_ID=replace-with-the-storage-access-key | ||
| AWS_SECRET_ACCESS_KEY=replace-with-the-storage-secret-key | ||
|
|
||
| JAVA_OPTS=-Xmx4g -Xms4g | ||
| ``` | ||
|
|
||
| Leave `S3_ENDPOINT` and `S3_PUBLIC_ENDPOINT` unset when using AWS S3. | ||
|
|
||
| ### Configure backend discovery | ||
|
|
||
| Multiple backend tasks must form a single Hazelcast cluster for presence, topics, and distributed state to work correctly. | ||
|
|
||
| Set a service name on every backend: | ||
|
|
||
| ``` | ||
| SWARM_SERVICE_NAME=server | ||
| ``` | ||
|
|
||
| Configure private DNS so that: | ||
|
|
||
| ``` | ||
| tasks.server | ||
| ``` | ||
|
|
||
| resolves to the private IP address of every backend task. Each task must be able | ||
| to reach the others over TCP ports 5701–5708 and 5801–5808. | ||
|
|
||
| ECS with AWS Cloud Map, Docker Swarm DNSRR, or another scheduler that provides | ||
| equivalent private DNS can satisfy this requirement. | ||
|
|
||
| Keep `PRODUCTION` unset. Setting `PRODUCTION=true` selects Instant Cloud's | ||
| production configuration rather than the mounted self-hosted `override.edn`. | ||
|
|
||
| A successful `/health/system` response verifies the database WAL but does not | ||
| verify backend clustering. After deployment, test presence and realtime updates | ||
| while requests are distributed across both backend tasks. | ||
|
|
||
| ### Run the dashboard | ||
|
|
||
| Deploy the dashboard image separately: | ||
|
|
||
| ``` | ||
| ghcr.io/instantdb/dashboard:latest | ||
| ``` | ||
|
|
||
| Set its public backend URL: | ||
|
|
||
| ``` | ||
| INSTANT_BACKEND_URL=https://api.myinstant.com | ||
| ``` | ||
|
|
||
| Route the dashboard hostname to port 3000: | ||
|
|
||
| ``` | ||
| https://dash.myinstant.com | ||
| ``` | ||
|
|
||
| The dashboard does not participate in backend service discovery. | ||
|
|
||
| ## Verify the deployment | ||
|
|
||
| The load balancer should only send traffic to backends where | ||
| `/health/system` returns `{"wal":"ok"}`. Open the dashboard and create an app to | ||
| check queries, writes, realtime updates, and file uploads. | ||
|
|
||
| Until Postmark is configured, login codes are written to the backend logs. For | ||
| an ECS deployment using CloudWatch Logs, tail the log group configured on the | ||
| backend task definition: | ||
|
|
||
| ```shell {% showCopy=true %} | ||
| aws logs tail /your/backend/log-group \ | ||
| --follow \ | ||
| --region your-region \ | ||
| --profile your-profile | ||
| ``` | ||
|
|
||
| Send application logs and infrastructure metrics wherever your team normally | ||
| monitors AWS services. At a minimum, watch request errors and latency, backend | ||
| health, server CPU and memory, Aurora connections and query latency, and S3 | ||
| errors. | ||
|
|
||
| ## Scale the deployment | ||
|
|
||
| Add backend servers when CPU, memory, or request latency stays high. | ||
| Resize the Aurora writer when database CPU, memory, connections, or query | ||
| latency becomes the bottleneck. Revisit the connection pool and replication | ||
| settings whenever you add backend servers. | ||
|
|
||
| Currently Instant Cloud runs on: | ||
|
|
||
| | Tier | Capacity | | ||
| | ------------------- | ---------------------------------------------------------------------------------------------- | | ||
| | Application servers | 3 x `m6a.16xlarge` (64 vCPUs and 256 GiB each) | | ||
| | PostgreSQL | `db.r8gd.16xlarge` (64 vCPUs and 512 GiB) with Aurora I/O-Optimized | | ||
| | Workload | 10,000+ concurrent connections, 10,000+ queries per second, and 1,000+ transactions per second | | ||
|
|
||
| Most deployments should start much smaller and scale each part from observed usage. | ||
|
|
||
| Once Instant is running, see [Operating Instant](/docs/self-hosting#operating) | ||
| to configure email, dashboard access, the CLI, and health checks. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| --- | ||
| nextjs: | ||
| metadata: | ||
| title: 'Migrate from Instant Cloud' | ||
| description: 'Move an Instant Cloud app to self-hosted Instant.' | ||
| --- | ||
|
|
||
| Migrating from Instant Cloud happens in two phases: | ||
|
|
||
| 1. **Rehearse the migration:** Set up self-hosted Instant and restore a test backup. This confirms that everything works and gives you an estimate for downtime. | ||
| 2. **Cut over:** Pause writes, restore a fresh backup, and point your app at your self-hosted Instant. | ||
|
|
||
| ## Rehearse the migration | ||
|
|
||
| ### Set up self-hosted Instant | ||
|
|
||
| If you haven't already, set up self-hosting with our [VPS](/docs/self-hosting/vps) or | ||
| [AWS](/docs/self-hosting/aws) guide. Make sure you can log in to the dashboard, | ||
| create an app, query it, and write data. | ||
|
|
||
| Before restoring your app: | ||
|
|
||
| - [Configure Postmark](/docs/self-hosting#configure-email-with-postmark) so magic code emails work. | ||
| - [Restrict dashboard signups](/docs/self-hosting#restrict-dashboard-signups) and [disable temporary apps](/docs/self-hosting#temporary-apps) to prevent unwanted app creation. | ||
| - Similarly if your app uses webhooks you'll need to configure those for your | ||
| self-hosted app. | ||
|
|
||
| If your app uses OAuth for end-user sign-in, recreate each OAuth provider on | ||
| the restored app. Copy its client ID, client secret, and any other provider | ||
| settings. Then add the self-hosted callback URL to the provider: | ||
|
|
||
| ```text | ||
| https://api.myinstant.com/runtime/oauth/callback | ||
| ``` | ||
|
|
||
| Keep the Instant Cloud callback configured until the migration is complete. | ||
|
|
||
| ### Restore a test backup | ||
|
|
||
| Migrating without data loss will require some downtime. To get a sense of how | ||
| much time it will take we'll | ||
|
|
||
| 1. Export a backup from Instant Cloud | ||
| 2. Restore the backup into your self hosted Instant. | ||
|
|
||
| After restoring verify the following look correct: | ||
|
|
||
| - Schema and permissions | ||
| - Application data | ||
| - Files | ||
| - Magic code and each OAuth provider your app uses | ||
| - Email templates | ||
|
|
||
| ### Prepare the client change | ||
|
|
||
| After successfully restoring we can put up a PR to update our clients to point | ||
| to our new self-hosted Instant app. | ||
|
|
||
| Choose a new app ID for the self-hosted app. The ID must be a valid UUID. You | ||
| can generate one in the terminal with: | ||
|
|
||
| ```sh {% showCopy=true %} | ||
| uuidgen | ||
| ``` | ||
|
|
||
| This will be the ID your app going forward. | ||
|
|
||
| Create a PR that points your app at self-hosted Instant, but do not merge it | ||
| yet. Update the app ID, API URL, and WebSocket URL in every client `init` call: | ||
|
|
||
| ```ts | ||
| const db = init({ | ||
| appId: 'YOUR_NEW_APP_ID', | ||
| apiURI: 'https://api.myinstant.com', | ||
| websocketURI: 'wss://api.myinstant.com/runtime/session', | ||
| }); | ||
| ``` | ||
|
|
||
| If you use the Admin SDK, update its app ID, admin token, and `apiURI` too. Keep | ||
| the PR ready to merge as soon as the final restore finishes. | ||
|
|
||
| ## Cut over | ||
|
|
||
| ### Pause writes on Instant Cloud | ||
|
|
||
| Open the app's **Admin** page in the Instant Cloud dashboard. Turn on | ||
| **Read-only mode**, then wait 30 seconds for in-flight mutations to finish. | ||
|
|
||
| Reads, live queries, and presence will keep working. New writes will be | ||
| rejected, including offline writes queued on user devices. We do this to ensure | ||
| there is no data loss during cut over. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| ### Restore the final backup | ||
|
|
||
| Create an on demand backup of the Instant Cloud app and restore it into self-hosted | ||
| Instant using the app ID from the rehearsal. | ||
|
|
||
| Before merging our earlier PR to switch clients over: | ||
|
|
||
| - Check that `/health/system` returns `{"wal":"ok"}`. | ||
| - Check the restored schema, permissions, data, and files. | ||
| - Make sure **Read-only mode** is off on the self-hosted app. | ||
| - Test magic code and OAuth login if your app uses them. | ||
|
|
||
| ### Switch to self-hosted Instant | ||
|
|
||
| Merge and deploy the PR you prepared earlier. New client connections will now | ||
| use the restored app on self-hosted Instant. Users may need to sign in again. | ||
|
|
||
| Watch the deployment and verify queries, writes, authentication, and file | ||
| uploads. Once clients begin writing to self-hosted Instant, the Instant Cloud | ||
| copy is no longer current. If you used OAuth you can remove the Instant Cloud | ||
| callback URL from each OAuth provider. | ||
|
|
||
| The migration should now be complete. Huzzah! 🎉 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.