Tutorial

Comment installer Linux, Nginx, MySQL, PHP (pile LEMP) sur Ubuntu 20.04

NginxUbuntuPHPLEMPUbuntu 20.04

Introduction

La pile logicielle LEMP est un groupe de logiciels qui peuvent être utilisés pour servir des pages web dynamiques et des applications web écrites en PHP. Il s'agit d'un acronyme qui décrit un système d'exploitation Linux, avec un serveur Web Nginx (prononcé « Engine-X »). Les données backend sont stockées dans la base de données MySQL et le traitement dynamique est géré par PHP.

Ce guide explique comment installer une pile LEMP sur un serveur Ubuntu 20.04. Le système d'exploitation Ubuntu prend en charge la première exigence. Nous allons vous décrire comment faire fonctionner les autres composants.

Conditions préalables

Pour suivre ce tutoriel, vous devez avoir accès à un serveur Ubuntu 20.04 en tant qu'utilisateur non-root ​​​​sud​o​​​ normal, et le pare-feu de votre serveur doit être activé. Pour configurer cela, vous pouvez notre guide de configuration initiale du serveur pour Ubuntu 20.04.

Étape 1 – Installation du serveur web Nginx

Afin d'afficher les pages web aux visiteurs de notre site, nous allons utiliser Nginx, un serveur web très performant. Nous allons utiliser le gestionnaire de packages apt pour obtenir ce logiciel.

Etant donné que c'est la première fois que nous allons utiliser apt pour cette session, commencez par mettre à jour l'index des packages de votre serveur. Ensuite, vous pouvez utiliser apt install pour installer Nginx :

  • sudo apt update
  • sudo apt install nginx

Lorsque vous y êtes invité, entrez y pour confirmer que vous voulez installer nginx. Une fois l'installation terminée, le serveur Web Nginx sera actif et s'exécutera sur votre serveur Ubuntu 20.04.

Si le pare-feu ufw est activé, comme le recommande notre guide de configuration initiale du serveur, vous devez autoriser les connexions à Nginx. Lors de l'installation, Nginx enregistre quelques profils d'application UFW différents. Pour vérifier quels profils UFW sont disponibles, exécutez :

  • sudo ufw app list
Output
Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH

Nous vous recommandons d'activer le profil le plus restrictif qui autorisera tout de même le trafic dont vous avez besoin. Puisque vous n'avez pas configuré SSL pour votre serveur dans ce guide, vous aurez seulement besoin d'autoriser le trafic HTTP régulier sur le port 80.

Procédez à son activation en tapant :

  • sudo ufw allow 'Nginx HTTP'

Vous pouvez vérifier le changement en exécutant :

  • sudo ufw status

Le résultat de cette commande vous montrera que le trafic HTTP est désormais autorisé :

Output
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx HTTP ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx HTTP (v6) ALLOW Anywhere (v6)

Une fois la nouvelle règle de pare-feu ajoutée, vous pouvez tester si le serveur est opérationnel en accédant au nom de domaine ou à l'adresse IP publique de votre serveur dans votre navigateur Web.

Si vous n'avez pas de nom de domaine pointé vers votre serveur et que vous ne connaissez pas l'adresse IP publique de votre serveur, vous pouvez la trouver en exécutant la commande suivante :

  • ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

Cela imprimera quelques adresses IP. Vous pouvez essayer chacune d'entre elles à tour de rôle dans votre navigateur web.

Vous pouvez également vérifier quelle est l'adresse IP accessible, telle qu'elle est vue depuis d'autres endroits sur Internet :

  • curl -4 icanhazip.com

Saisissez l'adresse que vous recevez dans votre navigateur web : elle vous conduira à la page d'accueil par défaut de Nginx :

http://server_domain_or_IP

Page par défaut de Nginx

Si vous voyez cette page, cela signifie que vous avez correctement installé Nginx et activé le trafic HTTP pour votre serveur web.

Étape 2 — Installer MySQL

