Configure HTTPS, OAuth, and Backups for Self-Hosted Supabase

Updated on Aug 18, 2026
Kimberly N
9 MINS READ
Table of Contents
Configure OAuth Self-Hosted Supabase

If you run your own backend, deploying Supabase is just step one. The real work starts when you need to configure HTTPS, point a real domain, configure OAuth self-hosted Supabase to work with providers like Google or GitHub, and put a backup plan in place so you do not lose user data. This guide covers all of that.

If you haven't set up Supabase yet, you can check this guide on Self-hosting Supabase with Docker Compose and then follow the steps below to handle HTTPS, OAuth, and backups.

What You Need Before You Start

Before you configure OAuth self-hosted Supabase, make sure you have all of this ready:

  • A Linux server running Ubuntu 22.04 or newer with Docker and Docker Compose installed.
  • A domain name with an A record pointing to your server's public IP.
  • Ports 80 and 443 are open in your firewall.
  • Your Supabase Docker stack is pulled and ready in a folder, for example, /opt/supabase.

For a stable setup, your server should have at least 4 GB of RAM and fast disks. Running Supabase, PostgreSQL, GoTrue Auth, and Kong on a shared VPS can cause bottlenecks under real traffic. A reliable dedicated server gives you full CPU and RAM resources with no noisy neighbors, making it a good choice once you move to production.

Step 1: DNS Setup

You must point your domain to the server before anything else. Go to your domain registrar's DNS panel and create an A record:

Field Value
Name api or @ for root
Type A
Value Your server's public IP
TTL 300 (5 minutes)

Wait a few minutes, then verify it works:

Bash
# Check DNS resolutiondig api.yourdomain.com +short # Or use pingping api.yourdomain.com

You should see your server IP in the output. Do not move forward until DNS resolves correctly; Caddy and Certbot both need it to issue an SSL certificate.

A simple domain registration service like PerLod lets you search, buy, and manage DNS records in one place, which makes the rest of this guide easier to follow.

Step 2: Configure HTTPS for Supabase

You can easily configure HTTPS with Caddy and Nginx. Here we will show you both options:

Option A: Use Caddy for HTTPS Configuration

Supabase ships with a ready-made Caddy override file. Caddy automatically handles Let's Encrypt certificates, renewals, HTTPS redirects, and WebSocket upgrades with zero extra config.

First, you must update your .env file and edit the URL variables to use HTTPS and your real domain:

Bash
nano /opt/supabase/.env

Change these three lines:

Bash
SUPABASE_PUBLIC_URL=https://api.yourdomain.comAPI_EXTERNAL_URL=https://api.yourdomain.comSITE_URL=https://api.yourdomain.com

Then, start Caddy with Docker Compose:

Bash
cd /opt/supabasedocker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d

Caddy reads the Caddyfile in volumes/proxy/caddy/ and automatically issues a certificate for your domain.

Verify HTTPS is working:

Bash
# Should return HTTP/2 401, this confirms you connected to Auth over HTTPS.curl -I https://api.yourdomain.com/auth/v1/ # Check Caddy logs if something is wrong.docker logs supabase-caddy

A 401 response is expected and correct here. It means HTTPS is working and the Auth service is responding.

Option B: Use Nginx for HTTPS Configuration

If you prefer Nginx over Caddy, you can use this method instead. First, set Nginx-specific variables in the .env file:

Bash
SUPABASE_PUBLIC_URL=https://api.yourdomain.comAPI_EXTERNAL_URL=https://api.yourdomain.comSITE_URL=https://api.yourdomain.comPROXY_DOMAIN=api.yourdomain.comCERTBOT_EMAIL=admin@yourdomain.com

Start with the Nginx override:

Bash
cd /opt/supabasedocker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d

Verify it is working correctly:

Bash
curl -I https://api.yourdomain.com/auth/v1/docker logs supabase-nginx

Step 3: Configure OAuth Self-Hosted Supabase with Google

When you configure OAuth self-hosted Supabase, you need three things: a correct callback URL registered with the provider, the right .env values, and the matching passthrough lines in docker-compose.yml.

First, create a Google OAuth app:

  • Go to Google Cloud Console.
  • Create or select a project.
  • Go to APIs & ServicesOAuth consent screen → click Get started → set app type to External.
  • Go to APIs & ServicesCredentialsCreate CredentialsOAuth client ID.
  • Set application type to Web application.
  • Under Authorized redirect URIs, add exactly:
    • https://api.yourdomain.com/auth/v1/callback
  • Click Create and copy your Client ID and Client Secret.

