Supabase is an open-source Firebase alternative that provides you with all the tools needed to develop your applications. Supabase offers a PostgreSQL database, user authentication, storage and a real-time API and integrates with popular frameworks and tools such as Angular, Flutter, Next.js, React, Svelte and Vue.
There are two ways of using Supabase. The first option is to sign up for their cloud-hosted app, which offers more features. The second option is to self-host the code using Docker. There are a few caveats on self-hosting, though. You cannot create or manage projects. Moreover, the entire project is in the beta phase, and you should use the self-hosted version only for testing and local development. For all other purposes, you should use their cloud application.
In this tutorial, you will learn how to install Supabase on a Debian 11 based server and proxy it via the Nginx server.
Prerequisites
-
A server running Debian 11 with a minimum of 2GB RAM.
-
A non-root user with sudo privileges.
-
A Domain name (
supabase.example.com
) pointing to the server. -
Everything is updated.
$ sudo apt update && sudo apt upgrade
-
Few packages that your system needs.
$ sudo apt install nano ufw software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release debian-archive-keyring -y
Some of these packages may already be installed on your system.
Step 1 - Configure Firewall
The first step is to configure the firewall. Debian comes with ufw (Uncomplicated Firewall).
Check if the firewall is running.
$ sudo ufw status
You should get the following output.
Status: inactive
Allow SSH port so that the firewall doesn't break the current connection on enabling it.
$ sudo ufw allow OpenSSH
Allow HTTP and HTTPS ports as well.
$ sudo ufw allow 80/tcp $ sudo ufw allow 443/tcp
Enable the Firewall
$ sudo ufw enable Command may disrupt existing ssh connections. Proceed with operation (y|n)? y Firewall is active and enabled on system startup
Check the status of the firewall again.
$ sudo ufw status
You should see a similar output.
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) 80/tcp (v6) ALLOW Anywhere (v6) 443/tcp (v6) ALLOW Anywhere (v6)
Step 2 - Install Git
Install Git.
$ sudo apt install git
Confirm the installation.
$ git --version git version 2.30.2
Step 3 - Install Docker
To install the latest version of Docker, add Docker's official GPG key.
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Install the official Docker repository.
$ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Update Debian system repositories.
$ sudo apt update
Install the latest version of Docker.
$ sudo apt install docker-ce docker-ce-cli containerd.io
Verify that Docker is running.
$ sudo systemctl status docker ? docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2022-03-21 03:19:09 UTC; 9s ago TriggeredBy: ? docker.socket Docs: https://docs.docker.com Main PID: 15816 (dockerd) Tasks: 7 Memory: 27.9M CPU: 566ms CGroup: /system.slice/docker.service ??15816 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
By default, Docker requires root privileges. If you want to avoid using sudo
every time you run the docker
command, add your username to the docker
group.
$ sudo usermod -aG docker $(whoami)
You need to log out of the server and back in as the same user to enable this change.
Step 4 - Install Docker Compose
Docker Compose's latest available version is 2.0.x, but for compatibility reasons, we will be installing the older and stable v1.29.2.
Run the following command to download the stable release of Docker Compose.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Apply executable permissions to the binary file.
$ sudo chmod +x /usr/local/bin/docker-compose
Download and install the Docker Compose's bash completion script.
$ sudo curl \ -L https://raw.githubusercontent.com/docker/compose/1.29.2/contrib/completion/bash/docker-compose \ -o /etc/bash_completion.d/docker-compose
Run the following command to apply the changes.
$ source ~/.bashrc
Step 5 - Download and Configure Supabase
Clone the Supabase Github repository.
$ git clone --depth 1 https://github.com/supabase/supabase.git
The --depth 1
parameter does a shallow clone of the repository, i.e., it only pulls the latest commits and not the entire history. This is done to improve the performance.
Switch to the docker directory.
$ cd supabase/docker
Create the environment file from the example file.
$ cp .env.example .env
Open the newly created file for editing.
$ nano .env
Change the value of the variable POSTGRES_PASSWORD
with a strongly generated unique password.
$ POSTGRES_PASSWORD=<yourpostgresqlpwd>
Generate another unique password with more than 32 characters with no special characters. Replace the value of JWT_SECRET
with this password.
JWT_SECRET=<your32pluscharacterspwd>
You can use an online password generator like Bitwarden or 1password to create the above passwords.
Open the Supabase website and enter your JWT_SECRET
to generate an ANON_KEY
. Paste your JWT_SECRET
in the box specified, select ANON_KEY
from the Preconfigured Payload dropdown menu and click on the Generate JWT button to generate the token.
Copy and paste this token as the value for ANON_KEY
in the .env
file.
Similarly, repeat the same steps for generating the SERVICE_KEY
by switching the Preconfigured Payload and pressing the Generate JWT button.
Copy the generated token and paste it as the value for the SERVICE_KEY
in the .env
file.
Configure the email SMTP settings by configuring the following variables. We are using Amazon's SES service for our tutorial.
SMTP_ADMIN_EMAIL=admin@example.com SMTP_HOST=email-smtp.us-west-2.amazonaws.com SMTP_PORT=587 SMTP_USER=<your_amazon_ses_user> SMTP_PASS=<your_amazon_ses_password> SMTP_SENDER_NAME=SupabaseAdmin
Configure the site URL.
SITE_URL=https://supabase.example.com
Configure the public REST URL.
PUBLIC_REST_URL=https://supabase.example.com/rest/v1/
Save the file by pressing Ctrl + X and entering Y when prompted.
The authentication mails sent via SMTP will have broken links because of a bug prevalent in Supabase. To fix this issue, open the docker-compose.yml
file.
$ nano docker-compose.yml
Add the variable API_EXTERNAL_URL
right below the GOTRUE_SITE_URL
variable to look like the following.
GOTRUE_SITE_URL: ${SITE_URL} API_EXTERNAL_URL: ${SITE_URL}
Save the file by pressing Ctrl + X and entering Y when prompted. This file will get overwritten every time you upgrade your Supabase installation. Hopefully, the bug will be fixed next time. You will need to add this variable manually to ensure the email bug doesn't repeat.
Open the volumes/api/kong.yml
file for editing.
$ nano volumes/api/kong.yml
Under the consumers
section, replace the anon
user's key with the ANON_KEY
generated before.
consumers: - username: anon keyauth_credentials: - key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
Also, replace the service_role
's key with the SERVICE_KEY
generated above.
- username: service_role keyauth_credentials: - key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
Save the file by pressing Ctrl + X and entering Y when prompted.
Step 6 - Install Supabase
Run Supabase by using the following command. This process will take some time.
$ docker-compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up -d
Check the status of the running containers.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d25393873731 supabase/storage-api:v0.10.0 "/bin/sh -c \"./stora…" About a minute ago Up About a minute 5000/tcp supabase-storage e6df7dcdd45b supabase/gotrue:v2.5.21 "gotrue" About a minute ago Up About a minute supabase-auth b3a758592d10 supabase/postgres-meta:v0.29.0 "postgres-meta" About a minute ago Up About a minute 0.0.0.0:5555->8080/tcp, :::5555->8080/tcp supabase-meta cdb18c248f79 supabase/realtime:v0.21.0 "bash -c './prod/rel…" About a minute ago Up About a minute supabase-realtime 71417337efae postgrest/postgrest:v9.0.0 "/bin/postgrest" About a minute ago Up About a minute 3000/tcp supabase-rest 2d51af16bd1f kong:2.1 "/docker-entrypoint.…" 2 minutes ago Up About a minute 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 8001/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp, 8444/tcp supabase-kong d6490380e4e8 supabase/postgres:14.1.0 "docker-entrypoint.s…" 2 minutes ago Up About a minute 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp supabase-db 40a49d1482fa supabase/studio:latest "docker-entrypoint.s…" 2 minutes ago Up About a minute 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp supabase-studio 3cce50db9782 inbucket/inbucket:stable "/start-inbucket.sh …" 2 minutes ago Up About a minute (healthy) 0.0.0.0:1100->1100/tcp, :::1100->1100/tcp, 0.0.0.0:2500->2500/tcp, :::2500->2500/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp supabase-mail
Step 7 - Install SSL
To install an SSL certificate using Let's Encrypt, we need to install the Certbot tool.
We will use the Snapd package installer for that. Since most Debian servers don't ship with it, install the Snapd installer.
$ sudo apt install snapd
Ensure that your version of Snapd is up to date.
$ sudo snap install core && sudo snap refresh core
Install Certbot.
$ sudo snap install --classic certbot
Use the following command to ensure that the Certbot command can be run by creating a symbolic link to the /usr/bin
directory.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Verify the installation.
$ certbot --version certbot 1.25.0
Generate the SSL certificate.
$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d supabase.example.com
The above command will download a certificate to the /etc/letsencrypt/live/supabase.example.com
directory on your server.
Generate a Diffie-Hellman group certificate.
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
Create a challenge webroot directory for Let's Encrypt auto-renewal.
$ sudo mkdir -p /var/lib/letsencrypt
Create a Cron Job to renew the SSL. It will run every day to check the certificate and renew if needed. For that, first, create the file /etc/cron.daily/certbot-renew
and open it for editing.
$ sudo nano /etc/cron.daily/certbot-renew
Paste the following code.
#!/bin/sh certbot renew --cert-name supabase.example.com --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"
Save the file by pressing Ctrl + X and entering Y when prompted.
Change the permissions on the task file to make it executable.
$ sudo chmod +x /etc/cron.daily/certbot-renew
Step 8 - Install and Configure Nginx
Debian ships with an older version of Nginx. You need to download the official Nginx repository to install the latest version.
Import the official Nginx signing key.
$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Add the repository for Nginx's stable version.
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \ http://nginx.org/packages/debian `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list
Update the Debian repositories.
$ sudo apt update
Install Nginx.
$ sudo apt install nginx
Verify the installation. Make sure you use sudo
every time you run the Nginx command on Debian. Otherwise, it won't work.
$ sudo nginx -v nginx version: nginx/1.20.2
Create and open the file /etc/nginx/conf.d/supabase.conf
for editing.
$ sudo nano /etc/nginx/conf.d/supabase.conf
Paste the following code in it.
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream supabase { server localhost:3000; } upstream kong { server localhost:8000; } # enforce HTTPS server { listen 80; listen [::]:80; server_name supabase.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name supabase.example.com; access_log /var/log/nginx/supabase.access.log; error_log /var/log/nginx/supabase.error.log; gzip on; # SSL ssl_certificate /etc/letsencrypt/live/supabase.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/supabase.example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/supabase.example.com/chain.pem; ssl_session_timeout 5m; ssl_session_cache shared:MozSSL:10m; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1; ssl_stapling on; ssl_stapling_verify on; ssl_dhparam /etc/ssl/certs/dhparam.pem; resolver 8.8.8.8; client_max_body_size 100m; # REST API location ~ ^/rest/v1/(.*)$ { proxy_set_header Host $host; proxy_pass http://kong; proxy_redirect off; } # Authentication location ~ ^/auth/v1/(.*)$ { proxy_set_header Host $host; proxy_pass http://kong; proxy_redirect off; } # Realtime location ~ ^/realtime/v1/(.*)$ { proxy_redirect off; proxy_pass http://kong; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } # Studio location / { proxy_set_header Host $host; proxy_pass http://supabase; proxy_redirect off; proxy_set_header Upgrade $http_upgrade; } }
Save the file by pressing Ctrl + X and entering Y when prompted once finished.
Open the file /etc/nginx/nginx.conf
for editing.
$ sudo nano /etc/nginx/nginx.conf
Add the following line before the line include /etc/nginx/conf.d/*.conf;
.
server_names_hash_bucket_size 64;
Save the file by pressing Ctrl + X and entering Y when prompted.
Verify the Nginx configuration file syntax.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Start the Nginx service to enable the new configuration.
$ sudo systemctl start nginx
Step 9 - Access Supabase
You can now access Supabase via the URL https://supabase.example.com
in your web browser.
You can't create new projects, but you can manage the existing ones and configure the database, storage, and authentication.
Step 10 - Enable HTTP authentication
Supabase doesn't provide user management, so you need to secure your Supabase installation. The easiest way to do that is to enable HTTP authentication using the Nginx server.
Install apache2-utils
package for Nginx.
$ sudo apt install apache2-utils
Create a password file for the user supabase
. You can choose any username you want. It will prompt you for a new password. Enter a strong password to finish setting up the file.
$ sudo htpasswd -c /etc/nginx/.htpasswd supabase New password: Re-type new password: Adding password for user supabase
The -c
flag tells the utility to create a new file. If you omit the file, you need to specify the location of an existing file.
Open the /etc/nginx/conf.d/supabase.conf
for editing.
$ sudo nano /etc/nginx/conf.d/supabase.conf
Make the changes in the following sections of the file, as shown below.
# REST API location ~ ^/rest/v1/(.*)$ { auth_basic off; proxy_set_header Host $host; proxy_pass http://kong; proxy_redirect off; } # Authentication location ~ ^/auth/v1/(.*)$ { auth_basic off; proxy_set_header Host $host; proxy_pass http://kong; proxy_redirect off; } # Realtime location ~ ^/realtime/v1/(.*)$ { auth_basic off; proxy_redirect off; proxy_pass http://kong; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } # Studio location / { auth_basic “Supabase Studio Login”; auth_basic_user_file /etc/nginx/.htpasswd; proxy_set_header Host $host; proxy_pass http://supabase; proxy_redirect off; proxy_set_header Upgrade $http_upgrade; }
Save the file by pressing Ctrl + X and entering Y when prompted.
Verify the configuration.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Restart the Nginx service.
$ sudo systemctl restart nginx
The next time you open Supabase, you will be greeted with the following login screen.
Step 11 - Update Supabase
Supabase is a constant work-in-progress product and will undergo constant changes. If you use it as a self-hosted instance, you must keep your Supabase installation updated.
Switch to the Supabase directory.
$ cd ~/supabase
Pull the latest Github repository.
$ git pull
Look for any changes in the docker/.env
, docker/volumes/api/kong.yml
files for anything that requires reconfiguration.
Shut down and clean up the existing Docker containers.
$ docker-compose down --remove-orphans
Pull the latest images.
$ docker-compose pull
Start the containers again.
$ docker-compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up -d
Conclusion
This concludes our tutorial on installing Supabase on a Debian 11 based server using the Nginx server as reverse-proxy. If you have any questions, post them in the comments below.