Maintenant que vous avez un serveur web opérationnel, vous devez installer le système de base de données pour pouvoir stocker et gérer les données de votre site. MySQL est un système de gestion de base de données populaire utilisé dans les environnements PHP.

Là encore, utilisez apt pour acquérir et installer ce logiciel :

  • sudo apt install mysql-server

Lorsque vous y êtes invité, confirmez l'installation en tapant Y, puis ENTRÉE.

Une fois l'installation terminée, il est recommandé d'exécuter un script de sécurité qui vient préinstallé avec MySQL. Ce script supprimera certains paramètres par défaut peu sûrs et verrouillera l'accès à votre système de base de données. Lancez le script interactif en exécutant :

  • sudo mysql_secure_installation

Il vous sera demandé si vous souhaitez configurer le VALIDATE PASSWORD PLUGIN.

Note : L'activation de cette fonction est en quelque sorte une question de jugement. Si elle est activée, les mots de passe qui ne correspondent pas aux critères spécifiés seront rejetés par MySQL avec une erreur. Laisser la validation désactivée est sans risque, mais vous devez toujours utiliser des mots de passe forts et uniques pour les identifiants de la base de données.

Répondez Y pour oui, ou tout autre chose pour continuer sans activer.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No:

Si vous répondez « oui », il vous sera demandé de choisir un niveau de validation du mot de passe. Gardez à l'esprit que si vous entrez 2 pour le niveau le plus fort, vous recevrez des erreurs lorsque vous tenterez de définir un mot de passe qui ne contient pas de chiffres, de lettres majuscules et minuscules et de caractères spéciaux, ou qui est basé sur des mots communs du dictionnaire.

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary              file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1

Que vous ayez ou non choisi de configurer le VALIDATE PASSWORD PLUGIN, votre serveur vous demandera ensuite de sélectionner et de confirmer un mot de passe pour l'utilisateur root de MySQL. Il ne faut pas confondre ce dernier avec le root du système. L'utilisateur root de la base de données est un utilisateur administratif disposant de tous les privilèges sur le système de base de données. Même si la méthode d'authentification par défaut pour l'utilisateur root de MySQL dispense de l'utilisation d'un mot de passe, même si celui-ci est défini, vous devez définir ici un mot de passe fort pour plus de sécurité. Nous en parlerons dans un instant.

Si vous avez activé la validation du mot de passe, la force du mot de passe root que vous venez d'entrer vous sera indiquée et votre serveur vous demandera si vous voulez continuer avec ce mot de passe. Si vous êtes satisfait de votre mot de passe actuel, saisissez Y pour « oui » à l'invite :

Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y

Pour le reste des questions, appuyez sur Y et appuyez sur la touche ENTRÉE à chaque invite. Cela supprimera les utilisateurs anonymes et la base de données de test, désactivera les connexions root à distance, et chargera ces nouvelles règles afin que MySQL respecte immédiatement les modifications que vous avez apportées.

Lorsque vous avez terminé, vérifiez si vous êtes capable de vous connecter à la console MySQL en tapant :

  • sudo mysql

Cela permettra de se connecter au serveur MySQL en tant que root de l'utilisateur de la base de données administrative, ce qui est déduit par l'utilisation de sudo lors de l'exécution de cette commande. Vous devriez voir une sortie comme celle-ci :

Output
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 22 Server version: 8.0.19-0ubuntu5 (Ubuntu) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>

Pour quitter la console MySQL, tapez :

  • exit

Notez que vous n'avez pas eu besoin de fournir un mot de passe pour vous connecter en tant qu'utilisateur root, même si vous en avez défini un lors de l'exécution du script mysql_secure_installation. En effet, la méthode d'authentification par défaut pour l'utilisateur administratif de MySQL est unix_socket au lieu du password. Même si cela peut sembler être un problème de sécurité au premier abord, cela rend le serveur de base de données plus sûr car les seuls utilisateurs autorisés à se connecter en tant qu'utilisateur MySQL root sont les utilisateurs du système ayant des privilèges sudo qui se connectent depuis la console ou par le biais d'une application fonctionnant avec les mêmes privilèges. Concrètement, cela signifie que vous ne pourrez pas utiliser l'utilisateur root de la base de données administrative pour vous connecter à partir de votre application PHP. La définition d'un mot de passe pour le compte root MySQL fonctionne comme une sauvegarde, dans le cas où la méthode d'authentification par défaut est changée de unix_socket au password.

