SSD Nodes Learn 8GB de RAM — $66/ano
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-02

Como hospedar o Supabase em um VPS com Docker

Aprenda a executar a pilha oficial do Supabase com Docker: troque os secrets padrão, entenda os 14 serviços, dimensione a RAM, faça backups e atualize sem perder o banco.

O que você vai criar

Hospedar o Supabase por conta própria significa executar a pilha oficial do Docker Compose no seu próprio servidor: Postgres, uma API REST na frente dele, um serviço de autenticação, armazenamento de arquivos, websockets em tempo real e o painel do Studio. Você clona um repositório, edita um arquivo .env e inicia cerca de quatorze contêineres que, juntos, funcionam como um projeto do Supabase sob seu controle.

A instalação é curta. O problema geralmente está no arquivo .env. Ele vem com secrets de demonstração publicados no repositório, e uma pilha iniciada com esses valores padrão fica aberta para qualquer pessoa que os encontre. Este guia aborda os secrets que você precisa substituir, a finalidade de cada serviço, a quantidade de memória de que a pilha realmente precisa e como atualizá-la sem excluir seu banco de dados.

Se o Compose ainda for novidade para você, leia primeiro Noções básicas do Docker Compose em um VPS. Tudo abaixo pressupõe que docker compose version já exiba uma versão.

O que a pilha realmente contém

O Supabase não é um único programa. O arquivo Compose inicia um conjunto de serviços separados em uma única rede. Saber a função de cada serviço transforma uma lista extensa de nomes de contêineres em algo que você pode depurar.

  • db é o PostgreSQL com as extensões do Supabase carregadas. Todos os outros serviços se comunicam com ele. Se este contêiner estiver com problemas, todo o restante também falhará.
  • kong é o gateway da API. Ele escuta na porta 8000 e roteia /rest/v1/, /auth/v1/ e /storage/v1/ para o backend correto. É o único contêiner que você deve expor.
  • rest é o PostgREST. Ele lê o esquema do Postgres e o disponibiliza como uma API REST. Assim, uma nova tabela se torna um novo endpoint sem código adicional.
  • auth é o GoTrue. Ele emite os JSON Web Tokens (JWT) que identificam seus usuários.
  • storage e imgproxy lidam com uploads de arquivos e redimensionamento de imagens.
  • realtime transmite alterações do banco de dados por websockets.
  • studio e meta são o dashboard e a API de administração usada por ele.
  • analytics (Logflare) e vector coletam logs, e supavisor é o pooler de conexões do Postgres.

Essa lista explica por que os números de recursos abaixo são os que são. Você não está executando apenas um banco de dados. Está executando um banco de dados com uma dúzia de serviços de suporte.

Dimensionamento: planeje 8 GB de RAM

A stack usa aproximadamente 2.5 a 3 GB de memória residente em uma instalação nova, em julho de 2026, antes dos seus próprios dados ou do tráfego. O serviço de analytics e o processo Studio Node.js são os dois maiores consumidores individuais. Um servidor com 2 GB iniciará os containers e depois perderá um deles para o OOM killer do kernel, geralmente analytics ou db. O sintoma é um container preso em reinicialização, com código de saída 137.

Use 8 GB de RAM e 4 vCPU para qualquer ambiente do qual você dependa. 4 GB funcionam para uma instância de desenvolvimento individual, se você aceitar que uma consulta pesada e uma sessão do Studio ao mesmo tempo serão lentas. O disco também importa, porque o Postgres, o volume de armazenamento e os dados de log ficam no diretório do projeto. Comece com 40 GB e monitore o uso.

Instalação: clone o repositório oficial

O procedimento compatível copia o diretório docker do repositório principal para um diretório de projeto próprio. Essa separação é importante porque impede que um git pull posterior substitua seu .env.

