Documentação/ Bancos de Dados/ Strings de Conexão

Strings de Conexão

O sh0 não liga os bancos às suas aplicações por você. Você lê as informações de conexão, cria um banco e um usuário para a aplicação e define DATABASE_URL você mesmo. Esta página mostra cada etapa com os comandos como foram executados.

Warning
Nenhuma variável é injetada automaticamente. Criar um servidor de banco de dados não adiciona DATABASE_URL, REDIS_URL nem qualquer outra variável às suas aplicações, seja qual for o projeto. Uma aplicação que espera DATABASE_URL não recebe nada até você defini-la.

Encontrar as informações de conexão

No painel, abra Bancos e depois o servidor: Informações de conexão mostra o Host interno, a porta, a senha de administrador e uma URL de conexão para copiar.

Pela CLI, sh0 db connection-info recebe o ID do servidor exibido na criação (ou por sh0 db list):

Terminal
$ sh0 db create --name my-pg --engine postgres
Database server 'my-pg' created (id: e8afafa4-2ff1-4088-8276-fccb839734a8, engine: postgres 16)

$ sh0 db connection-info e8afafa4-2ff1-4088-8276-fccb839734a8
Connection Info:
  Host:     my-pg.internal
  Port:     32962
  Username: postgres
  Password: <password>
  Internal: postgresql://postgres:<password>@my-pg.internal:5432/
  External: postgresql://postgres:<password>@localhost:32962/

Use a URL Internal nas suas aplicações. A URL External aponta para uma porta ligada a 127.0.0.1 no servidor: ela só responde a partir do próprio servidor (veja “Conectar a partir da sua máquina”).

Um banco e um usuário por aplicação

Um servidor começa sem nenhum banco e apenas com a conta de administrador. Dê a cada aplicação o seu próprio banco e o seu próprio usuário em vez da senha de administrador. No painel: Criar banco de dados, Criar usuário e depois Conceder acesso. Pela CLI:

Terminal
$ sh0 db create-database e8afafa4-2ff1-4088-8276-fccb839734a8 --name appdb
Database 'appdb' created (id: 503a447c-f9f5-44b8-87cf-22c0905f075c).

$ sh0 db create-user e8afafa4-2ff1-4088-8276-fccb839734a8 --username appuser --password '<password>'
User 'appuser' created (id: 86de6179-7e97-463a-93d8-dfd89b1da6e2).

$ sh0 db grant e8afafa4-2ff1-4088-8276-fccb839734a8 \
    --user 86de6179-7e97-463a-93d8-dfd89b1da6e2 \
    --database 503a447c-f9f5-44b8-87cf-22c0905f075c --privileges all
Access granted.
  • Regras de senha -- pelo menos uma letra maiúscula e um símbolo, entre outras; uma senha que não cumpre alguma é recusada com a regra violada. O botão Gerar do painel cria uma válida; guarde-a, ela não será exibida novamente.
  • Privilégios -- all ou readonly. Qualquer outro valor é recusado.

Definir DATABASE_URL na aplicação

Monte a URL com o host interno, a porta do motor, o usuário e o banco, e grave-a como variável de ambiente da aplicação. As variáveis são aplicadas no deploy, então faça um novo deploy:

Terminal
$ sh0 env my-api set "DATABASE_URL=postgresql://appuser:<password>@my-pg.internal:5432/appdb"
[ok] Set DATABASE_URL for 'my-api'

$ sh0 deploy my-api
[*] Deploying my-api...
  Deployment ID: 64492c39-dad0-409f-ad6d-29b71f79bab3
  Status:        queued

O formato da URL por motor (troque os nomes pelos seus; a porta interna é a porta padrão do motor, não a exibida em Port):

  • PostgreSQL -- postgresql://appuser:<senha>@my-pg.internal:5432/appdb
  • MySQL e MariaDB -- mysql://appuser:<password>@my-mysql.internal:3306/appdb
  • Redis -- redis://:<senha>@my-redis.internal:6379
Note
Várias aplicações do mesmo projeto usam o mesmo banco? Defina a variável uma vez no projeto: as variáveis de projeto chegam a todas as aplicações do projeto, e uma variável de mesmo nome numa aplicação tem prioridade. Caracteres especiais numa senha (@, :, /, #…) precisam ser codificados com percentual numa URL. As tarefas agendadas não recebem essas variáveis -- veja Tarefas agendadas.

Rede interna

As aplicações e os servidores de banco compartilham a rede Docker do sh0. Uma aplicação alcança um servidor por <nome-do-servidor>.internal na porta do motor -- medido a partir de um contêiner de aplicação: uma conexão TCP para my-pg.internal:5432 abre, e appuser entra em appdb com a URL acima.

Note
Esse tráfego fica na rede Docker do servidor e não é cifrado com TLS. É o normal para um banco ao lado da aplicação na mesma máquina; deixa de ser assim quando você abre o acesso externo.

Conectar a partir da sua máquina

Para acessar um banco a partir da sua máquina (pgAdmin, TablePlus, DBeaver, psql), há dois caminhos. Prefira o primeiro.

Túnel SSH (recomendado)

A porta exibida em Port (aqui 32962) está ligada a 127.0.0.1 no servidor. Encaminhe-a por SSH: nada fica exposto na internet, e o acesso é o da sua chave SSH.

Your machine
ssh -N -L 5432:127.0.0.1:32962 root@your-server
# in another terminal
psql "postgresql://appuser:<password>@127.0.0.1:5432/appdb"

Acesso externo

Habilitar acesso externo no servidor abre uma porta pública pelo proxy do sh0. O que o código da versão publicada impõe:

  • IPs permitidos obrigatórios -- endereços ou faixas CIDR; 0.0.0.0/0 e ::/0 são recusados.
  • TLS exigido por padrão.
  • Expiração -- 1 h, 6 h, 24 h, 7 dias, 30 dias ou permanente.
  • Porta -- a primeira livre na faixa 10000-10999; o seu firewall precisa liberá-la.
Warning
Esta seção descreve o código; ela não foi exercitada no nosso servidor de demonstração, onde abrir um banco para a internet deliberadamente não foi feito. Prefira o túnel SSH e, se abrir o acesso, use uma lista de IPs restrita e uma expiração.

Pooling de Conexão

Cada banco tem um limite de conexões (100 por padrão no PostgreSQL). Dimensione os pools para que o conjunto das réplicas fique abaixo dele.

  • Use o pool embutido do seu framework -- a maioria dos ORMs e drivers tem um.
  • Divida o limite entre as réplicas -- com 3 réplicas de uma aplicação e limite de 100, cerca de 30 conexões por réplica, menos o que outras aplicações usam.
  • Defina tempos de inatividade para que conexões ociosas liberem a vaga.
Node.js pool configuration
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 20,              // Maximum connections in the pool
  idleTimeoutMillis: 30000,  // Close idle connections after 30s
  connectionTimeoutMillis: 5000, // Fail if connection takes > 5s
});

Exemplos para Frameworks Comuns

Todos os exemplos abaixo leem a variável DATABASE_URL que você definiu na aplicação.

Ruby on Rails (config/database.yml)
production:
  url: <%= ENV['DATABASE_URL'] %>
Django (settings.py, dj-database-url)
import dj_database_url

DATABASES = {"default": dj_database_url.config(conn_max_age=600)}
Rust / SQLx
let pool = PgPoolOptions::new()
    .max_connections(20)
    .connect(&std::env::var("DATABASE_URL")?)
    .await?;
Go / pgx
pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))