Pour une sécurité accrue, il est préférable de créer des comptes d'utilisateurs dédiés avec des privilèges moins étendus pour chaque base de données, surtout si vous prévoyez d'héberger plusieurs bases de données sur votre serveur.

Note : Au moment de la rédaction de ce document, la bibliothèque MySQL PHP native mysqlnd ne prend pas en charge caching_sha2_authentification,la méthode d'authentification par défaut pour MySQL 8. Pour cette raison, lorsque vous créez des utilisateurs de base de données pour des applications PHP sur MySQL 8, vous devez vous assurer qu'ils sont configurés pour utiliser le mot de passe mysql_native_password à la place. Nous démontrerons comment le faire dans l'Étape 6.

Votre serveur MySQL est maintenant installé et sécurisé. Ensuite, nous allons installer PHP, le dernier composant de la pile LEMP.

Étape 3 – Installation de PHP

Vous avez installé Nginx pour servir votre contenu et MySQL pour stocker et gérer vos données. Vous pouvez maintenant installer PHP pour traiter le code et générer du contenu dynamique pour le serveur web.

Alors qu'Apache intègre l'interpréteur PHP dans chaque requête, Nginx nécessite un programme externe pour gérer le traitement PHP et agir comme un pont entre l'interpréteur PHP lui-même et le serveur web. Cela permet d'obtenir de meilleures performances globales dans la plupart des sites web basés sur PHP, mais cela nécessite une configuration supplémentaire. Vous devrez installer php-fpm (PHP fastCGI process manager) et indiquer à Nginx qu'il doit transmettre les requêtes PHP à ce logiciel pour qu'elles soient traitées. En outre, vous aurez besoin de php-mysql​​​​, un module PHP qui permet à PHP de communiquer avec des bases de données basées sur MySQL. Les packages PHP de base seront automatiquement installés en tant que dépendances.

Pour installer les packages php-fpm et php-mysql, exécutez :

  • sudo apt install php-fpm php-mysql

Lorsque vous y êtes invité, tapez Y et ENTER pour confirmer l'installation.

Maintenant, vos composants PHP sont installés. Ensuite, vous allez configurer Nginx afin de pouvoir les utiliser.

Étape 4 — Configuration de Nginx pour utiliser le processeur PHP

Avec le serveur Web Nginx, vous pouvez créer des blocs de serveur (similaires aux hôtes virtuels dans Apache) pour encapsuler les détails de configuration et héberger plusieurs domaines sur un seul serveur. Dans ce guide, nous utiliserons l'exemple de nom de domaine your_domain. Pour en savoir plus sur la mise en place d'un nom de domaine avec DigitalOcean, voir notre introduction à DigitalOcean DNS. 

Sur Ubuntu 20.04, Nginx dispose d'un bloc serveur activé par défaut qui est configuré pour servir des documents à partir d'un répertoire à /var/www/html. Même si cela fonctionne bien pour un seul site, cela peut devenir difficile à gérer si vous hébergez plusieurs sites. Au lieu de modifier /var/www/html, nous allons créer une structure de répertoire au sein de /var/www pour le site Web your_domain, en laissant /var/www/html en place comme répertoire par défaut à servir si une demande du client ne correspond à aucun autre site.

Créez le répertoire racine Web pour your_domain comme suit :

  • sudo mkdir /var/www/your_domain

Ensuite, attribuez la propriété du répertoire avec la variable d'environnement $USER qui fera référence à votre utilisateur actuel du système :

  • sudo chown -R $USER:$USER /var/www/your_domain