Then, add the credentials to the .env file:

Bash
nano /opt/supabase/.env

Uncomment or add these lines:

Bash
GOOGLE_ENABLED=trueGOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.comGOOGLE_SECRET=your-google-client-secret

You must also enable in docker-compose.yml:

Bash
nano /opt/supabase/docker-compose.yml

Find the auth: service block and uncomment or add these environment lines:

YAML
auth:  environment:    # ... existing variables ...    GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}    GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}    GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}    GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback

Restart only the auth container:

Bash
cd /opt/supabasedocker compose up -d --force-recreate --no-deps auth

Verify Google is enabled:

Bash
curl -H 'apikey: your-anon-key' https://api.yourdomain.com/auth/v1/settings

You should see:

JSON
{  "external": {    "google": true  }}

Step 4: Configure OAuth Self-Hosted Supabase with GitHub

The pattern to configure OAuth self-hosted Supabase is the same for every provider. Here is GitHub as a second example.

First, create a GitHub OAuth app:

  • Go to GitHubSettingsDeveloper settingsOAuth AppsNew OAuth App.
  • Set Homepage URL: https://api.yourdomain.com.
  • Set Authorization callback URL: https://api.yourdomain.com/auth/v1/callback.
  • Click Register application and copy your Client ID and Client Secret.

Add to .env file:

Bash
GITHUB_ENABLED=trueGITHUB_CLIENT_ID=your-github-client-idGITHUB_SECRET=your-github-client-secret

Add to docker-compose.yml:

YAML
auth:  environment:    GOTRUE_EXTERNAL_GITHUB_ENABLED: ${GITHUB_ENABLED}    GOTRUE_EXTERNAL_GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}    GOTRUE_EXTERNAL_GITHUB_SECRET: ${GITHUB_SECRET}    GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback

Restart auth:

Bash
docker compose up -d --force-recreate --no-deps auth

The same four steps work for every provider in the table below, just swap the prefix:

Provider Env prefix in .env Extra variable
Google GOOGLE_
GitHub GITHUB_ URL for GitHub Enterprise
GitLab GITLAB_ URL for self-hosted GitLab
Discord DISCORD_
Facebook FACEBOOK_
Azure AZURE_ URL (tenant URL)
LinkedIn LINKEDIN_OIDC_
Slack SLACK_OIDC_

For a complete list of provider-specific environment variables and the latest examples, you can also check the official Supabase guide.

Step 5: Allow Frontend Redirect URLs

After login, Supabase redirects users back to your frontend. If your app lives on a different domain, for example, https://app.yourdomain.com, you must explicitly allow it.

In .env, add:

Bash
ADDITIONAL_REDIRECT_URLS=https://app.yourdomain.com,https://app.yourdomain.com/**

Then restart the auth service:

Bash
docker compose up -d --force-recreate --no-deps auth

Without this, users will hit a redirect error right after a successful OAuth login, one of the most common mistakes when you configure OAuth self-hosted Supabase.

Step 6: Common Misconfigurations That Break Auth

When you configure OAuth self-hosted Supabase for the first time, these are the mistakes that show up most often:

HTTP vs HTTPS mismatch

The callback URL in your OAuth app uses http:// but your server runs on https://. Most providers reject HTTP callbacks. Always use HTTPS when you configure OAuth self-hosted Supabase for any provider.

Bash
# Confirm your API_EXTERNAL_URL is HTTPSgrep API_EXTERNAL_URL /opt/supabase/.env

Wrong callback path

Some people register https://api.yourdomain.com/callback instead of https://api.yourdomain.com/auth/v1/callback. The /auth/v1/callback path is required; do not shorten it.

Variable added to .env but not passed to the container

The .env values are not automatically available inside containers. They must have a matching GOTRUE_EXTERNAL_* line in docker-compose.yml. Check what the auth container actually sees:

Bash
docker compose exec auth env | grep GOTRUE_EXTERNAL

SITE_URL not set or wrong

After OAuth finishes, GoTrue redirects to SITE_URL. If it is blank or points to localhost in production, users land on the wrong page.

Bash
grep SITE_URL /opt/supabase/.env

Provider still shows false in settings

Run this to confirm the variable reached the container:

Bash
docker compose exec auth env | grep GOOGLE

