Les outils du développeur web
Préparez et sécurisez l'environnement de travail d'un développeur web basé sur Apache, MySQL, PHP et phpMyAdmin. Soyez prêt à chiffrer les connexions avec SSL. Configurez un serveur de courrier local avec Postfix et Dovecot. Gérez la mise en ligne d'un site web avec SSH et Rsync. Surveillez l'activité du serveur avec Nagios. Centralisez le code source avec Git. Programmez des sauvegardes incrémentales. Limitez l'utilisation de l'espace disque avec les quotas. Montez un serveur de noms local avec Bind - Synchronisez le système avec un serveur de temps.
- LAMP
- Apache
- PHP
- MySQL
- phpMyAdmin
- Chiffrement
- Courrier local
- Accès à distance
- Gestion des sources
- Synchronisation
- Supervision
- Sauvergardes
- Quotas
- DNS
- NTP
LAMP
Installez Apache, MySQL et PHP :
$ sudo apt install apache2
$ sudo apt install mysql-client mysql-server
$ sudo apt install php5 php5-mcrypt php5-gd libapache2-mod-php5 php5-mysql
Durant l'installation de MySQL, choisissez un mot de passe pour l'administrateur de la BD. Notez-le bien.
Apache
Assurez-vous que le serveur Apache est bien démarré :
$ sudo /etc/init.d/apache2 start
Vérifiez qu'Apache fonctionne en tapant localhost dans la barre d'adresse de votre navigateur. Si la connexion avec le serveur est rejetée, la cause est dans le journal d'erreur /var/log/apache2/error.log.
Créez le fichier /etc/apache2/httpd.conf avec le contenu suivant :
- #
- # ServerAdmin: Your address, where problems with the server should be
- # e-mailed. This address appears on some server-generated pages, such
- # as error documents. e.g. admin@your-domain.com
- #
- ServerAdmin webmaster@localhost
- #
- # ServerName gives the name and port that the server uses to identify itself.
- # This can often be determined automatically, but we recommend you specify
- # it explicitly to prevent problems during startup.
- #
- # If your host doesn't have a registered DNS name, enter its IP address here.
- #
- #ServerName www.example.com:80
- ServerName localhost
Si nécessaire, ajoutez les lignes suivantes dans le fichier /etc/apache2/apache2.conf avant la ligne Include ports.conf
:
# Include all the user configurations:
Include httpd.conf
Éditez le fichier de configuration /etc/apache2/sites-available/default.
Mettez la directive AllowOverride
à all
dans la configuration du répertoire /var/www :
- <Directory /var/www/>
- Options Indexes FollowSymLinks MultiViews
- AllowOverride All
- Order allow,deny
- allow from all
- </Directory>
IMPORTANT : Depuis Apache 2.4, vous devez ajouter la directive Require all granted
.
Notifiez le changement au serveur Apache :
$ sudo /etc/init.d/apache2 reload
Ajoutez votre compte au groupe www-data
:
$ sudo adduser frasq www-data
NOTE : remplacez frasq par votre nom de connexion.
Créez le dossier /var/www/frasq.org :
$ sudo mkdir /var/www/frasq.org
$ sudo chgrp www-data /var/www/frasq.org
$ sudo chmod 2775 /var/www/frasq.org
NOTE : remplacez frasq.org par le nom de domaine de votre site.
Créez le fichier frasq dans le répertoire /etc/apache2/sites-available avec le contenu suivant :
- <VirtualHost *:80>
- DocumentRoot /var/www/frasq.org
- ServerName local.frasq.org
- </VirtualHost>
Créez un lien vers le fichier /etc/apache2/sites-available/frasq dans le répertoire /etc/apache2/sites-enabled :
$ cd /etc/apache2/sites-enabled
$ sudo ln -s ../sites-available/frasq frasq
Redémarrez Apache :
$ sudo /etc/init.d/apache2 restart
Associez le nom local.frasq.org à l'adresse IP locale en ajoutant la ligne suivante dans le fichier /etc/hosts :
127.0.0.1 local.frasq.org
Vérifiez que le DNS fonctionne :
$ ping local.frasq.org
PING local.frasq.org (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.030 ms
^C
Entrez local.frasq.org dans la barre d'adresse de votre navigateur pour vérifier que le site virtuel est accessible.
PHP
Éditez le fichier de configuration de PHP pour Apache /etc/php5/apache2/php.ini.
Cherchez le paramètre session.gc_maxlifetime
. Donnez-lui la valeur suivante :
session.gc_maxlifetime = 3600
Créez le fichier /var/www/frasq.org/phpinfo.php avec le contenu suivant :
Entrez local.frasq.org/phpinfo.php dans la barre d'adresse de votre navigateur pour vérifier l'installation de PHP.
MySQL
Assurez-vous que le serveur MySQL est bien démarré :
$ sudo /etc/init.d/mysql start
IMPORTANT : Si l'installation de MySQL ne vous a pas demandé de définir un mot de passe pour l'administrateur, faites-le immédiatement :
$ sudo -s
# mysql -u root
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'root_password';
mysql> FLUSH PRIVILEGES;
Remplacez root_password
par un mot de passe de votre choix. Ne l'oubliez pas.
Éditez le fichier de configuration /etc/mysql/mysql.conf.d/mysqld.cnf. Vérifiez le paramètre bind-address
:
bind-address = 127.0.0.1
Votre BD est protégée d'une connexion à distance.
Vérifiez que l'administrateur de la BD est bien protégé et accessible :
$ mysql -u root -p
Enter password:
Entrez le mot de passe de root
.
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql>
Essayez d'exécuter une commande :
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
mysql>
Entrez quit
pour quitter mysql
.
Si vous avez oublié le mot de passe de l'administrateur de la BD, commencez par arrêter le serveur :
$ sudo /etc/init.d/mysql stop
Redémarrez le serveur dans le mode qui donne un accès libre sans mot de passe à tous les utilisateurs tout en leur attribuant tous les privilèges :
$ sudo mysqld_safe --skip-grant-tables &
Lancez mysql
en tant que root
:
$ mysql -u root --skip-password
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'root_password';
mysql> quit
Remplaçezroot_password
par un mot de passe de votre choix.
Arrêtez le serveur :
$ sudo pkill -9 mysqld_safe
[1]+ Processus arrêté sudo mysqld_safe --skip-grant-tables
Redémarrez le serveur en mode normal :
$ sudo /etc/init.d/mysql start
Vérifiez que la BD est bien protégée et accessible :
$ mysql -u root -p
Enter password:
phpMyAdmin
NOTE : Adminer est une alternative à phpMyAdmin.
$ sudo apt install adminer
Pour installer la dernière version :
$ sudo mkdir /usr/share/adminer
$ sudo wget "http://www.adminer.org/latest.php" -O /usr/share/adminer/latest.php
$ sudo ln -s /usr/share/adminer/latest.php /usr/share/adminer/adminer.php
$ echo "Alias /adminer /usr/share/adminer/adminer.php" | sudo tee /etc/apache2/conf-available/adminer.conf
$ sudo a2enconf adminer
$ sudo service apache2 reload
Entrez localhost/adminer dans la barre d'adresse de votre navigateur.
Pour installer phpMyAdmin :
$ sudo apt install phpmyadmin
Durant l'installation, sélectionnez Apache en appuyant sur la barre d'espace puis sur tabulation et Entrée, sélectionnez apache2
comme serveur, validez la configuration avec dbconfig-common
, entrez root
pour le nom de l'administrateur de la BD puis le mot de passe que vous avez spécifié pour l'utilisateur root
de MySQL.
L'installation a créé un lien vers le fichier /etc/phpmyadmin/apache.conf dans le dossier /etc/apache2/conf-enabled. NOTE : Pour les versions plus anciennes d'Apache, le lien est créé dans le dossier /etc/apache2/conf.d.
Activez le module php5-mcrypt :
$ sudo php5enmod mcrypt
Éditez le fichier de configuration des paramètres d'accès à la BD de PHP /etc/phpmyadmin/config-db.php. Notez le mot de passe de l'utilisateur de la BD :
$dbuser='phpmyadmin';
$dbpass='************';
Éditez le fichier de configuration /etc/phpmyadmin/config.inc.php.
Vérifiez que le type d'authentification est bien 'cookie'
:
$cfg['Servers'][$i]['auth_type'] = 'cookie';
IMPORTANT : Ce paramètre détermine le mode de connexion avec la BD employé par phpMyAdmin. La valeur 'cookie'
force l'affichage d'une page d'identification. Le mode 'config'
qui donne un accès direct à la BD est à proscrire.
Éditez le fichier de configuration de phpMyAdmin pour Apache /etc/phpmyadmin/apache.conf. Modifiez le chemin d'accès à phpMyAdmin :
#Alias /phpmyadmin /usr/share/phpmyadmin
Alias /mysql /usr/share/phpmyadmin
Bloquez l'accès au répertoire /usr/share/phpmyadmin/setup :
<Directory /usr/share/phpmyadmin/setup>
Order Deny,Allow
Deny from All
</Directory>
Notifiez le changement au serveur Apache :
$ sudo /etc/init.d/apache2 reload
Entrez localhost/mysql dans la barre d'adresse de votre navigateur.
Identifiez-vous en tant que root
. Entrez le mot de passe de l'administrateur de la BD.
Cliquez sur la BD mysql
puis sur la table user
.
Pour des raisons de sécurité, supprimez toutes les entrées sauf celle avec user
à root
et host
à localhost
.
Insérez une entrée pour phpMyAdmin avec user
à phpmyadmin
, host
à localhost
, password
à la valeur du mot de passe défini par le paramètre $dbpass
du fichier /etc/phpmyadmin/config-db.php.
Ne donnez aucun privilège à l'utilisateur phpmyadmin
.
Seulement root
a le droit d'exécuter toutes les opérations sur toutes les bases de données.
IMPORTANT : Pensez à sélectionner la fonction PASSWORD pour le champ password
sinon la valeur ne sera pas chiffrée et le mot de passe saisi par une page d'identification, qui sera chiffré, ne correspondra pas. Faites particulièrement attention si vous changez le mot de passe de root
.
Cliquez sur la table db
de la BD mysql
.
Insérez une entrée pour phpMyAdmin avec user
à phpmyadmin
, host
à localhost
et db
à phpmyadmin
et tous les privilèges.
Redémarrez MySQL :
$ sudo /etc/init.d/mysql restart
IMPORTANT : Ne donnez jamais de privilèges globaux à un utilisateur, sauf root
.
Accordez toujours des privilèges, et seulement ceux nécessaires, à un utilisateur en particulier sur une base de données spécifique.
Essayez d'éviter les connexions à distance.
Chiffrement
Installez OpenSSL :
$ sudo apt install openssl
Créez un dossier SSL dans votre répertoire personnel :
$ mkdir ~/SSL
Protégez-le :
$ chmod 700 ~/SSL
Copiez le fichier de configuration /etc/ssl/openssl.cnf dans votre dossier SSL :
$ cp /etc/ssl/openssl.cnf ~/SSL
Placez-vous dans votre dossier SSL :
$ cd ~/SSL
Créez les dossiers private, certs et newcerts et protégez-les :
$ mkdir private certs newcerts
$ chmod 700 private certs newcerts
Créez l'index :
$ touch index.txt
$ chmod 664 index.txt
Éditez le fichier openssl.cnf et changez les lignes suivantes :
dir = . # Where everything is kept
new_certs_dir = $dir/newcerts # default place for new certs.
default_days = 3650 # how long to certify for
stateOrProvinceName = optional
countryName_default = FR
stateOrProvinceName_default =
0.organizationName_default = frasq.org
organizationalUnitName_default = Software
#nsComment = "OpenSSL Generated Certificate"
nsComment = "Generated by frasq.org"
nsCertType = server
D'autres options par défault :
[ req ]
default_bits = 2048
default_md = sha256
NOTE : Adaptez ce fichier en remplaçant frasq.org
par le nom de domaine de votre site, en changeant la durée de vie par défaut d'un certificat, la désignation du pays d'émission des certificats, etc.
IMPORTANT : L'option nsCertType
de la section [usr_cert]
dépend de l'extension voulue.
Utilisez server
pour générer le certificat d'un serveur.
Utilisez client, email
pour générer le certificat d'un utilisateur contenant une adresse d'email.
Autorité de certification
Commencez par créer le certificat de votre autorité de certification :
$ openssl req -config ./openssl.cnf -newkey rsa:2048 -sha256 -keyout private/cakey.pem -out cacert-req.pem
Entrez les réponses suivantes aux questions :
organizationName = frasq.org
organizationalUnitName = http://www.frasq.org
commonName = Frasq Signing Authority
emailAddress = keymaster@frasq.org
Le paramètre -newkey rsa:2048
génère une clé RSA de 2048 bits.
Le paramètre -sha256
force l'utilisation d'une empreinte SHA2.
Le fichier cacert-req.pem contient une demande de certification.
Vérifiez le contenu du fichier :
$ openssl req -in cacert-req.pem -text -noout
...
Subject: C=FR, L=La Chapelle, O=frasq.org, OU=http://www.frasq.org, CN=Frasq Signing Authority/emailAddress=keymaster@frasq.org
...
Public-Key: (2048 bit)
...
Signature Algorithm: sha256WithRSAEncryption
...
Créez un certificat racine auto-signé :
$ openssl ca -config ./openssl.cnf -create_serial -selfsign -extensions v3_ca -keyfile private/cakey.pem -md sha256 -out cacert.pem -days 3650 -infiles cacert-req.pem
Le paramètre -md sha256
génère un certificat au format SHA2.
L'option -days 3650
crée un certificat valable 10 ans.
Le paramètre -create_serial
initialise le fichier serial.
Vérifiez le contenu du certificat :
$ openssl x509 -in cacert.pem -text -noout
...
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FR, L=La Chapelle, O=frasq.org, OU=http://www.frasq.org, CN=Frasq Signing Authority/emailAddress=keymaster@frasq.org
...
Subject: C=FR, L=La Chapelle, O=frasq.org, OU=http://www.frasq.org, CN=Frasq Signing Authority/emailAddress=keymaster@frasq.org
...
X509v3 Basic Constraints:
CA:TRUE
...
Notez que les champs Issuer
et Subject
sont identiques et que le champ X509v3 Basic Constraints
est à CA:TRUE
.
Certification d'un serveur
Créez la demande de certificat pour le site en ligne :
$ openssl req -config ./openssl.cnf -new -nodes -newkey rsa:2048 -sha256 -out frasq.org-req.pem -keyout private/frasq.org-key.pem
La combinaison d'options -new -nodes
génère une clé privée qui n'est pas protégée. Apache pourra ainsi la charger sans demander une phrase de passe.
Entrez les réponses suivantes aux questions :
organizationName = frasq.org
organizationalUnitName = Software
commonName = www.frasq.org
emailAddress = webmaster@frasq.org
Vérifiez que l'option nsCertType
de la section [usr_cert]
du fichier de configuration openssl.cnf est à la valeur server
:
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
...
# This is OK for an SSL server.
nsCertType = server
Affichez la demande de certification :
$ openssl req -in frasq.org-req.pem -text -noout
...
Subject: C=FR, L=La Chapelle, O=frasq.org, OU=Software, CN=www.frasq.org/emailAddress=webmaster@frasq.org
...
Le champ CN
doit contenir l'adresse du site. Signez la demande pour fabriquer le certificat :
$ openssl ca -config ./openssl.cnf -md sha256 -out frasq.org-cert.pem -infiles frasq.org-req.pem
Vérifiez le contenu du certificat :
$ openssl x509 -in frasq.org-cert.pem -text -noout
...
Issuer: C=FR, L=La Chapelle, O=frasq.org, OU=http://www.frasq.org, CN=Frasq Signing Authority/emailAddress=keymaster@frasq.org
...
Subject: C=FR, O=frasq.org, OU=Software, CN=www.frasq.org/emailAddress=webmaster@frasq.org
...
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
...
Créez un certificat pour localhost :
$ openssl req -config ./openssl.cnf -new -nodes -newkey rsa:2048 -sha256 -out localhost-req.pem -keyout private/localhost-key.pem
...
organizationName = frasq.org
organizationalUnitName = Software
commonName = localhost
emailAddress = webmaster@localnet.net
...
$ openssl ca -config ./openssl.cnf -md sha256 -out localhost-cert.pem -infiles localhost-req.pem
Pour créer un certificat valide pour plusieurs variantes d'un nom de domaine, e.g. sitename.net, www.sitename.net et local.sitename.net, ajoutez les lignes suivantes à la fin du fichier openssl.cnf :
[ san_ext ]
subjectAltName = @subject_alt_names
[ subject_alt_names ]
DNS.1 = ${ENV::CN}
DNS.2 = www.${ENV::CN}
DNS.3 = local.${ENV::CN}
Le paramètre ${ENV::CN}
permet de récupérer la valeur de la variable d'environnement CN
.
Créez la demande de certification normalement en configurant la variable d'environnement CN au nom de domaine du site :
$ CN=sitename.net openssl req -config ./openssl.cnf -new -nodes -newkey rsa:2048 -sha256 -out sitename-req.pem -keyout private/sitename-key.pem
...
organizationName = sitename.net
organizationalUnitName = Web
commonName = sitename.net
emailAddress = webmaster@sitename.net
...
Pour signer un certificat en activant cette extension, tapez la commande suivante :
$ CN=sitename.net openssl ca -config ./openssl.cnf -md sha256 -extensions san_ext -out sitename-cert.pem -infiles sitename-req.pem
Vérifiez le contenu du certificat :
$ openssl x509 -in sitename-cert.pem -text -noout
...
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:sitename.net, DNS:www.sitename.net, DNS:local.sitename.net
IMPORTANT :
Depuis la version 58, Chrome impose que les certificats SSL utilisent le SAN (Subject Alternative Name) et la prise en charge du nom commun (CN) a été supprimée.
Certification d'un client
Éditez le fichier openssl.cnf et mettez l'option nsCertType
de la section [usr_cert]
à la valeur client, email
:
[ usr_cert ]
...
# This is OK for an SSL server.
#nsCertType = server
...
# For normal client use this is typical
nsCertType = client, email
...
Créez une demande de certificat pour un client avec l'adresse d'email webmaster@frasq.org :
$ openssl req -config ./openssl.cnf -new -nodes -newkey rsa:2048 -sha256 -out webmaster-req.pem -keyout private/webmaster-key.pem
Entrez les réponses suivantes aux questions :
organizationName = frasq.org
organizationalUnitName = Software
commonName = webmaster
emailAddress = webmaster@frasq.org
Créez le certificat :
$ openssl ca -config ./openssl.cnf -md sha256 -out webmaster-cert.pem -infiles webmaster-req.pem
Créez un certificat au format PKCS12 :
$ openssl pkcs12 -export -out webmaster-cert.p12 -in webmaster-cert.pem -inkey private/webmaster-key.pem -name "webmaster" -caname "Frasq Signing Authority" -certfile cacert.pem
Ce format est accepté par Firefox et Thunderbird.
Apache
Créez des liens vers les fichiers /etc/apache2/mods-available/ssl.load et /etc/apache2/mods-available/ssl.conf dans le répertoire /etc/apache2/mods-enabled :
$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/ssl.load .
$ sudo ln -s ../mods-available/ssl.conf .
Installez le certificat de l'autorité de certification :
$ cd ~/SSL
$ sudo cp cacert.pem /etc/ssl/certs/frasq.crt
$ cd /etc/ssl/certs; sudo ln -s frasq.crt `openssl x509 -in frasq.crt -noout -subject_hash`.0
La dernière commande lie le fichier du certificat à un fichier dont le nom est le hachage du sujet du certificat avec l'extension .0.
Installez le certificat du serveur localhost :
$ cd ~/SSL
$ sudo cp cacert.pem /etc/ssl/certs/frasq.crt
$ sudo cp localhost-cert.pem /etc/ssl/certs/localhost.crt
Installez la clé du serveur :
$ cd ~/SSL
$ sudo cp private/localhost-key.pem /etc/ssl/private/localhost.key
$ sudo chmod 640 /etc/ssl/private/localhost.key
IMPORTANT : Assurez-vous que la clé n'est pas en lecture pour tout le monde sinon Apache refusera de la lire.
Éditer le fichier /etc/apache2/sites-available/default-ssl. Remplacez les lignes suivantes :
#SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
SSLCertificateFile /etc/ssl/certs/localhost.crt
SSLCertificateKeyFile /etc/ssl/private/localhost.key
Décommentez la ligne suivante :
SSLCACertificatePath /etc/ssl/certs/
Créez un lien vers le fichier /etc/apache2/sites-available/default-ssl dans le répertoire /etc/apache2/sites-enabled :
$ cd /etc/apache2/sites-enabled
$ sudo ln -s ../sites-available/default-ssl 001-default-ssl
Redémarrez Apache :
$ sudo /etc/init.d/apache2 restart
En cas de problème, cherchez la cause dans le journal d'erreur /var/log/apache2/error.log.
Firefox & Thunderbird
Installez le certificat de votre autorité de certification en choisissant Avancé puis Chiffrement dans les Préférences, puis Afficher les certificats, Autorités et Importer. Ouvrez le fichier cacert.pem dans votre dossier ~/SSL.
Cochez les cases de confirmation et validez.
NOTE : Cliquez sur Voir et vérifiez l'empreinte SHA1 du certificat que vous pouvez obtenir avec la commande suivante :
$ openssl x509 -in cacert.pem -fingerprint -noout
Entrez https://localhost dans la barre d'adresse pour vérifier que tout est bien en place.
Installez le certificat personnel du webmestre en choisissant Avancé puis Chiffrement dans les Préférences, puis Afficher les certificats, Vos certificats et Importer. Ouvrez le fichier webmaster-cert.p12 dans votre dossier ~/SSL.
Répétez les procédures d'installation du certificat de votre autorité de certification et du certificat personnel du webmestre dans Thunderbird.
Windows
Copiez le fichier cacert.pem de votre dossier ~/SSL en le renommant cacert.crt. Double-cliquez sur cacert.crt et suivez les options par défaut de la procédure d'installation. Pour installer le certificat personnel du webmestre, double-cliquez sur webmaster-cert.p12 et validez les options par défaut.
Protéger phpMyAdmin
Éditez le fichier de configuration de phpMyAdmin pour Apache /etc/phpmyadmin/apache.conf. Mettez la directive Alias en commentaire :
#Alias /phpmyadmin /usr/share/phpmyadmin
#Alias /mysql /usr/share/phpmyadmin
<Directory "/usr/share/phpmyadmin">
...
Vérifiez que phpMyAdmin ne répond plus aux adresses http://localhost/phpmyadmin et http://localhost/mysql.
Éditez le fichier de configuration du site SSL par défault /etc/apache2/sites-available/default-ssl.
Ajoutez les lignes suivante :
<VirtualHost _default_:443>
...
Alias /mysql /usr/share/phpmyadmin
<Directory "/usr/share/phpmyadmin">
SSLVerifyClient require
SSLRequire (%{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
and %{SSL_CLIENT_S_DN_O} eq "frasq.org"\
and %{SSL_CLIENT_S_DN_CN} in {"webmaster"})
#SSLCACertificateFile /etc/ssl/certs/frasq.crt
</Directory>
...
L'option require
de la directive SSLVerifyClient
impose l'échange d'un certificat client avec le serveur.
La directive SSLRequire
vérifie que le certificat transmis a été signé par frasq.org
et établi pour le nom webmaster
.
Adaptez ce paramètre en remplaçant frasq.org
par le nom de votre autorité de certification.
Notifiez Apache :
$ sudo /etc/init.d/apache2 reload
Entrez https://localhost/mysql dans la barre d'adresse de votre navigateur pour accéder à phpMyAdmin. Vérifiez que si vous retirez le certificat du webmestre de Firefox, phpMyAdmin n'est pas accessible.
Sites virtuels
Pour associer une URL locale à un site virtuel en HTTPS, créez une clé et un certificat avec le champ commonName
au nom du serveur, e.g. local.frasq.org
, et copiez la clé dans le dossier /etc/ssl/private et le certificat dans le dossier /etc/ssl/certs.
Ajoutez un fichier appelé frasq-ssl dans le répertoire /etc/apache2/sites-available avec le contenu suivant :
<VirtualHost *:443>
DocumentRoot /var/www/frasq.org
ServerName local.frasq.org
SSLEngine On
SSLCertificateFile /etc/ssl/certs/local.frasq.org.crt
SSLCertificateKeyFile /etc/ssl/private/local.frasq.org.key
</VirtualHost>
</IfModule>
Créez un lien vers le fichier /etc/apache2/sites-available/frasq-ssl dans le répertoire /etc/apache2/sites-enabled :
$ cd /etc/apache2/sites-enabled
$ sudo ln -s ../sites-available/frasq-ssl frasq-ssl
Éditez le fichier /etc/apache2/sites-available/default-ssl. Remplacez la ligne suivante :
#<VirtualHost _default_:443>
<VirtualHost *:443>
Éditez le fichier /etc/apache2/ports.conf et ajoutez une directive NameVirtualHost *:443
:
Listen 80
<IfModule mod_ssl.c>
# If you add NameVirtualHost *:443 here, you will also have to change
# the VirtualHost statement in /etc/apache2/sites-available/default-ssl
# to <VirtualHost *:443>
# Server Name Indication for SSL named virtual hosts is currently not
# supported by MSIE on Windows XP.
NameVirtualHost *:443
Listen 443
</IfModule>
Notez le commentaire à propos de la directive <VirtualHost *:443>
du fichier default-ssl.
Redémarrez Apache :
$ sudo /etc/init.d/apache2 restart
Entrez https://local.frasq.org dans la barre d'adresse de votre navigateur.
Courrier
Installez Postfix, le serveur POP de Dovecot et la commande mailx
:
$ sudo apt install postfix dovecot-pop3d bsd-mailx
Prenez l'option Internet with a smarthost
lorsque l'installation de Postfix vous demande de choisir un type de configuration.
Entrez localnet.net
comme nom de domaine.
Complétez la configuration avec le nom du serveur SMTP de votre FAI ou à défaut smtp.gmail.com
.
Postfix
Vérifiez que le fichier /etc/mailname a le contenu suivant :
localnet.net
Editez le fichier /etc/postfix/main.cf.
Cherchez le paramètre myorigin
. Ajoutez la ligne suivante :
myorigin = /etc/mailname
Cherchez le paramètre mydestination
. Donnez-lui la valeur suivante :
mydestination = localhost, localnet.net, localhost.localnet.net
Assignez au paramètre relayhost
le nom ou l'adresse IP du serveur SMTP de votre fournisseur internet :
relayhost = smtp.gmail.com
IMPORTANT : Si votre fournisseur internet refuse d'acheminer les courriers adressés à d'autres domaines, laissez ce champ à vide.
Vérifiez que le paramètre mynetworks
autorise les connexions en local, éventuellement à distance :
mynetworks = 127.0.0.0/8 192.168.0.0/16 192.168.1.0/16
Ajoutez la ligne suivante :
virtual_mailbox_base = /var/mail
Éditez le fichier /etc/aliases et redirigez le courrier local envoyé à root
et à webmaster
vers votre compte personnel :
root: frasq
webmaster: frasq
NOTE : Remplacez frasq
par votre nom de connexion.
Relancez le service :
$ sudo newaliases
$ sudo /etc/init.d/postfix restart
Essayez de vous envoyer un message :
$ mailx frasq
Subject: Test
blahblah :-)
^D
Cc:
Remplacez frasq
par votre nom de connexion. Appuyez sur Ctrl-D pour terminer le texte du message. Appuyez sur Entrée après Cc:
pour l'envoyer.
Lisez votre courrier :
$ mailx
mailx
Mail version 8.1.2 01/15/2001. Type ? for help.
"/var/mail/frasq": 1 message 1 new
>N 1 frasq@localnet.ne Thu May 13 14:10 1/423 Test.
&
Entrez le numéro du message pour l'afficher :
& 1
Message 1:
From frasq@localnet.net Thu May 13 14:10:09 2010
X-Original-To: frasq@localnet.net
To: frasq@localnet.net
Subject: Test.
Date: Thu, 13 May 2010 14:10:08 +0200 (CET)
From: frasq@localnet.net
blahblah :-)
&
Entrez d
pour détruire le message puis q
pour quitter mailx
.
NOTE : Si vous ne recevez pas le message, la raison est dans le journal d'erreur /var/log/mail.log.
Essayez d'ajouter le domaine @localnet.net
à l'adresse.
Vérifiez qu'un courrier envoyé à l'extérieur à votre adresse publique est bien relayé vers votre fournisseur internet.
Si le courrier n'arrive pas, essayez de ne donner aucune valeur au paramètre relayhost
dans main.cf.
Si le relais sendmail se plaint de ne pouvoir obtenir une identification IPv6 (Gmail) et si vous ne pouvez pas configurer votre DNS correctement, changez la valeur du paramètre inet_protocols
à ipv4
.
Dovecot
Éditez le fichier /etc/dovecot/conf.d/10-mail.conf.
Mettez le paramètre mail_location
à la valeur suivante :
mail_location = mbox:~/mail:INBOX=/var/mail/%u
Assignez le nom du groupe autorisé à écrire dans INBOX au paramètre mail_privileged_group
:
mail_privileged_group = mail
Thunderbird
NOTE : Adaptez la configuration de Thunderbird en remplaçant frasq
par votre identifiant local.
Ajoutez un compte Localhost
à Thunderbird avec pour adresse électronique frasq@localnet.net
.
Postfix est le serveur SMTP en charge des messages sortant. Dovecot est le serveur POP3 en charge des messages entrant.
Configurez le serveur entrant en POP avec localhost
comme nom de serveur et 110
comme numéro de port. Entrez frasq
comme nom d'utilisateur.
Configurez le serveur sortant en SMTP avec localhost
comme nom de serveur et 25
comme numéro de port. Optez pour aucune option de sécurité.
Assurez-vous que l'identité frasq@localnet.net
est bien associée au serveur sortant localhost
.
Relevez le courrier du compte Localhost
. Envoyez un message avec l'identité frasq@localnet.net
à frasq
. Relevez le message.
En cas de problème, la cause est dans le journal d'erreur /var/log/mail.log.
Gérer le site web
Connexion
Installez OpenSSH :
$ sudo apt install openssh-client openssh-server
Affichez l'empreinte de la clé publique de votre serveur local :
$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub
2048 75:1b:e8:dd:95:ec:86:1e:fa:da:b3:58:e1:e8:b3:87 /etc/ssh/ssh_host_rsa_key.pub (RSA)
Tentez une connexion locale :
$ ssh localhost
The authenticity of host 'localhost (::1)' can't be established.
RSA key fingerprint is 75:1b:e8:dd:95:ec:86:1e:fa:da:b3:58:e1:e8:b3:87.
Le programme affiche l'empreinte du serveur distant. Vérifiez puis acceptez la connexion :
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
frasq@localhost's password:
Entrez votre mot de passe. Vous êtes connecté. Entrez logout
pour fermer la connexion à distance.
Le fichier ~/.ssh/known_hosts contient les clé publiques de tous les serveurs auxquels vous avez été connecté :
$ cat ~/.ssh/known_hosts
Si la clé d'un serveur change, la connexion est rejetée pour vous protéger des attaques sur les adresses IP, les résolutions de noms DNS et les routages. Si le changement est légitime, retirez l'ancienne clé du fichier.
Générez une paire de clés :
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/frasq/.ssh/id_rsa):
Acceptez le nom de fichier proposé. Entrez une phrase de passe assez longue avec des chiffres, des lettres minuscules et majuscules, d'autres caractères comme des #, ~ et autres @, de la ponctuation, etc. Allez dans le dossier ~/.ssh et listez son contenu :
$ cd ~/.ssh
$ ls
id_rsa id_rsa.pub
id_rsa contient votre clé privée, id_rsa.pub votre clé publique. Assurez-vous que l'accès à votre clé privée est protégé :
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/id_rsa
$ chmod 644 ~/.ssh/id_rsa.pub
IMPORTANT : N'oubliez pas la phrase de passe. Ne donnez JAMAIS votre clé privée.
Éditez le fichier de configuration du serveur SSH /etc/ssh/sshd_config et modifiez les lignes suivantes :
RSAAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
#AuthorizedKeysFile /etc/ssh/authorized_keys/%u
PermitRootLogin no
PasswordAuthentication no
Compression yes
#AllowUsers frasq
PasswordAuthentication
à no
interdit les connexions avec une identification par mot de passe.
RSAAuthentication
à yes
active l'identification par clé RSA.
Notifiez SSH :
IMPORTANT : Avant de mettre le paramètre PasswordAuthentication
à no
, assurez-vous que la connexion par clé est opérationnelle. Pendant la mise à place, gardez un autre terminal connecté sur le serveur distant.
$ /etc/init.d/ssh reload
Tentez de vous connecter :
$ ssh localhost
Permission denied (publickey).
Pour autoriser un utilisateur à se connecter, ajoutez sa clé publique au fichier ~/.ssh/authorized_keys :
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Connectez-vous avec votre clé privée :
$ ssh localhost
Tapez la phrase de passe qui verrouille votre clé privée. Vous êtes connecté. Entrez logout
pour fermer la connexion à distance.
Pour strictement contrôler qui est autorisé à se connecter à un système, décommentez la ligne qui met le paramètre AuthorizedKeysFile
à /etc/ssh/authorized_keys/%u
dans /etc/ssh/sshd_config :
#AuthorizedKeysFile %h/.ssh/authorized_keys
AuthorizedKeysFile /etc/ssh/authorized_keys/%u
Créez le répertoire /etc/ssh/authorized_keys :
$ sudo mkdir /etc/ssh/authorized_keys
Installez votre clé publique :
$ sudo cp ~/.ssh/id_rsa.pub /etc/ssh/authorized_keys/frasq
Le nom du fichier doit correspondre au nom de connexion. Vérifiez la connexion :
$ ssh localhost
Le démon ssh-agent
enregistre les clés qui ont été débloquées.
Entrez la commande ssh-add -l
pour les lister.
Entrez la commande ssh-add -D
pour vider la liste.
Pour automatiquement vous connecter à une machine avec une clé spécifique, ajoutez les lignes suivantes dans le fichier ~/.ssh/config :
Host frasq.org
HostName=frasq.org
IdentityFile=~/.ssh/frasq@frasq.org.pub
Gestion du code source
Installez Git :
$ sudo apt install git-core
Créez un groupe git et un utilisateur git. Ajoutez votre identifiant au groupe git. Créez un dépôt partagé :
$ sudo mkdir /git
$ sudo chown git:git /git
$ chmod 775 /git
$ sudo -u git bash
$ cd /git
$ umask 007
$ git clone --bare /www/frasq frasq.git
$ cd frasq.git
$ find . -type d -print0 | xargs -0 chmod 770
$ git config core.sharedrepository 1
$ git config receive.denyNonFastforwards true
^D
Le drapeau core.sharedrepository
demande à Git de tout laisser en lecture et en écriture pour le groupe. Le drapeau receive.denyNonFastforwards
garantit que des fusions ne peuvent pas se produire lors d'une poussée vers le dépôt. Vous devez effectuer les fusions sur votre machine locale avant de pouvoir pousser le résultat.
Ajoutez l'adresse IP du serveur Git dans /etc/hosts :
127.0.0.1 githost
Créez un clone du dépôt dans votre répertoire de travail ou directement dans la racine locale du site :
$ cd /www
$ mv frasq frasq.old # make a backup copy
$ git clone ssh://githost/git/frasq.git frasq
$ cd frasq
$ git status
Quand le dépôt change, mettez vos sources locales à jour :
$ git pull
Quand vos sources locales sont dans un état stable, placez-les dans le dépôt :
$ git push
Synchronisation
Installez Rsync :
$ sudo apt install rsync
Pour télécharger une copie exacte de votre arbre de développement vers le serveur de production, exécutez la commande suivante :
$ cd /www; rsync -Catv --delete frasq www.frasq.org:www
--delete
détruit les fichiers de la copie qui ne sont plus dans la source.
-C
ignores les répertoires utilisés par CVS, SVN ou Git.
Si vous avez d'autres fichiers ou d'autres répertoires que Rsync ne doit pas télécharger, créez un fichier appelé exclude.rsync à la racine de l'arbre, listez les chemins d'accès que Rsync doit ignorer, y compris exclude.rsync, et ajoutez l'option --exclude-from=/www/frasq/exclude.rsync
à la ligne de commande.
NOTE : Rsync utilise SSH pour transférer les fichiers. Pensez à ajouter votre clé publique ~/.ssh/id_rsa.pub au fichier ~/.ssh/authorized_keys sur le système distant.
#
abort () {
echo $1 >&2
exit ${2-1}
}
usage () {
abort "$0 sitename"
}
if [ $# -ne 1 ]
then
usage
fi
host='www.frasq.org'
sitename=('frasq.org')
siteuser=('frasq')
siterdir=('/var/www/frasq.org')
exclude='--exclude .gitignore --exclude .settings --exclude .buildpath --exclude .project --exclude log --exclude tmp'
name=
user=
rdir=
for (( i = 0; i < ${#sitename[@]}; i++ ))
do
if [ $1 == ${sitename[$i]} ]
then
name=${sitename[$i]}
user=${siteuser[$i]}
rdir=${siterdir[$i]}
break
fi
done
if [ -z "$name" ]
then
abort "$1?"
fi
(cd /www; rsync -Catv --delete $exclude /var/www/${name}/ ${user}@${host}:${rdir}/)
Supervision
Téléchargez les paquets des sources du core et des plugins de Nagios. Installez les modules nécessaires à la compilation du code :
$ sudo apt install openssl snmp snmpd libsnmp-dev ligd-dev
Créez un groupe nagios
et un utilisateur nagios
:
$ sudo addgroup --gid 300 nagios
$ sudo adduser --uid 300 --gid 300 nagios
Ajoutez l'utilisateur Apache www-data
dans le groupe nagios
:
$ sudo adduser www-data nagios
Compilez et installez Nagios :
$ tar -zxvf nagios-4.*.tar.gz
$ cd nagios-4.*
$ ./configure --with-httpd-conf=/etc/apache2/conf-available
$ make nagios cgis contrib modules
$ make all
$ sudo make install install-base install-cgis install-html install-config install-init install-commandmode fullinstall
$ sudo cp ./sample-config/httpd.conf /etc/apache2/conf-available/nagios.conf
$ sudo a2enconf nagios
NOTE : Pour une version plus ancienne d'Apache, copiez le fichier httpd.conf dans le dossier /etc/apache2/conf.d.
$ tar -zxvf nagios-plugins-2.*.tar.gz
$ cd nagios-plugins-2.*
$ ./configure
$ sudo make install
Le programme s'installe dans le répertoire /usr/local/nagios. Vérifiez que l'installation est opérationnelle :
$ /usr/local/nagios/libexec/check_http -H --ssl www.frasq.org
HTTP OK: HTTP/1.1 200 OK - 11192 octets en 0.016 seconde de temps de réponse|time=0.015749s;;;0.000000 size=11192B;;;0
Pour compiler et installer NRPE - Nagios Remote Plugin Executor, téléchargez le paquet à partir de la page des add-ons puis recherchez l'emplacement de la librairie SSL :
$ sudo apt install apt-file
$ sudo apt-file update
$ apt-file search libssl|grep libssl-dev
Passez le répertoire de la librairie à configure
:
$ tar -zxvf nrpe-3.*.tar.gz
$ ./configure --with-ssl --with-ssl-lib=/usr/lib/libx86_64-linux-gnu
$ make all
$ sudo make install
Éditez le fichier /usr/local/nagios/etc/objects/contacts.cfg et modifiez la ligne qui configure l'adresse d'email utilisée pour les alertes :
define contact{
contact_name nagiosadmin ; Short name of user
...
email frasq
}
Vérifiez la configuration :
$ sudo /usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg
Activez le service :
$ sudo systemctl enable nagios.service
Démarrez Nagios :
$ sudo systemctl start nagios
Créez le mot de passe pour l'interface web :
$ cd /usr/local/nagios/etc
$ sudo htpasswd -c htpasswd.users nagiosadmin
$ sudo chmod 660 htpasswd.users
$ sudo chown nagios:nagios htpasswd.users
Assurez-vous que le module cgi est activé :
$ sudo a2enmod cgi
Redémarrez Apache :
$ sudo systemctl restart apache2
Entrez http://localhost/nagios/ dans la barre d'adresse de votre navigateur.
Entrez nagiosadmin
comme nom d'utilisateur et le mot de passe que vous avez défini avec la commande htpasswd
.
Cliquez sur le lien services
dans le menu sur le côté gauche.
Essayez Imoin.
Sauvegardes
Installez backup-manager
:
$ sudo apt install backup-manager
Éditez le fichier /etc/backup-manager.conf :
export BM_REPOSITORY_GROUP="adm"
export BM_UPLOAD_METHOD="none"
export BM_BURNING_METHOD="none"
export BM_ARCHIVE_TTL="365"
export BM_ARCHIVE_METHOD="tarball-incremental mysql"
export BM_TARBALL_FILETYPE="tar.bz2"
export BM_TARBALLINC_MASTERDATETYPE="weekly"
export BM_TARBALLINC_MASTERDATEVALUE="5"
export BM_TARBALL_DIRECTORIES="/etc /var/www /home/frasq"
export BM_TARBALL_BLACKLIST=".git *.o"
export BM_MYSQL_SAFEDUMPS="true"
export BM_MYSQL_ADMINLOGIN="backupmanager"
export BM_MYSQL_ADMINPASS="backupmanager-password"
Adaptez les paramètres, en particulier BM_TARBALL_DIRECTORIES
et BM_TARBALL_BLACKLIST
.
La BD MySQL est intégralement sauvegardée avec mysqldump
.
Créez un utilisateur MySQL appelé backupmanager
avec les privilèges Selec_priv
et Lock_tables_priv
et un mot de passe aléatoire que vous copierez dans le paramètre BM_MYSQL_ADMINPASS
.
Créez un script backup-manager en mode 775 dans le dossier /etc/cron.daily :
#!/bin/sh
# cron script for backup-manager
test -x /usr/sbin/backup-manager || exit 0
/usr/sbin/backup-manager
Vérifiez le moment d'exécution des scripts cron.daily
, cron.weekly
et cron.monthly
dans /etc/crontab.
Ajoutez un fichier .backup-manager_my.cnf en mode 600 dans votre répertoire racine et dans celui de root
:
[mysqldump]
user="backupmanager"
password="mysql-backupmanager-password"
Quotas
Installez le paquet des quotas :
$ sudo apt install quota
Éditez le fichier /etc/fstab et ajoutez les options usrquota
et grpquota
au système de fichiers :
/dev/sda2 /home ext4 defaults,usrquota,grpquota,relatime 0 2
Remontez le système de fichiers :
$ sudo mount -o remount /home
Initialisez les quotas :
$ sudo quotacheck -avug
Définissez les quotas pour un utilisateur ou pour un groupe :
$ sudo edquota frasq
Quotas disque pour user frasq (uid 1000) :
Système de fichiers blocs souple stricte inodes souple stricte
/dev/sda2 55188 0 1000000 1995 0 0
Vérifiez les quotas :
$ sudo repquota /home
DNS
Installez Bind :
$ sudo apt install bind9
Éditez le fichier /etc/bind/named.conf.local. Ajoutez une zone pour le domaine frasq.org et associez-la au fichier de configuration /etc/bind/db.frasq.org.
NOTE : remplacez frasq.org par le nom de domaine de votre site.
zone "frasq.org" {
type master;
file "/etc/bind/db.frasq.org";
allow-transfer { isp-dns-ip; };
allow-query { any; };
notify yes;
};
L'option allow-transfer
liste les adresses IP des serveurs autorisés à copier la zone.
Remplacez isp-dns-ip
par l'adresse IP du serveur DNS de votre fournisseur internet.
Éditez le fichier /etc/bind/named.conf.options.
auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
listen-on { any; };
allow-recursion { 127.0.0.1; };
allow-query-cache { 127.0.0.1; isp-dns-ip; };
additional-from-cache no;
Remplacez isp-dns-ip
par l'adresse IP du serveur DNS de votre fournisseur internet.
Créez le fichier /etc/bind/db.frasq.org avec le contenu suivant :
; frasq.org
$TTL 3600
@ IN SOA primary-dns-hostname. root.frasq.org. (
1 ; SERIAL
3600; REFRESH
15M; RETRY
1W; EXPIRE
600 ) ; Negative Cache TTL
;
; nameservers
;
frasq.org. IN NS primary-dns-hostname.
frasq.org. IN NS isp-dns-hostname.
;
; nodes in domain
;
www IN A primary-dns-ip
mail IN A primary-dns-ip
smtp IN A primary-dns-ip
pop IN A primary-dns-ip
ftp IN A primary-dns-ip
imap IN A primary-dns-ip
frasq.org. IN A primary-dns-ip
frasq.org. IN MX 10 mail.frasq.org.
;
; subdomains
;
*.frasq.org. IN A primary-dns-ip
Remplacez primary-dns-hostname
par le nom du serveur, primary-dns-ip
par l'adresse IP du serveur, isp-dns-hostname
par le nom du serveur DNS de votre fournisseur internet.
N'oubliez pas les . (POINT) à la fin d'un nom.
Si vous souhaitez garder le service de courrier de votre fournisseur internet, essayez la configuration suivante :
; frasq.org
$TTL 3600
@ IN SOA primary-dns-hostname. root.frasq.org. (
1 ; SERIAL
3600; REFRESH
15M; RETRY
1W; EXPIRE
600 ) ; Negative Cache TTL
;
; nameservers
;
frasq.org. IN NS primary-dns-hostname.
frasq.org. IN NS isp-dns-hostname.
;
; nodes in domain
;
www IN A primary-dns-ip
mail IN CNAME isp-mail-hostname.
smtp IN CNAME isp-smtp-hostname.
pop IN CNAME isp-pop-hostname.
ftp IN A primary-dns-ip
imap IN CNAME isp-imap-hostname.
frasq.org. IN A primary-dns-ip
frasq.org. IN MX 10 isp-mx-hostname.
;
; subdomains
;
*.frasq.org. IN A primary-dns-ip
Remplacez les différents noms des serveurs par service par ceux de votre fournisseur internet.
Si vous voulez que votre DNS supporte IPv6, ajoutez les lignes suivantes :
;
; IPv6
;
www IN AAAA primary-dns-ipv6
ftp IN AAAA primary-dns-ipv6
;
frasq.org. IN AAAA primary-dns-ipv6
*.frasq.org. IN AAAA primary-dns-ipv6
;
Certains fournisseurs internet demandent une preuve que le serveur est bien autorisé à gérer le domaine :
ownercheck IN TXT "isp-domain-key"
Pour la vérification d'un domaine par Google, utilisez ce format :
@ IN TXT "google-site-verification=..."
IMPORTANT : Incrémentez le numéro de série du fichier à chaque modification.
Redémarrez Bind :
$ sudo /etc/init.d/named restart
Vérifiez la configuration :
$ sudo named-checkconf -z
Testez le DNS local :
$ nslookup frasq.org localhost
Testez le DNS de votre fournisseur internet :
$ nslookup frasq.org isp-dns-hostname
Pour vérifier un enregistrement TXT :
$ nslookup -q=txt ownercheck.frasq.org localhost
NTP
Installez NTP:
$ sudo apt install ntp
Editez le fichier /etc/ntp.conf. Ajoutez le serveur de temps de votre zone - NTP Pool Project - avant le serveur déjà listé :
# You do need to talk to an NTP server or two (or three).
server fr.pool.ntp.org
server ntp.ubuntu.com
Redémarrez le serveur NTP :
$ sudo service ntp restart
Vérifiez que le serveur de temps est opérationnel :
$ ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
*europium.canoni 193.79.237.14 2 u 99 1024 377 4.959 -0.200 0.005
Lisez le manuel Écrire un CMS en PHP pour apprendre comment structurer le développement d'un site web.
Commentaires