Ouvrez ensuite un nouveau fichier de configuration dans le répertoire sites-available de Nginx en utilisant votre éditeur de ligne de commande préféré. Ici, nous utiliserons nano :

  • sudo nano /etc/nginx/sites-available/your_domain

Cela créera un nouveau fichier vierge. Collez dans la configuration suivante :

/etc/nginx/sites-available/your_domain
server {
    listen 80;
    server_name your_domain www.your_domain;
    root /var/www/your_domain;

    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
     }

    location ~ /\.ht {
        deny all;
    }

}


Voici ce que font chacune de ces directives et blocs de localisation :

  • listen — Définit le port que Nginx écoutera. Dans ce cas, l'écoute se fera sur le port 80, le port par défaut de HTTP.
  • root — Définit la racine du document dans laquelle les fichiers servis par ce site Web sont stockés.
  • index — Définit dans quel ordre Nginx priorisera les fichiers d'index pour ce site Web. Il est courant de répertorier les fichiers index.html avec une priorité plus élevée que les fichiers index.php, pour permettre de configurer rapidement une page de destination de maintenance dans les applications PHP. Vous pouvez ajuster ces paramètres pour mieux répondre aux besoins de votre application.
  • server_name — Définit les noms de domaine et / ou adresses IP auxquels ce bloc serveur doit répondre. Pointez cette directive sur le nom de domaine ou l'adresse IP publique de votre serveur.
  • location / —Le premier bloc de localisation comprend une directive try_files, qui vérifie l'existence de fichiers ou de répertoires correspondant à une demande d'URI. Si Nginx n'arrive pas à trouver la ressource appropriée, il renverra une erreur 404.
  • location ~ \.php$ — Ce bloc de localisation gère le traitement PHP réel en pointant Nginx vers le fichier de configuration fastcgi-php.conf et vers le fichier php7.4-fpm.sock, qui indique quel socket est associé à php-fpm.
  • location ~ /\.ht — Le dernier bloc de localisation s'occupe des fichiers .htaccess que Nginx ne traite pas. En ajoutant la directive deny all, les fichiers .htaccess qui se retrouvent dans la racine du document ne seront pas présentés aux visiteurs.

Une fois que vous avez terminé vos modifications, enregistrez et fermez le fichier. Si vous utilisez nano, vous pouvez le faire en appuyant sur CTRL + X, puis y et ENTER pour confirmer.

Activez votre configuration en établissant un lien vers le fichier de configuration à partir du répertoire sites-enabled de Nginx :

  • sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/

Cela indiquera à Nginx d'utiliser la configuration lors du prochain rechargement. Vous pouvez vérifier si votre configuration contient des fautes de syntaxe en tapant :

  • sudo nginx -t

Si des erreurs sont signalées, revenez à votre fichier de configuration pour corriger son contenu avant de continuer.

Une fois que vous êtes prêt, rechargez Nginx pour appliquer les modifications :

  • sudo systemctl reload nginx

Votre nouveau site web est maintenant actif, mais le root web /var/www/your_domain est toujours vide. Créez un fichier index.html à cet endroit afin que nous puissions tester si le bloc de serveur fonctionne comme prévu :

  • nano /var/www/your_domain/index.html

Incluez le contenu suivant dans ce dossier :

/var/www/your_domain/index.html
<html>
  <head>
    <title>your_domain website</title>
  </head>
  <body>
    <h1>Hello World!</h1>

    <p>This is the landing page of <strong>your_domain</strong>.</p>
  </body>
</html>

Maintenant, allez dans votre navigateur et accédez au nom de domaine ou à l'adresse IP de votre serveur, comme indiqué dans la directive server_name de votre fichier de configuration de bloc de serveur :

http://server_domain_or_IP

Vous verrez une page comme celle-ci :

Nginx server block

Si vous voyez cette page, cela signifie que votre bloc de serveur Nginx fonctionne comme prévu.

