MySQL: Prime configurazioni

Come iniziare con MySQL

👋 Benvenuti nella documentazione di Stackhero!

Stackhero offre un servizio MySQL cloud completamente gestito che semplifica il deployment e la gestione per i carichi di lavoro in produzione:

  • Connessioni e trasferimenti di dati illimitati.
  • Interfaccia web phpMyAdmin integrata per una gestione semplice del database.
  • Aggiornamenti senza complicazioni con upgrade in un solo clic.
  • Performance costante e sicurezza avanzata su un'infrastruttura privata e dedicata.

Con Stackhero, potete avere un database MySQL affidabile pronto in pochi minuti. Dedicate meno tempo alla configurazione e alla manutenzione, e più tempo allo sviluppo delle vostre applicazioni. Provate oggi stesso l'hosting MySQL cloud su Stackhero.

Se desidera un metodo rapido per connettersi al suo servizio MySQL, può utilizzare il formato URL di MySQL, a condizione che il driver lo supporti:

mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?useSSL=true&requireSSL=true

Se lavora con Ruby, il formato URL è leggermente diverso:

mysql2://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?reconnect=true&useSSL=true&requireSSL=true

Ecco un esempio di connessione a MySQL in PHP utilizzando l'estensione MySQLi in stile orientato agli oggetti:

<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // Anche se in questo esempio viene utilizzato il database "root", è consigliabile creare un database e un utente dedicati per la sua applicazione tramite phpMyAdmin.

$mysqli = mysqli_init();
$mysqliConnected = $mysqli->real_connect($hostname, $user, $password, $database, $port, NULL, MYSQLI_CLIENT_SSL);
if (!$mysqliConnected) {
  die("Errore di connessione: " . $mysqli->connect_error);
}

echo 'Connessione riuscita... ' . $mysqli->host_info . "\n";

$mysqli->close();

?>

Se preferisce il codice procedurale, ecco come può connettersi utilizzando MySQLi in stile procedurale:

<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // Per una maggiore sicurezza, crei un database e un utente dedicati tramite phpMyAdmin invece di utilizzare "root".

$mysqli = mysqli_init();
$mysqliConnected = mysqli_real_connect($mysqli, $hostname, $user, $password, $database, $port, NULL, MYSQLI_CLIENT_SSL);
if (!$mysqliConnected) {
  die("Errore di connessione: " . mysqli_connect_error($mysqli));
}

echo 'Successo: ' . mysqli_get_host_info($mysqli) . "\n";

mysqli_close($mysqli);

?>

Se preferisce utilizzare PDO per l'accesso al database, ecco un esempio di configurazione della connessione:

<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // È preferibile creare un database e un utente dedicati per la sua applicazione.

$dsn = "mysql:host=$hostname;port=$port;dbname=$database";

$options = array(
  // Se riscontra errori relativi a SSL durante la connessione, verifichi che il sistema disponga dei certificati CA corretti installati (vedi sotto).
  PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/',
  // PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem',
  PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
);

$pdo = new PDO($dsn, $user, $password, $options);

$stm = $pdo->query("SELECT VERSION()");
$version = $stm->fetch();

echo "Connessione a un database con versione " . $version[0] . "\n";

?>

Se visualizza un errore come questo:

Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed

Probabilmente il sistema non dispone dei certificati CA nella directory /etc/ssl/certs/.

Se ha accesso al sistema dove viene eseguito il codice PHP, può aggiungere i certificati come segue:

  1. Su Ubuntu/Debian: sudo apt-get install ca-certificates
  2. Su Alpine Linux: apk add ca-certificates

Se non ha accesso diretto, può aggiungere manualmente il certificato:

  1. Scarichi il certificato: https://letsencrypt.org/certs/isrgrootx1.pem
  2. Inserisca il file isrgrootx1.pem nel suo progetto PHP.
  3. Commenti la riga PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/'
  4. Decommenti la riga PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem'

Se visualizza errori come:

Fatal error: Uncaught Error: Undefined constant PDO::MYSQL_ATTR_SSL_CAPATH

o messaggi simili, significa che PDO è stato installato senza il supporto MySQL.

  1. Su Ubuntu/Debian

Può aggiungere l'estensione necessaria eseguendo:

sudo apt-get install php-mysql
  1. In Docker