git clone --depth 1 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/* supabase-project
cp supabase/docker/.env.example supabase-project/.env
cd supabase-project
docker compose pull

docker compose pull baixa vários gigabytes de imagens. O comando deve terminar com todos os serviços marcados como Pulled. Um erro manifest unknown nesse ponto significa que a tag de imagem fixada foi removida no repositório upstream. A correção é baixar uma cópia mais recente do repositório, em vez de editar as tags manualmente.

Os segredos que você deve alterar antes da primeira inicialização

Faça isso antes de iniciar a stack, não depois. Vários desses valores são gravados nos dados na primeira inicialização. Alterá-los depois exige redefinir o banco de dados.

O repositório inclui um gerador que produz todos os valores corretamente, incluindo as duas chaves de API que devem ser assinadas com o novo segredo JWT.

sh utils/generate-keys.sh --update-env

Esse script grava novos valores para JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY e os tokens do Logflare em .env. Ele precisa de openssl, presente em qualquer imagem normal do Ubuntu.

Há dois valores que ele não define. Você deve editá-los manualmente em .env:

  • POSTGRES_PASSWORD. Use apenas letras e dígitos. A pontuação aqui interrompe as strings de conexão que vários serviços montam concatenando strings. A falha parece um erro de autenticação, não um erro de análise. Isso faz com que a investigação siga a direção errada.
  • DASHBOARD_USERNAME e DASHBOARD_PASSWORD. Essas são as credenciais de autenticação básica do Studio. A senha padrão fornecida é literalmente this_password_is_insecure_and_should_be_updated.

Entenda por que ANON_KEY e SERVICE_ROLE_KEY não podem ser inventados. Ambos são JWTs assinados com JWT_SECRET. O gateway verifica essa assinatura em cada solicitação. Portanto, uma chave que não corresponde ao seu segredo é rejeitada com {"message":"Invalid authentication credentials"}. Esta é a falha mais comum em instalações autogerenciadas: o operador alterou JWT_SECRET, mas manteve as chaves de demonstração. Gere os três juntos, sempre.

Trate SERVICE_ROLE_KEY como uma senha de root. Ele ignora completamente a segurança em nível de linha. Deve ser usado em código no lado do servidor e em nenhum outro lugar.

Defina SITE_URL e API_EXTERNAL_URL como o endereço que seus usuários realmente acessarão, por exemplo, https://supabase.example.com. O Auth cria os links de confirmação de email e de retorno do OAuth a partir desses valores. Portanto, deixá-los como http://localhost:8000 envia todos os seus usuários para a própria máquina deles.

Depois, verifique o que você tem:

sh run.sh secrets

Inicie-o e confirme se está saudável

sh run.sh start
docker compose ps

run.sh start encapsula docker compose up -d --wait, portanto não retorna até que as verificações de integridade sejam aprovadas. Cada serviço deve mostrar running (healthy) ou running. A primeira inicialização leva de dois a quatro minutos porque o Postgres executa seus scripts de inicialização antes que qualquer outro componente possa se conectar.

Se um container estiver reiniciando, leia os logs pelo nome do serviço:

docker compose logs db
docker compose logs auth

O Studio estará na porta 8000 e solicitará o nome de usuário e a senha do dashboard que você definiu.

Não exponha a porta 8000 à Internet pública

O Kong na porta 8000 usa HTTP simples. Todas as chaves de API e todas as senhas de usuário atravessam a rede em texto não criptografado. As credenciais do Studio usam autenticação básica, que é codificação base64, não criptografia.

Coloque um proxy reverso à frente dele, encerre o TLS (segurança da camada de transporte) nesse proxy e faça o Kong escutar no endereço de loopback para impedir qualquer outro acesso. Em docker-compose.yml, o mapeamento de portas kong torna-se 127.0.0.1:8000:8000, e o proxy encaminha as solicitações para essa porta. Traefik à frente de vários aplicativos Compose aborda a configuração dos certificados.

Feche também as demais portas no firewall, porque o Docker publica portas gravando suas próprias regras do iptables, que uma configuração ingênua do ufw não consegue ver. Essa armadilha é explicada em por que os contêineres do Docker ignoram suas regras do ufw.

Faça backup do banco de dados, não do diretório

Os dados do Postgres ficam em um bind mount em ./volumes/db/data. Copiar esse diretório enquanto o container está em execução gera uma cópia inconsistente, porque o Postgres mantém as gravações em buffer e os arquivos no disco só ficam consistentes durante um checkpoint. A restauração geralmente funcionará, mas às vezes perderá silenciosamente as últimas transações. Esse é o pior tipo de falha possível em um backup.

Faça um dump. pg_dumpall é executado dentro do container e produz um snapshot consistente:

docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sql

Verifique se o arquivo não está vazio antes de confiar nele. Depois, envie esses dumps para fora do servidor conforme uma programação. É para isso que servem os backups criptografados externos com restic. Faça backup do seu .env ao mesmo tempo. Perder JWT_SECRET invalida todos os tokens emitidos e torna ilegível todo segredo criptografado armazenado.

Os arquivos enviados ficam em ./volumes/storage. Como são arquivos comuns, uma cópia simples é suficiente.

Atualizar sem perder dados

O Supabase fixa as versões das imagens em docker-compose.yml, portanto nada muda até que você faça a atualização. Faça um dump antes, sempre.

docker compose pull
sh run.sh recreate

recreate interrompe a stack e a inicia novamente com as novas imagens. Seus dados permanecem porque ficam nos bind mounts no host, não dentro dos containers. Leia CHANGELOG.md no repositório antes de uma atualização de versão principal, pois as atualizações principais do Postgres não são automáticas e exigem um dump e uma restauração.

Para aplicar alterações no próprio arquivo Compose, clone novamente o repositório upstream e copie o diretório docker para o seu projeto, tomando cuidado para não substituir .env.

A redefinição completa, que destrói tudo, incluindo o banco de dados, é feita por um script separado que solicita confirmação:

sh reset.sh

FAQ

Por que minhas chamadas de API retornam "Invalid authentication credentials"?

Seu ANON_KEY ou SERVICE_ROLE_KEY não foi assinado com o JWT_SECRET atualmente definido em .env. O gateway verifica a assinatura em cada solicitação e rejeita valores incompatíveis. Gere os três novamente juntos com sh utils/generate-keys.sh --update-env e execute sh run.sh recreate para que os serviços leiam os novos valores.

Posso executar o Supabase auto-hospedado em um VPS com 2 GB?

Não de forma confiável. A stack fica próxima de 3 GB em estado ocioso desde July 2026 porque executa cerca de fourteen serviços. Por isso, um servidor com 2 GB perde containers para o out of memory killer, e você vê o código de saída 137 em docker compose ps. Use 8 GB em produção e considere 4 GB o mínimo para desenvolvimento individual.

O Supabase auto-hospedado inclui edge functions?

Sim. O arquivo Compose inclui o runtime de funções baseado em Deno e disponibiliza tudo o que você colocar em ./volumes/functions. Ele não inclui a rede global de implantação da plataforma hospedada. Portanto, suas funções são executadas em um único servidor e em uma única localização.

Como me conecto diretamente ao banco de dados Postgres?

Use docker exec -it supabase-db psql -U postgres para abrir um shell interativo no próprio servidor. Para um cliente externo, conecte-se ao Supavisor na porta 5432 usando o usuário postgres.<POOLER_TENANT_ID> e seu POSTGRES_PASSWORD. Não exponha essa porta à internet. Acesse-a por uma VPN ou por um túnel SSH.

Por que os e-mails de confirmação da autenticação apontavam para localhost?

SITE_URL e API_EXTERNAL_URL em .env permaneceram com os valores padrão. O serviço de autenticação cria todos os links de confirmação e redefinição de senha com base nesses dois valores. Por isso, ele envia o endereço configurado. Defina ambos com sua URL pública real e recrie a stack.