Vous pouvez laisser ce fichier en place en tant que page d'accueil temporaire pour votre demande jusqu'à ce que vous créiez un fichier index.php pour le remplacer. Une fois que vous aurez fait cela, n'oubliez pas de supprimer ou de renommer le fichier index.html du root de votre document car il aurait la priorité sur un fichier index.php par défaut.

Votre pile LEMP est maintenant entièrement configurée. A l'étape suivante, nous allons créer un script PHP pour tester que Nginx est vraiment capable de gérer les fichiers .php au sein de votre site Web nouvellement configuré.

Étape 5 – Tester PHP avec Nginx

Maintenant, votre pile LEMP devrait être entièrement installée. Vous pouvez la tester pour vérifier que Nginx peut correctement transmettre les fichiers .php à votre processeur PHP.

Vous pouvez le faire en créant un fichier PHP de test dans la racine de votre document. Ouvrez un nouveau fichier appelé info.php dans la racine de votre document dans votre éditeur de texte :

  • nano /var/www/your_domain/info.php

Saisissez ou collez les lignes suivantes dans le nouveau fichier. Il s'agit d'un code PHP valide qui renverra des informations sur votre serveur :

/var/www/your_domain/info.php
<?php
phpinfo();

Une fois que vous avez terminé, enregistrez et fermez le fichier en tapant CTRL+X, puis y et ENTER pour confirmer.

Vous pouvez maintenant accéder à cette page dans votre navigateur Web en consultant le nom de domaine ou l'adresse IP publique que vous avez défini dans votre fichier de configuration Nginx, suivi de /info.php :

http://server_domain_or_IP/info.php

Vous verrez apparaître une page Web contenant des informations détaillées sur votre serveur :

PHPInfo Ubuntu 20.04

Après avoir vérifié les informations pertinentes sur votre serveur PHP par le biais de cette page, il est préférable de supprimer le fichier que vous avez créé car il contient des informations sensibles sur votre environnement PHP et votre serveur Ubuntu. Vous pouvez utiliser rm pour supprimer ce fichier :

  • sudo rm /var/www/your_domain/info.php

Vous pourrez toujours générer de nouveau ce fichier si vous en avez besoin plus tard.

Étape 6 — Tester la connexion à la base de données à partir de PHP (facultatif)

Si vous souhaitez tester si PHP est capable de se connecter à MySQL et d'exécuter des requêtes de base de données, vous pouvez créer une table de test avec des données factices et interroger son contenu à partir d'un script PHP. Avant cela, nous devons créer une base de données test et un nouvel utilisateur MySQL correctement configuré pour y accéder.

Au moment de la rédaction du présent document, la bibliothèque MySQL PHP native mysqlnd ne prend pas en charge caching_sha2_authentification, la méthode d'authentification par défaut pour MySQL 8. Nous devrons créer un nouvel utilisateur avec le mot de passe mysql_native_password afin de pouvoir se connecter à la base de données MySQL à partir de PHP. 

Nous allons créer une base de données appelée exemple_database et un utilisateur nommé example_user, mais vous pouvez remplacer ces noms par des valeurs différentes. 

Tout d'abord, connectez-vous à la console MySQL en utilisant le compte root :

  • sudo mysql

Pour créer une nouvelle base de données, exécutez la commande suivante depuis votre console MySQL :

  • CREATE DATABASE example_database;

Vous pouvez maintenant créer un utilisateur et lui accorder tous les privilèges sur la base de données personnalisée que vous venez de créer.

La commande suivante crée un nouvel utilisateur nommé example_user, en utilisant mysql_native_password comme méthode d'authentification par défaut. Nous définissons le mot de passe de cet utilisateur comme password, mais vous devez remplacer cette valeur par un mot de passe sécurisé de votre choix. 

  • CREATE USER 'example_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';

Nous devons maintenant donner à cet utilisateur une autorisation sur la base de données example_database : 

  • GRANT ALL ON example_database.* TO 'example_user'@'%';

Cela donnera à l'utilisateur example_user tous les privilèges sur la base de données example_database, tout en empêchant cet utilisateur de créer ou de modifier d'autres bases de données sur votre serveur.

