Docs/ Bases de données/ Chaînes de connexion

Chaînes de connexion

sh0 ne branche pas les bases à vos applications à votre place. Vous lisez les informations de connexion, créez une base et un utilisateur pour l'application, et posez DATABASE_URL vous-même. Cette page montre chaque étape avec les commandes telles qu'elles s'exécutent.

Warning
Aucune variable n'est injectée automatiquement. Créer un serveur de bases n'ajoute ni DATABASE_URL, ni REDIS_URL, ni aucune autre variable à vos applications, quel que soit leur projet. Une application qui attend DATABASE_URL ne reçoit rien tant que vous ne l'avez pas posée.

Trouver les informations de connexion

Dans le tableau de bord, ouvrez Bases, puis le serveur : Informations de connexion affiche l'Hôte interne, le port, le mot de passe administrateur et une URL de connexion à copier.

En ligne de commande, sh0 db connection-info prend l'identifiant du serveur affiché à sa création (ou par 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/

Utilisez l'URL Internal depuis vos applications. L'URL External pointe vers un port lié à 127.0.0.1 sur le serveur : il ne répond que depuis le serveur lui-même (voir « Se connecter depuis votre poste »).

Une base et un utilisateur par application

Un serveur démarre sans aucune base et avec le seul compte administrateur. Donnez à chaque application sa propre base et son propre utilisateur plutôt que le mot de passe administrateur. Dans le tableau de bord : Créer une base de données, Créer un utilisateur, puis Accorder l'accès. En ligne de commande :

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.
  • Règles de mot de passe -- au moins une majuscule et un symbole, entre autres ; un mot de passe qui en manque une est refusé avec la règle enfreinte. Le bouton Générer du tableau de bord en produit un conforme ; enregistrez-le, il ne sera plus affiché.
  • Droits -- all ou readonly. Toute autre valeur est refusée.

Poser DATABASE_URL sur l'application

Construisez l'URL à partir de l'hôte interne, du port du moteur, de l'utilisateur et de la base, et enregistrez-la comme variable d'environnement de l'application. Les variables s'appliquent au déploiement : redéployez.

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

La forme de l'URL selon le moteur (remplacez les noms par les vôtres ; le port interne est le port par défaut du moteur, pas celui affiché sous Port) :

  • PostgreSQL -- postgresql://appuser:<password>@my-pg.internal:5432/appdb
  • MySQL et MariaDB -- mysql://appuser:<password>@my-mysql.internal:3306/appdb
  • Redis -- redis://:<password>@my-redis.internal:6379
Note
Plusieurs applications d'un même projet utilisent la même base ? Posez la variable une fois sur le projet : les variables de projet atteignent toutes les applications du projet, et une variable de même nom sur une application l'emporte. Les caractères spéciaux d'un mot de passe (@, :, /, #…) doivent être encodés en pourcentage dans une URL. Les tâches planifiées ne reçoivent pas ces variables -- voir Tâches planifiées.

Réseau interne

Les applications et les serveurs de bases partagent le réseau Docker de sh0. Une application joint un serveur par <nom-du-serveur>.internal sur le port du moteur -- mesuré depuis un conteneur d'application : une connexion TCP vers my-pg.internal:5432 s'ouvre, et appuser se connecte à appdb avec l'URL ci-dessus.

Note
Ce trafic reste sur le réseau Docker du serveur et n'est pas chiffré en TLS. C'est la norme pour une base posée à côté de son application sur la même machine ; ce n'est plus vrai dès que vous ouvrez l'accès externe.

Se connecter depuis votre poste

Pour joindre une base depuis votre poste (pgAdmin, TablePlus, DBeaver, psql), il y a deux voies. Préférez la première.

Tunnel SSH (recommandé)

Le port affiché sous Port (ici 32962) est lié à 127.0.0.1 sur le serveur. Faites-le suivre par SSH : rien n'est exposé sur Internet, et l'accès est celui de votre clé 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"

Accès externe

Activer l'accès externe sur le serveur ouvre un port public via le proxy de sh0. Ce que le code de la version publiée impose :

  • IP autorisées obligatoires -- des adresses ou des plages CIDR ; 0.0.0.0/0 et ::/0 sont refusées.
  • TLS exigé par défaut.
  • Expiration -- 1 h, 6 h, 24 h, 7 jours, 30 jours, ou permanente.
  • Port -- le premier libre dans la plage 10000-10999 ; votre pare-feu doit le laisser passer.
Warning
Cette section décrit le code ; elle n'a pas été exercée sur notre serveur de démonstration, où ouvrir une base sur Internet n'a délibérément pas été fait. Préférez le tunnel SSH, et si vous ouvrez l'accès, gardez une liste d'IP étroite et une expiration.

Pooling de connexions

Chaque base a une limite de connexions (100 par défaut pour PostgreSQL). Dimensionnez vos pools pour que l'ensemble des répliques reste en dessous.

  • Utilisez le pool intégré de votre framework -- la plupart des ORM et des pilotes en ont un.
  • Répartissez la limite entre les répliques -- avec 3 répliques d'une application et une limite de 100, environ 30 connexions par réplique, moins ce qu'utilisent les autres applications.
  • Fixez des délais d'inactivité pour que les connexions dormantes rendent leur place.
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
});

Exemples pour les frameworks courants

Chaque exemple ci-dessous lit la variable DATABASE_URL que vous avez posée sur l'application.

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"))