Self-host Synch on Cloudflare
Create your own Synch server on Cloudflare and connect the Obsidian plugin to it.
This guide walks you through creating your own Synch server on a free Cloudflare account, then pasting that server address into the Obsidian plugin. The button below lets Cloudflare prepare most of the setup for you.
Prefer to avoid Cloudflare entirely and run on your own hardware instead? See the self-hosting guide for Docker or systemd.
Before you deploy
You can start with a free Cloudflare account. If your Cloudflare account is new, enable R2 first. In the Cloudflare dashboard, open R2 Object Storage, register a payment card, and turn R2 on. If you skip this step, the deployment can fail.

Deploy the API
-
Click Deploy to Cloudflare.
-
Sign in to Cloudflare and choose the account you want to use.
-
Follow the prompts to connect your GitHub account to Cloudflare.
-
When you reach the secrets screen, enter these three values:
AUTH_ALLOWED_EMAILS- comma-separated email addresses allowed to create accounts, for exampleyou@example.com,family@example.comBETTER_AUTH_SECRETSYNC_TOKEN_SECRET
The wizard always asks for these three, even if you plan to sign in with single sign-on afterwards instead of a password - see Single sign-on (OIDC) below for why
AUTH_ALLOWED_EMAILSis still needed here.
Click the button, then paste each value into the matching Cloudflare field.
- Click Deploy to start, then wait for the deployment to complete.

Connect Obsidian
After deployment, copy your Synch server address from the Cloudflare Worker Settings tab. It usually looks like this:
https://your-synch-api.your-account.workers.dev