Maintenant, quittez le shell MySQL avec :

  • exit

Vous pouvez tester si le nouvel utilisateur a les bonnes autorisations en vous connectant à nouveau à la console MySQL, cette fois-ci en utilisant les identifiants personnalisés de l'utilisateur :

  • mysql -u example_user -p

Remarquez le drapeau -p dans cette commande qui vous demandera le mot de passe utilisé lors de la création de l'utilisateur example_user. Après vous être connecté à la console MySQL, confirmez que vous avez accès à la base de données example_database :

  • SHOW DATABASES;

Cela donnera la sortie suivante :

Output
+--------------------+ | Database | +--------------------+ | example_database | | information_schema | +--------------------+ 2 rows in set (0.000 sec)

Ensuite, nous allons créer une table de test appelée todo_list. Depuis la console MySQL, lancez la déclaration suivante :

  • CREATE TABLE example_database.todo_list (
  • item_id INT AUTO_INCREMENT,
  • content VARCHAR(255),
  • PRIMARY KEY(item_id)
  • );

Insérez quelques lignes de contenu dans la table de test. Vous pouvez répéter la commande suivante plusieurs fois, en utilisant des valeurs différentes :

  • INSERT INTO example_database.todo_list (content) VALUES ("My first important item");

Pour confirmer que les données ont bien été enregistrées dans votre tableau, exécutez :

  • SELECT * FROM example_database.todo_list;

Vous verrez la sortie suivante :

Output
+---------+--------------------------+ | item_id | content | +---------+--------------------------+ | 1 | My first important item | | 2 | My second important item | | 3 | My third important item | | 4 | and this one more thing | +---------+--------------------------+ 4 rows in set (0.000 sec)

Après avoir confirmé que vous avez des données valides dans votre table de test, vous pouvez quitter la console MySQL :

  • exit

Vous pouvez maintenant créer le script PHP qui se connectera à MySQL et interrogera votre contenu. Créez un nouveau fichier PHP dans votre répertoire root personnalisé en utilisant votre éditeur préféré. Nous utiliserons nano pour cela :

  • nano /var/www/your_domain/todo_list.php

Le script PHP suivant se connecte à la base de données MySQL et interroge le contenu de la table todo_list affichant les résultats dans une liste. S'il y a un problème avec la connexion à la base de données, il y aura une exception. Copiez ce contenu dans votre script todo_list.php : 

/var/www/your_domain/todo_list.php
<?php
$user = "example_user";
$password = "password";
$database = "example_database";
$table = "todo_list";

try {
  $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
  echo "<h2>TODO</h2><ol>";
  foreach($db->query("SELECT content FROM $table") as $row) {
    echo "<li>" . $row['content'] . "</li>";
  }
  echo "</ol>";
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}

Enregistrez et fermez le fichier lorsque vous avez fini de le modifier.

Vous pouvez maintenant accéder à cette page dans votre navigateur web en consultant le nom de domaine ou l'adresse IP publique configurée de votre site web, suivi de /todo_list.php :

http://server_domain_or_IP/todo_list.php

Vous devriez voir une page comme celle-ci, montrant le contenu que vous avez inséré dans votre tableau de test :

Exemple todo list PHP

Cela signifie que votre environnement PHP est prêt à se connecter et à interagir avec votre serveur MySQL.

Conclusion

Dans ce guide, nous avons établi une base souple pour offrir des sites web et des applications PHP à vos visiteurs en utilisant Nginx comme serveur web et MySQL comme système de base de données.

À partir de là, vous pouvez effectuer certain nombre d'étapes supplémentaires. Par exemple, vous devez vous assurer que les connexions à votre serveur sont sécurisées. Pour cela, vous pourriez sécuriser votre installation Nginx avec Let’s Encrypt. En suivant ce guide, vous allez acquérir un certificat TLS/SSL gratuit pour votre serveur, ce qui lui permettra de servir du contenu sur HTTPS.

Creative Commons License