Instant features
Self Hosting
#Localhost Setup
Use this setup if you want to self-host InstantDB while developing on your own machine. In most cases, it's more convenient to use our cloud service to spin up unlimited free apps.
git clone https://github.com/instantdb/instant.gitcd instant/self-hostingdocker compose --env-file .env.example up
The dashboard will be available on http://localhost:3000.
The server will be available on http://localhost:8888.
If you are developing an app and would like to use port 3000 (for example: NextJS), you can modify the port assignment in the docker-compose.yml file like so:
www:ports:- '3001:3000'
Then you will need to change the value for INSTANT_DASHBOARD_URL in .env.example
Apply changes with:
docker compose --env-file .env.example up -d
#Full Hetzner Setup Guide
Create a new server on Hetzner. We tested on a server with 4 vCPU, 8 GB RAM. This guide also shows how to set up TLS. For memory-constrained environments, set the JAVA_OPTIONS environment variable to limit the memory the server container uses.
This setup guide assumes that you have a domain name and can set DNS A records.
If you do not have a domain name, you can use sslip.io to create a domain name on the fly that points to the IP address of your server.
#Install Docker (optional if docker is already installed)
The following Docker install instructions come from docs.docker.com
apt updatesudo apt install ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOFTypes: debURIs: https://download.docker.com/linux/ubuntuSuites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")Components: stableArchitectures: $(dpkg --print-architecture)Signed-By: /etc/apt/keyrings/docker.ascEOFsudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
#Clone the Instant DB Repo
git clone https://github.com/instantdb/instant.git
#Edit Environment Variables
cd instant/self-hostingcp .env.example .envnano .env
Example:
# Public URLs. Change these when deploying behind a domain or proxy.INSTANT_BACKEND_URL=https://api.myinstant.comINSTANT_DASHBOARD_URL=https://dash.myinstant.comS3_PUBLIC_ENDPOINT=https://files.myinstant.com# Domains used by the Caddy file. For production, point DNS at this host# and update the public URLs above to use these domains with https://.DASHBOARD_DOMAIN=dash.myinstant.comBACKEND_DOMAIN=api.myinstant.comSTORAGE_DOMAIN=files.myinstant.com
The _DOMAIN variables are only used by the Caddy reverse proxy, so if you are bringing your own reverse proxy, you can ignore them.
The MinIO bucket is private by default. Files are accessed through Instant-generated signed URLs.
#Configure the Deployment Superuser
The deployment superuser can manage settings for your entire self-hosted deployment. Set INSTANT_SUPERUSER_EMAIL to the email address of the person who should administer it:
INSTANT_SUPERUSER_EMAIL=admin@example.com
Instant creates this dashboard user when the server starts. Log in with this email and open Deployment Settings from the account menu to manage your deployment. If you change the email, restart the server to transfer superuser access.
#Restrict Dashboard Signups
By default, anyone can create a dashboard account. To limit access, open Deployment Settings and set Who can sign up?:
- Open: Anyone can sign up.
- Restricted: Only email addresses you add can sign up.
- Closed: No new dashboard accounts can sign up.
Existing dashboard users can always sign in.
#Temporary Apps
Instant supports spinning up temporary apps without authentication. Because these apps do not require a dashboard account, the signup restrictions above do not apply to them. Anyone who can reach your backend API can create temporary apps by default.
To disable temporary app creation, open Deployment Settings and turn off Allow temporary app creation under Temporary apps.
#Configure Google Dashboard Login (Optional)
To let users log in to the Instant dashboard with Google, create an OAuth client in the Google Cloud Console with the application type Web application.
Add this authorized redirect URI, using your public backend URL:
https://api.myinstant.com/dash/oauth/callback
Then set both credentials in .env:
INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.comINSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_SECRET=your-client-secret
The redirect URI must exactly match ${INSTANT_BACKEND_URL}/dash/oauth/callback. This configures login to the Instant dashboard; OAuth for users of your Instant apps is configured separately.
#DNS
Before running Instant, make sure that you have pointed the subdomain DNS records to the IP address of the server so that when the Caddy reverse proxy starts, it is able to set up TLS certificates automatically.
#Start Command
docker compose -f docker-compose.with-caddy.yml --env-file .env up --build
After everything starts up, the dashboard will be available at whatever you set INSTANT_DASHBOARD_URL to.
#Updating
For routine updates, pull the latest server and dashboard images and recreate only those containers:
docker compose -f docker-compose.with-caddy.yml --env-file .env pull server www && \docker compose -f docker-compose.with-caddy.yml --env-file .env up -d --no-deps server www
If you changed the start command, use the same Compose options here.
This does not update PostgreSQL or other infrastructure. It also leaves your Compose files, .env, overrides, and volumes unchanged.
#Memory Limits
By default, the backend server container can use a lot of resources. We recommend setting a maximum memory limit on the server container using the JAVA_OPTS environment variable like so:
server:depends_on:postgres:condition: service_healthycreatebuckets:condition: service_completed_successfullyimage: 'ghcr.io/instantdb/server:latest'environment:JAVA_OPTS: -Xmx8g -Xms8g
This example sets the minimum and maximum heap memory usage to 8GB.
#Using Self-Hosted InstantDB
Without a POSTMARK_TOKEN environment variable set, OTP codes will not be emailed. You must read the console output of the server container, which will print the body of any emails that would get sent.
You can use this command to print out recent logs from the server (last 50 lines):
docker compose logs server -n 50
#Using your self-hosted deployment with instant-cli
To use the Instant CLI with your self-hosted instance, set INSTANT_CLI_API_URI to the backend URL and INSTANT_CLI_DASH_URI to the dashboard URL. For example:
# Local Machine DeploymentINSTANT_CLI_API_URI=http://localhost:8888 \INSTANT_CLI_DASH_URI=http://localhost:3000 \npx instant-cli@latest init# Server DeploymentINSTANT_CLI_API_URI=https://api.myinstant.com \INSTANT_CLI_DASH_URI=https://dash.myinstant.com \npx instant-cli@latest init
You can also set both URLs in the instant.config.ts file.
// instant.config.tsexport default {apiURI: 'http://127.0.0.1:8888',dashURI: 'http://localhost:3000',};
#Horizontal Scaling With Docker Swarm
Docker Swarm allows one or more machines to distribute Docker containers between them. The InstantDB repo includes a deploy-swarm.sh script designed to easily deploy InstantDB across multiple machines.
This setup guide does not constitute a full production-ready deployment. You are still responsible for backups, observability, monitoring, etc. Every self-hosting situation is different so this is intended to get you started in the right direction.
#Prerequisite
One or more servers with Docker installed. See above guide or the Official Docker Install Guide for instructions.
#Setup Guide
Set up a Docker swarm using:
docker swarm init
This will output a command that you can run on the other servers to join the swarm.
Create an overlay network
docker network create -d overlay --attachable caddy
This will create an overlay network called "caddy" that we will use for the reverse proxy. --attachable is provided so that if needed in the future, a standalone container can be attached for debugging / monitoring purposes.
Assign labels to stabilize machine assignments
docker node update --label-add caddy=true --label-add storage=true <node-name>
For each machine that you would like to accept requests, make sure you assign the "caddy=true" output and point your DNS at that IP address.
Choose one machine that is responsible for file storage and assign the "storage=true" label. This ensures that the Postgres and MinIO containers will always run on that node, preserving your data.
The 'www', 'createbuckets', and 'server' containers can move freely between nodes since they don't have persistent storage requirements.
#Creating The Encryption Keys
The InstantDB backend server requires the presence of a file at /app/resources/config/override.edn to provide keys for encrypting various secrets in the backend. In the single-container self-hosted setup, this is accomplished via a startup script that creates a file persisted to a volume. Since the backend service will be running on multiple machines without shared storage, we instead use Docker Secrets to mount this file.
The easiest way to register this secret is to run the following on a leader machine.
docker run --rm \-v "$PWD:/out" \ghcr.io/instantdb/server:latest \/app/start.sh generate-override-config /out/override.edndocker secret create server_config ./override.edn
#Configuring Environment Variables
Rather than cloning the repo on a server and filling out a .env file, we have provided a script that you can modify and execute to easily deploy the services with the proper configuration.
To get started: clone the repo on your local computer and edit the ./self-hosting/deploy-swarm.sh file.
SSH_HOST=root@ipDASHBOARD_URL="https://dashboard.example.com"SERVER_URL="https://backend.example.com"S3_PUBLIC_ENDPOINT="https://files.example.com"INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_ID="your-client-id.apps.googleusercontent.com"INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_SECRET="your-client-secret"stack_config() {env -i \PATH="$PATH" \DASHBOARD_URL="$DASHBOARD_URL" \SERVER_URL="$SERVER_URL" \S3_PUBLIC_ENDPOINT="$S3_PUBLIC_ENDPOINT" \INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_ID="$INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_ID" \INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_SECRET="$INSTANT_DASHBOARD_GOOGLE_OAUTH_CLIENT_SECRET" \docker stack config --compose-file swarm.yml}stack_config | (ssh $SSH_HOST 'docker stack deploy -c - instant')
Docker Swarm/Stack doesn't support loading environment variables from .env files so we use the docker stack config command to fill out a completed yaml specification and send that to the docker stack deploy command on the swarm's manager node by using stdin over ssh.
SSH_HOST is the username and IP address of the manager node to the swarm you are deploying to.
For DASHBOARD_URL, SERVER_URL, and S3_PUBLIC_ENDPOINT, modify the domain/subdomains to match what you assigned in the DNS for your domain.
To configure other environment variables such as a Postmark token to send emails, add another row in the env -i command. Adding the variables outside of stack_config() will not work in order to prevent accidental leakage of environment variables not meant for the deployment.