Se utilizza Docker, si assicuri che il supporto MySQL sia incluso durante la build. Può aggiungere questa riga al suo Dockerfile:

RUN docker-php-ext-install pdo pdo_mysql

### Utilizzo di MySQL con Symfony e Doctrine

Se lavora con Symfony e Doctrine, può configurare la connessione come segue:

1. Modifichi il file `.env` e imposti la variabile `DATABASE_URL`:

DATABASE_URL="mysql://<USER>:<PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/<DATABASE>"


1. Poi, in `config/packages/doctrine.yaml`, imposti il driver e le opzioni:

```yaml
doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        driver: 'pdo_mysql'
        options:
            # PDO::MYSQL_ATTR_SSL_CAPATH
            1010: '/etc/ssl/certs'
            # PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
            1014: true

Se riscontra un errore come:

Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed

Probabilmente la directory /etc/ssl/certs/ non contiene i certificati CA.

Se ha accesso al sistema, può installarli come segue:

  1. Su Ubuntu/Debian: sudo apt-get install ca-certificates
  2. Su Alpine Linux: apk add ca-certificates

Se non ha accesso diretto, può aggiungere manualmente il certificato:

  1. Scarichi: https://letsencrypt.org/certs/isrgrootx1.pem
  2. Inserisca isrgrootx1.pem nel suo progetto Symfony.
  3. Aggiorni config/packages/doctrine.yaml:
doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        driver: 'pdo_mysql'
        options:
            # PDO::MYSQL_ATTR_SSL_CA
            1009: 'isrgrootx1.pem'
            # PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
            1014: true

Per configurare MySQL in Laravel, apra config/database.php e aggiorni la sezione MySQL:

'mysql' => [
  'driver' => 'mysql',
  'host' => env('STACKHERO_MYSQL_HOST'),
  'port' => env('STACKHERO_MYSQL_PORT'),
  'username' => env('STACKHERO_MYSQL_USER'),
  'password' => env('STACKHERO_MYSQL_PASSWORD'),
  'database' => env('STACKHERO_MYSQL_USER'),
  'charset' => 'utf8mb4',
  'collation' => 'utf8mb4_unicode_ci',
  'prefix' => '',
  'prefix_indexes' => true,
  'strict' => true,
  'engine' => null,
  'sslmode' => 'require',
  'options' => extension_loaded('pdo_mysql')
    ? array_filter([
      // Per errori SSL, consulti la sezione di troubleshooting sopra.
      PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/',
      // PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem',
      PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
    ])
    : [],
],

Nel file di configurazione database.php, può aggiungere:

$db['default'] = array(
  'hostname' => getenv('STACKHERO_MYSQL_HOST'),
  'port'     => getenv('STACKHERO_MYSQL_PORT'),
  'username' => getenv('STACKHERO_MYSQL_USER'),
  'password' => getenv('STACKHERO_MYSQL_PASSWORD'),
  'database' => getenv('STACKHERO_MYSQL_USER'), // Per convenzione, il nome del database corrisponde all'utente.
  'dbdriver' => 'mysqli',
  'dbprefix' => '',
  'pconnect' => true,
  'char_set' => 'utf8',
  'dbcollat' => 'utf8_general_ci',
  'encrypt'  => array() // Importante: abilitare la cifratura TLS
);

È generalmente più sicuro evitare di memorizzare le credenziali del database nel codice. Può utilizzare le variabili d'ambiente. Ecco come recuperarle:

$hostname = getenv('STACKHERO_MYSQL_HOST');
$port = getenv('STACKHERO_MYSQL_PORT');
$user = getenv('STACKHERO_MYSQL_USER');
$password = getenv('STACKHERO_MYSQL_PASSWORD');
$database = getenv('STACKHERO_MYSQL_USER'); // Per convenzione, il nome del database corrisponde all'utente.

Collegare WordPress a Stackhero per MySQL è semplice. Basta modificare il file wp-config.php come segue:

define('DB_HOST', '<XXXXXX>.stackhero-network.com');
define('DB_PORT', '<PORT>');
define('DB_NAME', 'root');
define('DB_USER', 'root');
define('DB_PASSWORD', '<yourPassword>');

// Abilita la cifratura TLS (nota anche come SSL)
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);

Il passaggio fondamentale qui è abilitare la cifratura TLS (SSL). Senza questa impostazione, la connessione non funzionerà correttamente.

Per utilizzare il protocollo MySQL X, può installare il pacchetto ufficiale xdevapi:

npm install @mysql/xdevapi

Ecco un esempio di script:

const mysqlx = require('@mysql/xdevapi');

(async () => {
  // Connessione a MySQL tramite MySQL X Protocol
  const session = await mysqlx.getSession({
    host: '<XXXXXX>.stackhero-network.com',
    port: '<PORT>',
    user: 'root',
    password: '<ROOT_PASSWORD>'
  });

  // Crea lo schema (database) se non esiste
  const schemaExists = await session.getSchema('stackherotest').existsInDatabase();
  if (!schemaExists) {
    await session.createSchema('stackherotest');
  }

  // Crea la tabella 'users' se non esiste
  const tableExists = await session
    .getSchema('stackherotest')
    .getTable('users')
    .existsInDatabase();
  if (!tableExists) {
    await session
      .sql('CREATE TABLE `stackherotest`.`users` '
        + '('
        + '`userId` INT UNSIGNED NOT NULL,'
        + '`name` VARCHAR(128) NOT NULL,'
        + '`address` TEXT NOT NULL,'
        + '`email` VARCHAR(265) NOT NULL'
        + ') '
        + 'ENGINE = InnoDB;')
      .execute();
  }

  // Inserisce un utente di esempio
  await session
    .getSchema('stackherotest')
    .getTable('users')
    .insert('userId', 'name', 'address', 'email')
    .values(
      Math.round(Math.random() * 100000),
      'User name',
      'User address',
      '[email protected]'
    )
    .execute();

  // Conta il numero di utenti
  const usersCount = await session
    .getSchema('stackherotest')
    .getTable('users')
    .count();

  console.log(`Attualmente ci sono ${usersCount} record nella tabella "users"`);

  // Chiude la connessione
  await session.close();

})().catch(error => {
  console.error('');
  console.error('Si è verificato un errore!');
  console.error(error);
  process.exit(1);
});

Se preferisce il protocollo classico, può utilizzare il pacchetto mysql2 con supporto alle promise. Può installarlo con:

npm install mysql2

Esempio di utilizzo:

const mysql = require('mysql2/promise');

(async () => {
  const db = await mysql.createConnection({
    host: '<XXXXXX>.stackhero-network.com',
    port: '<PORT>',
    user: 'root',
    password: '<ROOT_PASSWORD>'
  });

  // Crea il database se necessario
  await db.query('CREATE DATABASE IF NOT EXISTS stackherotest');

  // Crea la tabella se necessario
  await db.query('CREATE TABLE IF NOT EXISTS `stackherotest`.`users` '
    + '('
    + '`userId` INT UNSIGNED NOT NULL,'
    + '`name` VARCHAR(128) NOT NULL,'
    + '`address` TEXT NOT NULL,'
    + '`email` VARCHAR(265) NOT NULL'
    + ') '
    + 'ENGINE = InnoDB;');

  // Inserisce un utente di esempio
  await db.query(
    'INSERT INTO `stackherotest`.`users` (`userId`, `name`, `address`, `email`) VALUES ?',
    [
      [
        Math.round(Math.random() * 100000),
        'User name',
        'User address',
        '[email protected]'
      ]
    ]
  );

  // Conta gli utenti
  const [ usersCount ] = await db.query('SELECT COUNT(*) AS `cpt` FROM `stackherotest`.`users`');
  console.log(`Attualmente ci sono ${usersCount[0].cpt} record nella tabella "users"`);

  // Chiude la connessione
  await db.end();

})().catch(error => {
  console.error('');
  console.error('Si è verificato un errore!');
  console.error(error);
  process.exit(1);
});

Per connettersi da Node.js, NestJS o TypeORM, può aggiungere l'opzione ssl come mostrato di seguito:

TypeOrmModule.forRoot({
  type: 'mysql',
  host: '<XXXXXX>.stackhero-network.com',
  port: <PORT>,
  username: 'root',
  password: '<ROOT_PASSWORD>',
  database: 'root',
  entities: [],
  synchronize: true,
  ssl: {}
});

Se utilizza Prisma, aggiungere l'opzione sslaccept=strict garantisce una connessione cifrata. Ecco un esempio di configurazione:

datasource db {
  provider = "mysql"
  url = "mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?sslaccept=strict"
}

Se non ha ancora installato il modulo mysqlclient, può farlo con:

pip install mysqlclient

Se durante l'installazione compare l'errore Exception: Can not find valid pkg-config name, potrebbe essere necessario aggiungere il pacchetto libmysqlclient. Su Ubuntu/Debian, può eseguire: apt-get update && apt-get install --no-install-recommends -y libmysqlclient-dev

Per un primo test della connessione, può inserire la password direttamente nel file settings.py. Per una maggiore sicurezza a lungo termine, è preferibile utilizzare le variabili d'ambiente (vedi sotto).

Modifichi il suo settings.py come segue:

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'HOST': '<XXXXXX>.stackhero-network.com',
    'PORT': '<PORT>',
    'OPTIONS': {
      'ssl_mode': 'REQUIRED',
    },
    'NAME': 'root',
    'USER': 'root',
    'PASSWORD': '<ROOT_PASSWORD>'
  }
}

Attenzione: questo esempio è solo per test e non è raccomandato in ambienti di produzione!

Dopo aver verificato che la connessione funziona, può passare a un approccio più sicuro utilizzando django-environ per gestire le variabili d'ambiente.

Per prima cosa, installi il pacchetto:

pip install django-environ

Poi aggiorni il suo settings.py:

import environ
env = environ.Env()
environ.Env.read_env()

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'HOST': env('STACKHERO_MYSQL_HOST'),
    'PORT': env('STACKHERO_MYSQL_PORT'),
    'OPTIONS': {
      'ssl_mode': 'REQUIRED',
    },
    'NAME': 'root',
    'USER': 'root',
    'PASSWORD': env('STACKHERO_MYSQL_ROOT_PASSWORD')
  }
}

Crei o modifichi il file .env nella stessa directory di settings.py e aggiunga:

STACKHERO_MYSQL_HOST=<XXXXXX>.stackhero-network.com
STACKHERO_MYSQL_PORT=<PORT>
STACKHERO_MYSQL_ROOT_PASSWORD=<ROOT_PASSWORD>

Infine, per proteggere le sue credenziali, aggiunga .env al file .gitignore:

echo ".env" >> .gitignore

Per collegare la sua applicazione Spring, può impostare la variabile d'ambiente SPRING_DATASOURCE_URL con l'URL del database, assicurandosi di anteporre jdbc::

SPRING_DATASOURCE_URL=jdbc:mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?useSSL=true&requireSSL=true

Ecco un esempio di configurazione della sua applicazione Grails per connettersi a MySQL:

dataSource {
  pooled = true
  driverClassName = "com.mysql.cj.jdbc.Driver"
  dialect = org.hibernate.dialect.MySQL8Dialect
  // Proprietà specifiche SSL
  properties {
    useSSL = true
    requireSSL = true
    verifyServerCertificate = true
    sslMode = "REQUIRED"
  }
}

environments {
  production {
    dataSource {
      dbCreate = "none"
      url = "jdbc:mysql://" + System.env.STACKHERO_MYSQL_HOST + ":" + System.env.STACKHERO_MYSQL_PORT + "/root?useSSL=true&requireSSL=true&verifyServerCertificate=true&sslMode=required" // Può sostituire "/root" con il database desiderato.
      username = "root" // È consigliabile creare un utente dedicato per la sua applicazione.
      password = System.env.STACKHERO_MYSQL_ROOT_PASSWORD
      properties {
        maxActive = 50
        minEvictableIdleTimeMillis = 1800000
        timeBetweenEvictionRunsMillis = 1800000
        numTestsPerEvictionRun = 3
        testOnBorrow = true
        testWhileIdle = true
        testOnReturn = false
        validationQuery = "SELECT 1"
      }
    }
  }
}

Per una maggiore sicurezza, è buona prassi creare un utente dedicato per la sua applicazione invece di utilizzare l'utente "root". Può farlo facilmente tramite phpMyAdmin:

  1. In phpMyAdmin, selezioni User accounts dal menu principale.

  2. Clicchi su Add user account.

  3. Compili il modulo di creazione utente:

    • Inserisca un nome account (di solito il nome della sua applicazione)
    • Clicchi su Generate password per ottenere una password sicura e la copi
    • Selezioni Create database with same name and grant all privileges

Dopo aver inviato il modulo, avrà un nuovo utente e un database dedicato che porta lo stesso nome dell'utente.