apps/docs/content/guides/self-hosting/self-hosted-proxy-https.mdx
HTTPS is required for production self-hosted Supabase deployments. This guide covers two production approaches using a reverse proxy in front of self-hosted Supabase API gateway, plus a self-signed certificate option for development environment.
You need:
Below are two options for adding a reverse proxy with automatic HTTPS in front of your self-hosted Supabase: Caddy (simpler, zero-config TLS) and Nginx + Let's Encrypt (more control over proxy settings). Both sit in front of Kong and terminate TLS, so internal traffic stays on HTTP.
<Admonition type="tip" label="Using a different reverse proxy?">If you already run HAProxy, Traefik, Nginx Proxy Manager, or another reverse proxy for your infrastructure, you can use it instead of Caddy or Nginx above. The key requirements are:
8000 (or <your-ip>:8000 if the proxy runs outside the Docker network)X-Forwarded headers to all requestsdocker-compose.yml if the proxy runs in the same Docker networkSUPABASE_PUBLIC_URL, API_EXTERNAL_URL, and SITE_URL in .env to your HTTPS URLUpdate the URL configuration in your .env file to use your HTTPS domain:
SUPABASE_PUBLIC_URL=https://<your-domain>
API_EXTERNAL_URL=https://<your-domain>
SITE_URL=https://<your-domain>
Change the following to your domain name and a valid email address:
PROXY_DOMAIN=your-domain.example.com
[email protected]
Pick one of the options below and use the corresponding Docker Compose overlay.
<Tabs scrollable size="small" type="underlined" defaultActiveId="caddy"
<TabPanel id="caddy" label="Caddy (easiest)">
Caddy automatically provisions and renews Let's Encrypt TLS certificates with zero configuration. It also handles HTTP-to-HTTPS redirects, WebSocket upgrades, and HTTP/2 and HTTP/3 out of the box.
Start Caddy by using the pre-configured docker-compose.caddy.yml overlay:
docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
Caddy configuration is in volumes/proxy/caddy/Caddyfile.
This option uses a 3rd party Nginx Docker image (jonasal/nginx-certbot), which includes Certbot for automatic Let's Encrypt certificate issuance and renewal in a single container.
Start Nginx by using the pre-configured docker-compose.nginx.yml overlay:
docker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d
Nginx configuration template is in volumes/proxy/nginx/supabase-nginx.conf.tpl. On container startup, ${NGINX_SERVER_NAME} is substituted using the environment variable from the .env file. The jonasal/nginx-certbot image reads the resolved server_name to determine which domain to request a Let's Encrypt certificate for.
HTTP-to-HTTPS redirects are handled automatically by the jonasal/nginx-certbot image.
curl -I https://<your-domain>/auth/v1/
You should receive a 401 response confirming you could connect to Auth.
Self-signed certificates trigger browser warnings and are rejected by most OAuth providers. Use this approach only in development environment or internal networks.
</Admonition>For development or internal networks where you cannot use Let's Encrypt, you can configure Kong to serve HTTPS directly using self-signed certificates.
Change <your-domain> in the example below, and create certificates with openssl:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout volumes/api/server.key \
-out volumes/api/server.crt \
-subj "/CN=<your-domain>" && \
chmod 640 volumes/api/server.key && \
chgrp 65533 volumes/api/server.key
Comment out Kong's HTTP port mapping in docker-compose.yml:
kong:
# ...
ports:
#- ${KONG_HTTP_PORT}:8000/tcp
Uncomment the certificate volume mounts and SSL environment variables in docker-compose.yml:
kong:
# ... existing configuration ...
volumes:
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
- ./volumes/api/server.crt:/home/kong/server.crt:ro
- ./volumes/api/server.key:/home/kong/server.key:ro
environment:
# ... existing environment variables ...
KONG_SSL_CERT: /home/kong/server.crt
KONG_SSL_CERT_KEY: /home/kong/server.key
Edit your .env file to use HTTPS with the Kong HTTPS port:
SUPABASE_PUBLIC_URL=https://<your-domain>:8443
API_EXTERNAL_URL=https://<your-domain>:8443
SITE_URL=https://<your-domain>:8443
docker compose down && docker compose up -d
curl -I -k https://<your-domain>:8443/auth/v1/
The -k flag tells curl to accept the self-signed certificate.
If Caddy or Certbot fails to obtain a certificate:
docker logs supabase-caddy or docker logs supabase-nginxIf Realtime subscriptions fail to connect:
Upgrade and Connection headers on the /realtime/v1/ location. Verify your nginx.conf includes these headers as shown aboveIf OAuth redirects fail with a callback URL error:
API_EXTERNAL_URL in .env is set to your HTTPS URLAPI_EXTERNAL_URL followed by /auth/v1/callbackAPI_EXTERNAL_URL, restart all services with docker compose down && docker compose up -dIf the browser console shows mixed content errors:
SUPABASE_PUBLIC_URL is set to your HTTPS URLSITE_URL is also set to HTTPSThis is expected when using self-signed certificates. For production, use Caddy or Nginx with Let's Encrypt. If you need to use self-signed certificates, add the certificate to your system's trust store or use a browser flag to bypass the warning.