If nothing shows, your passthrough line in docker-compose.yml is missing or commented out.

Step 7: Database Backups

Once you configure OAuth self-hosted Supabase and real users start signing in, you need a backup plan. All user accounts, tokens, and data live in PostgreSQL. Losing the database means losing everything.

1. Manual backup with pg_dump:

Bash
# Replace 'postgres' with your DB user if differentdocker compose exec db pg_dump -U postgres postgres > /opt/backups/supabase_$(date +%Y%m%d_%H%M%S).sql

2. Create a backup directory:

Bash
mkdir -p /opt/backupschmod 700 /opt/backups

3. Automate with a daily cron job:

Bash
crontab -e

Add this line to run a backup every day at 2 AM:

Bash
0 2 * * * cd /opt/supabase && docker compose exec -T db pg_dump -U postgres postgres > /opt/backups/supabase_$(date +\%Y\%m\%d).sql

4. Remove backups older than 7 days: Add this line to the same crontab to keep disk usage under control:

Bash
0 3 * * * find /opt/backups -name "*.sql" -mtime +7 -delete

5. Copy backups off-server, for example, with rsync: Do not store all backups on the same machine. Push them to a remote server or object storage:

Bash
# Copy to remote server via rsyncrsync -avz /opt/backups/ user@backup-server:/remote/backups/supabase/

6. Restore from a backup:

Bash
# Stop the app but keep the DB runningdocker compose stop kong auth rest realtime storage # Restorecat /opt/backups/supabase_20260529.sql | docker compose exec -T db psql -U postgres postgres # Start everything againdocker compose start

Step 8: Backup Your Config Files

Your .env and docker-compose.yml files are just as important as the database. If your server dies, you need them to rebuild it.

Bash
# Copy config files to a safe locationcp /opt/supabase/.env /opt/backups/supabase_env_$(date +%Y%m%d).bakcp /opt/supabase/docker-compose.yml /opt/backups/docker-compose_$(date +%Y%m%d).bak

Or push them to a private Git repository without secrets inside, use a secret manager, or environment injection in production.

Step 9: Check Logs for Issues

If login breaks or something is off, always start with the logs:

Bash
# Auth container logs (OAuth errors appear here)docker compose logs auth # All servicesdocker compose logs # Follow logs in real timedocker compose logs -f auth # Check if all containers are runningdocker compose ps

For Nginx or Caddy proxy errors:

Bash
docker logs supabase-caddydocker logs supabase-nginx

Test the Full Supabase OAuth Configuration

You can run a quick HTML test page to confirm everything works once you configure OAuth self-hosted Supabase. Create a test HTML file:

HTML/XML
# Create a test HTML filecat > /tmp/oauth-test.html <<'EOF'<!doctype html><html><body>  <h1>Supabase OAuth Test</h1>  <button id="loginBtn">Sign in with Google</button>  <pre id="result"></pre>  <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>  <script>    document.addEventListener('DOMContentLoaded', function () {      const supabase = window.supabase.createClient(        'https://api.yourdomain.com',        'your-anon-key'      )      document.getElementById('loginBtn').addEventListener('click', async () => {        const { error } = await supabase.auth.signInWithOAuth({ provider: 'google' })        if (error) document.getElementById('result').textContent = JSON.stringify(error, null, 2)      })      supabase.auth.getSession().then(({ data }) => {        if (data.session) {          document.getElementById('result').textContent = 'Logged in as: ' + data.session.user.email        }      })    })  </script></body></html>EOF

Then, serve it locally:

Bash
cd /tmp && python3 -m http.server 3000

Open http://localhost:3000/oauth-test.html in your browser. Click the button. If you land back on the page logged in, your setup is working.

Conclusion

Getting HTTPS, a real domain, and working social logins on a self-hosted Supabase instance requires getting each piece right in order. The most common failures when people configure OAuth self-hosted Supabase include HTTP vs HTTPS mismatches, the wrong callback URL, and missing passthrough lines in docker-compose.yml. Follow the steps above and check the logs when something breaks.

We hope you enjoy this guide.

It is always https://your-domain/auth/v1/callback. Register this exact URL in your OAuth provider console.

The URL registered in your OAuth app and the one in API_EXTERNAL_URL must match exactly, same domain, same path, same HTTPS. A trailing slash or a wrong path breaks it.

No. Pick one. Caddy is simpler and recommended unless you already have Nginx deeply configured in your stack.