- Open Obsidian.
- Go to Settings.
- Open Synch.
- In Self-hosted server, paste the Synch server address you copied. Do not include a trailing
/. - Click Save.
- Continue sign-in and vault setup normally.
Single sign-on (OIDC)
Synch can authenticate through any standards-compliant OpenID Connect provider - Keycloak, Authentik, Authelia, Zitadel, Dex, Okta, Entra ID, Auth0, and others all work. This isn’t tied to one vendor.
OIDC isn’t part of the Deploy to Cloudflare wizard above, so it’s set up afterwards. In the Cloudflare dashboard, open your Worker’s Settings → Variables and Secrets and add:
OIDC_DISCOVERY_URL- your provider’s discovery document, typically ending in/.well-known/openid-configurationOIDC_CLIENT_IDOIDC_CLIENT_SECRET
These three belong together: set all of them, or none of them. Setting only one or two is treated as a broken configuration, not a disabled feature - the Worker fails requests until the missing value is filled in, rather than quietly running without OIDC. Add OIDC_CLIENT_SECRET as a Secret, not a Variable - equivalently, wrangler secret put OIDC_CLIENT_SECRET from apps/api if you’re working from a checkout. Never put it in a vars entry in a committed config file.
Whatever provider you use, register this exact redirect URI with it:
{PUBLIC_URL}/api/auth/callback/oidc
using your own Worker’s address in place of {PUBLIC_URL} - for example https://your-synch-api.your-account.workers.dev/api/auth/callback/oidc. Getting this path wrong is the single most common way to lose an hour on OIDC setup; most providers call it a “redirect URI” or “callback URL” on their own client configuration screen.
Optional variables:
OIDC_PROVIDER_NAME- label shown on the sign-in button. Defaults toSingle sign-on.OIDC_SCOPES- comma-separated scopes to request. Defaults toopenid,profile,email.OIDC_ACCOUNT_ISSUER- overrides the issuer identity used to scope linked accounts. Defaults to the full issuer returned by discovery, including any tenant or realm path. Normally leave this unset; assigning the same override to different issuers can confuse their accounts.
If upgrading from the first OIDC implementation, stored account issuers may contain only the discovery URL’s origin. Do not automatically carry that namespace to a different tenant. With the same verified email, the normal account-linking rules can attach the new full-issuer identity to the existing user. If emails have changed, review the affected accounts before migrating; do not fall back to matching subjects across issuers.
Verified email addresses
Your provider must also mark each user’s email address as verified - the email_verified claim in the ID token it issues. Synch rejects sign-ins whose email the provider hasn’t verified, the same rule it applies to Google and GitHub sign-in, and the sign-in page tells the user why. Some providers leave addresses unverified by default. Pocket ID, for example, only marks emails as verified once its EMAILS_VERIFIED setting is turned on, and that applies to addresses added or changed afterwards - so mark any users you created earlier as verified individually.
Account linking by email
When someone signs in through OIDC, Synch links that session to any existing local account with the same email address instead of creating a duplicate. This is deliberate: someone who registered with a password before OIDC was set up keeps their existing vaults after switching to single sign-on.
One consequence is worth knowing before you rely on this. Self-hosted Synch doesn’t send verification emails, so registering an address here never proves control of it - and that’s true regardless of whether your provider verifies addresses on its own side. So if password sign-up is still open, anyone could register one of your allowed addresses before its real owner ever signs in through your provider - and would then be linked to that account the moment the real owner does. Vault contents stay safe either way, since they’re encrypted on the client with a passphrase the server never sees; what’s exposed in that scenario is a session, the vault list and its metadata, the encrypted blobs, and the ability to delete or purge vaults - not the notes themselves. This is also why reusing your account password as your vault passphrase isn’t a good idea: it collapses a separation the encryption is designed to preserve.
Setting AUTH_EMAIL_PASSWORD=disabled (see below) closes this off, since no password account - and so no address to register ahead of its owner - can be created.
Turning off password sign-in
Password sign-up stays enabled by default alongside OIDC. Once you’ve confirmed OIDC sign-in works, you can require it exclusively by setting AUTH_EMAIL_PASSWORD to disabled. Do this as a second step after a normal deploy - it isn’t offered by the wizard, and the wizard’s AUTH_ALLOWED_EMAILS prompt happens either way, because password sign-up is on by default and the allowlist is the only thing gating it. Once AUTH_EMAIL_PASSWORD=disabled takes effect, AUTH_ALLOWED_EMAILS is optional. If supplied, it still restricts new Google/GitHub accounts; OIDC accounts are exempt.
If your provider is unreachable
Discovery runs only when an OIDC operation needs it. Password login, Google/GitHub login, existing session checks and sync do not wait for it. The SSO button stays visible so you can retry after an outage. If initialization fails or takes more than three seconds, the OIDC request returns 503 OIDC_UNAVAILABLE.
On Node, failed initialization can retry after a two-second cooldown. The auth library does not expose cancellation for discovery, so a still-running fetch is retained instead of starting overlapping requests; a late successful response becomes usable automatically. On Cloudflare, initialization is scoped to the OIDC request. The three-second limit applies to initialization, not the subsequent token exchange. Local sign-out does not require contacting the identity provider.
Troubleshooting: everything returns internal_error after changing secrets
If every route - including /health - starts returning {"error":"internal_error"} right after you add or edit OIDC secrets, the most likely cause is an incomplete OIDC variable set (for example, OIDC_CLIENT_ID set but OIDC_CLIENT_SECRET still missing, or a typo in a name). That failure happens before the Worker has registered its routes, including the health check, so the generic error is all you’ll see in the response. Check wrangler tail, or the Logs tab in the Cloudflare dashboard, to see which variable is actually missing.
Update your server
Only enable this if you want an easy way to update your server later. You only need to set it up once.
Server update setup (optional)
Paste your deployment repository URL and select the button below.
Enter a valid github.com repository URL.
- Use the initializer above and commit the pre-filled workflow on GitHub.
- Go to the repository’s Actions tab.
- Run the Update Synch server workflow whenever you want to update.
Cloudflare then rebuilds and redeploys your server automatically. Your secrets and data are not affected, but any changes you committed yourself (except wrangler.jsonc and workflow files) are overwritten. If the run summary lists items under Manual attention needed, follow the instructions there.