MySQL: Prime configurazioni

Come iniziare con MySQL

👋 Benvenuti nella documentazione di Stackhero!

Stackhero offre una soluzione MySQL cloud pronta all'uso che fornisce una serie di vantaggi, tra cui:

  • Connessioni e trasferimenti illimitati.
  • Interfaccia web phpMyAdmin inclusa.
  • Aggiornamenti facili con un solo clic.
  • Prestazioni ottimali e sicurezza robusta grazie a una VM privata e dedicata.

Risparmia tempo e semplifica la tua vita: ci vogliono solo 5 minuti per provare la soluzione di MySQL cloud hosting di 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.