Self-hosted
The self-hosted edition runs Plotic on your own server. It shares the writing core with the cloud edition while the infrastructure, database and backups stay under your control.
Requirements
- Docker with Compose.
- A server where you can publish the application.
- Separate secret values for the database, authentication and collaboration.
Quick start
From the repository root:
cp .env.example .env
openssl rand -base64 32
docker compose up -d --buildSet different values for POSTGRES_PASSWORD, BETTER_AUTH_SECRET and COLLABORATION_SECRET. Then open http://localhost or the domain you configured.
Google sign-in and Turnstile protection are optional. To enable either one, add both variables in its pair (GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET or TURNSTILE_SITE_KEY + TURNSTILE_SECRET_KEY) and rebuild the application; the server refuses to start when a pair is incomplete.
Google sign-in
Each self-hosted installation should use its own Google credentials. Do not copy credentials from another installation.
Open Google Cloud Console, create or select a project, and configure the OAuth consent screen.
Go to APIs & Services → Credentials → Create Credentials → OAuth client ID.
Choose Web application.
Add the exact redirect URI for your installation:
texthttps://your-domain.example/api/auth/callback/googleFor local Docker Compose use
http://localhost/api/auth/callback/google; for server development without Compose usehttp://127.0.0.1:3000/api/auth/callback/google. The host and protocol must matchPLOTIC_ORIGIN/BETTER_AUTH_URL.Copy the client ID and secret into
.env:envPLOTIC_ORIGIN=https://your-domain.example GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=...Better Auth uses that URL to build the callback. See the official Better Auth Google guide.
Turnstile bot protection
Turnstile protects account creation; normal sign-in does not require a captcha.
Open the Cloudflare Turnstile dashboard and select Turnstile → Add widget.
Create a Managed widget and add your installation's exact hostname, for example
your-domain.example.Enter only the hostname: do not include
https://, paths, or ports. For local development, use a separate widget withlocalhostand127.0.0.1.Leave Pre-clearance disabled, create the widget, and copy the sitekey and secret key.
Add them to
.env:envTURNSTILE_SITE_KEY=... TURNSTILE_SECRET_KEY=...The sitekey is used in the browser; the secret key must stay on the server. See Cloudflare's widget creation guide and hostname management guide.
Rebuild the application after changing these variables:
docker compose up -d --buildTo disable either integration, leave both variables in its pair empty. Never commit secrets to Git. For local tests, use Cloudflare's official Turnstile test keys, never production keys.
Verify the installation
docker compose ps
curl http://localhost/api/health
pnpm selfhost:verifyThe complete reference and Nginx setup are in the repository README.