<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
>

<channel>
	<title>Metrogeek</title>
	<atom:link href="https://metrogeek.fr/feed/" rel="self" type="application/rss+xml" />
	<link>https://metrogeek.fr</link>
	<description>Le bahut du codeur : Apprendre et partager le code</description>
	<lastBuildDate>Fri, 03 Feb 2017 20:47:26 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.2.1</generator>
<site xmlns="com-wordpress:feed-additions:1">108012675</site>	<item>
		<title>Django et Laravel-mix</title>
		<link>https://metrogeek.fr/django-et-laravel-mix/</link>
				<comments>https://metrogeek.fr/django-et-laravel-mix/#respond</comments>
				<pubDate>Fri, 03 Feb 2017 20:47:26 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[laravel]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=389</guid>
				<description><![CDATA[Juste avant de passer au vrai sujet de ce billet, parlons un peu des virtualenv. Récemment, Python3.6 a été publié. Mise à jour classique du langage, mais ça m&#8217;a permis d&#8217;apprendre quelque chose. En fait je tentais de préparer une [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>Juste avant de passer au vrai sujet de ce billet, parlons un peu des virtualenv. Récemment, Python3.6 a été publié. Mise à jour classique du langage, mais ça m&rsquo;a permis d&rsquo;apprendre quelque chose.<br />
En fait je tentais de préparer une configuration Webpack avec Helpmepiz, et en voulant réactiver le virtualenv, plus rien ne répondait. C&rsquo;était lié à ma nouvelle version du langage, et c&rsquo;est là que l&rsquo;utilisation de freeze a pris tout son sens. Il a fallut supprimer le dossier env, et et en créer un nouveau, puis lancer pip freeze > requirements.txt.<br />
Par contre, ça m&rsquo;a surtout fait comprendre que le virtualenv n&rsquo;avait rien à faire dans le dépôt. Il faut le mettre complètement ailleurs, là où j&rsquo;avais pris comme reflex de le mettre au même niveau que l&rsquo;appli. Il faudra donc que je déporte ça à terme, mais surtout, ne faites pas la même erreur !</p>
<p>Passons maintenant à Laravel-mix. En poussant la configuration de webpack, je commençais à avoir envie de pleurer. Puis Laravel-mix est arrivé. C&rsquo;est un Webpack prêt à l&rsquo;usage, qui colle parfaitement à ce que je veux faire. Il se colle sur n&rsquo;importe quelle application, contrairement à ce que son nom laisse entendre, donc allons-y !</p>
<h2>Installation avec Yarn</h2>
<p>Il faut donc déjà avoir Yarn d&rsquo;installé en global. Ensuite, on va installer Webpack, également en global. Une dépendance qui n&rsquo;est pas encore documentée (<a href="https://github.com/JeffreyWay/laravel-mix/issues/94" target="_blank">mais qui vous évitera de chercher</a>), est cross-env, qu&rsquo;il faut aussi avoir en global :</p>
<pre class="brush: bash; title: code; notranslate">sudo npm install -g webpack cross-env</pre>
<p>Effectivement, je n&rsquo;utilise pas Yarn pour installer en global, il y a des soucis dans les liens symboliques, donc npm est plus approprié. </p>
<p>Ensuite on est prêt à accueillir Mix dans l&rsquo;application :</p>
<pre class="brush: bash; title: code; notranslate">yarn add laravel-mix &amp;&amp; cp -r node_modules/laravel-mix/setup/** ./</pre>
<h2>Ajouter les commandes npm</h2>
<p>Pour s&rsquo;éviter d&rsquo;avoir à taper les longues commandes avec webpack, voici ce que vous devez ajouter au fichier packages.json :</p>
<pre class="brush: bash; title: code; notranslate">&quot;scripts&quot;: {
    &quot;webpack&quot;: &quot;cross-env NODE_ENV=development webpack --progress --hide-modules&quot;,
    &quot;dev&quot;: &quot;cross-env NODE_ENV=development webpack --watch --progress --hide-modules&quot;,
    &quot;hmr&quot;: &quot;cross-env NODE_ENV=development webpack-dev-server --inline --hot&quot;,
    &quot;production&quot;: &quot;cross-env NODE_ENV=production webpack --progress --hide-modules&quot;
  }</pre>
<p>La commande webpack vous permet de compiler vos fichiers une seule fois.<br />
La commande dev va recompiler à chaque changement de fichier<br />
La commande hmr vous permet d&rsquo;activer le hrm (duh?)<br />
Et la commande production va compiler, minifier, et générer les .map pour la production.</p>
<h2>Modifier la configuration apache</h2>
<p>On a vu dans un article précédent comment configurer un <a href="https://metrogeek.fr/setup-de-django-avec-apache/" target="_blank">vhost apache pour Django</a>. Mais si on livrait les assets compilés dans le repertoire /assets de l&rsquo;application (c&rsquo;est le comportement par défaut de Django il me semble), je préfère changer et passer ça dans /dist.<br />
/assets contiendra tous les fichiers non compilés, donc voici ce qu&rsquo;on ajoute :</p>
<pre class="brush: bash; title: code; notranslate">Alias /static/  /chemin/vers/helpmepyz.dev/helpmepyz/dist/</pre>
<h2>La fonction mix pour Python/Django</h2>
<p>Alors c&rsquo;est ma toute première fonction python, c&rsquo;est pas parfait, mais ça fait le job. Il faudra juste remplacer le retour avec un objet request, pour déterminer l&rsquo;url complète.</p>
<p>Mais globalement, qu&rsquo;est ce que fait cette fonction :</p>
<p>Ignorons la partie hot reload pour l&rsquo;instant, mais Laravel Mix génère un fichier mix-manifest.json. Dans ce fichier, il y a les chemins vers les chunks versionnés, ce qui va vous éviter de dire « vous pouvez rafraichir la page syouplai? F5 ».</p>
<pre class="brush: python; title: code; notranslate">
from os.path import isfile, abspath
from os import getcwd
from json import loads


def mix(path, manifest = False, should_hot_reload = False):
    if not manifest:
        manifest_path = getcwd() + '/mix-manifest.json'
        should_hot_reload = isfile(abspath('/dist/hot'))
        if not isfile(manifest_path):
            raise Exception( 'The Laravel Mix manifest file does not exist. Please run &quot;npm run webpack&quot; and try again.')

        manifest_file = loads(open(manifest_path).read())

    # if (not path.startswith('/')): path = f&quot;/{path}&quot;

    if not path in manifest_file:
        raise Exception('Unknown Laravel Mix file path: f&quot;{path}&quot;.'
                        'Please check your requested webpack.mix.js output path, and try again.')

    return 'http://localhost:8080f&quot;{manifest_file[path]}&quot;' if should_hot_reload else manifest_file[path]

</pre>
<p>Donc on va bientôt être prêt coté front !</p>
<p>Sinon, en lisant <a href="http://sametmax.com/les-imports-en-python/" target="_blank">Sam et Max</a>, je suis tombé sur cette phrase, qui m&rsquo;a permis de comprendre la différence entre les 2 termes, et de manière très simple, donc je vous la laisse :</p>
<blockquote><p>
Donc, quand vous faites import os, Python va faire une boucle for là dessus et chercher dans chaque dossier si un package (un dossier avec un fichier __init__.py) ou un module (un fichier avec l’extension .py) nommé os existe.
</p></blockquote>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/django-et-laravel-mix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">389</post-id>	</item>
		<item>
		<title>Quelles différences il y a entre Eloquent et Doctrine2 ?</title>
		<link>https://metrogeek.fr/differences-eloquent-doctrine2/</link>
				<comments>https://metrogeek.fr/differences-eloquent-doctrine2/#respond</comments>
				<pubDate>Thu, 12 Jan 2017 11:30:12 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[dev]]></category>
		<category><![CDATA[laravel]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=382</guid>
				<description><![CDATA[En fait, chacun utilise un pattern différent. Eloquent implémente Active Record, qui est généralement plus facilement utilisable. Doctrine2 quant à lui, implémente le pattern Data Mapper. Je vous renvoie aux fiches Wikipédia [1][2] pour en savoir plus si ces 2 [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>En fait, chacun utilise un pattern différent. Eloquent implémente <strong>Active Record</strong>, qui est généralement plus facilement utilisable. Doctrine2 quant à lui, implémente le pattern <strong>Data Mapper</strong>. Je vous renvoie aux fiches Wikipédia [<a href="https://fr.wikipedia.org/wiki/Active_record" target="_blank">1</a>][<a href="https://en.wikipedia.org/wiki/Data_mapper_pattern" target="_blank">2</a>] pour en savoir plus si ces 2 termes sont abstraits pour vous, ici on va se concentrer sur Eloquent et Doctrine2.</p>
<h2>Eloquent</h2>
<p>Quand vous prenez un modèle Laravel, une fois instancié, vous pouvez directement appeler la méthode <em>save()</em> dessus. Etant donné que ce modèle étend Eloquent, c&rsquo;est Eloquent qui va directement s&rsquo;occuper de la sauvegarde et de la restauration des données : <strong>La persistance</strong>.</p>
<h2>Doctrine2</h2>
<p>Même si ça se passe autrement pour Doctrine, en regardant un modèle, on s&rsquo;aperçoit qu&rsquo;il n&rsquo;étend aucune classe. Donc il ne traitera pas directement avec la base de données, et vous devez donc définir toutes les propriétés du modèle puisqu&rsquo;il n&rsquo;est pas directement connecté à la base.<br />
Ce qui rend potentiellement Doctrine <strong>plus léger</strong> (en mémoire) à l&rsquo;usage.</p>
<h2>Migrations VS Annotations</h2>
<p>Là où Laravel va gérer la structure de la base de données, via des fichiers de migration qui sont executé manuellement, Doctrine2 va utiliser un système d&rsquo;annotation pour que l&rsquo;<strong>Entity Manager</strong> puisse structurer la base en fonction de ce qui a été décrit.</p>
<p>Voici l&rsquo;exemple d&rsquo;annotation pour Doctrine, directement extrait de la documentation :</p>
<pre class="brush: php; title: code; notranslate">
&lt;?php
/**
 * @Column(type=&quot;string&quot;, length=32, unique=true, nullable=false)
 */
protected $username;

/**
 * @Column(type=&quot;string&quot;, columnDefinition=&quot;CHAR(2) NOT NULL&quot;)
 */
protected $country;

/**
 * @Column(type=&quot;decimal&quot;, precision=2, scale=1)
 */
protected $height;

/**
 * @Column(type=&quot;string&quot;, length=2, options={&quot;fixed&quot;:true, &quot;comment&quot;:&quot;Initial letters of first and last name&quot;})
 */
protected $initials;

/**
 * @Column(type=&quot;integer&quot;, name=&quot;login_count&quot; nullable=false, options={&quot;unsigned&quot;:true, &quot;default&quot;:0})
 */
protected $loginCount;
</pre>
<p>Ca a l&rsquo;avantage de déresponsabiliser le développeur sur la gestion de la base. Avec Eloquent, et plus particulièrement avec Laravel, si tu ne mets pas les bonnes infos dans la méthode down(), tu peux simplement tout casser.</p>
<h2>L&rsquo;Entity Manager</h2>
<p>Vu que votre modèle ne s&rsquo;occupe pas de la persistance, c&rsquo;est l&rsquo;entity manager qui s&rsquo;en charge. Le résultat c&rsquo;est qu&rsquo;il faut écrire beaucoup plus de choses pour le même résultat, mais l&rsquo;avantage c&rsquo;est la légèreté.</p>
<p>Voici comment on va créer, et sauvegarder une propriété avec Eloquent :</p>
<pre class="brush: php; title: code; notranslate">
&lt;?php
$user = new User;
$user-&gt;email('foo@bar.com');
$user-&gt;save();


EntityManager::persist($user);
EntityManager::flush();
</pre>
<p>Et voici comment ça se passe pour Doctrine2 :</p>
<pre class="brush: php; title: code; notranslate">

&lt;?php
$user = new User;
$user-&gt;setEmail('foo@bar.com');

EntityManager::persist($user);
EntityManager::flush();

</pre>
<p>En gros, la différence vient du fait que <em>persist()</em> est utilisé pour générer la transaction vers la base de donnée. <em>Flush()</em> est appelé pour valider la transaction et faire la modification dans la base de données.</p>
<h2>Setters &#038;&#038; Getters</h2>
<p>Là aussi une différence fondamentale, toujours liée au fait que le modèle n&rsquo;a aucun lien avec la base de données :<br />
Là où Eloquent va aller chercher les propriétés demandées dans la base de données (si le champ existe), Doctrine2 a besoin d&rsquo;avoir tous les <strong>getters</strong> et tous les <strong>setters</strong> pour accéder à un champ.</p>
<p>Donc là aussi, Doctrine2 va être plus <strong>verbeux</strong>, mais ça a l&rsquo;avantage d&rsquo;en savoir tout de suite plus sur son modèle aussi. Et n&rsquo;oublions pas encore, la légèreté.</p>
<h2>Les requêtes</h2>
<p>Bel avantage pour Eloquent sur ce point selon moi. La grande majorité des requètes avec Eloquent peut se faire avec une véritable syntaxe PHP. C&rsquo;est à dire que tu n&rsquo;écris presque plus de SQL.<br />
Forcément, écrire peu de requète SQL a ses avantages, et ses inconvénients, mais ce n&rsquo;est pas le sujet ici. Au quotidien, je trouve ça pratique quand même.</p>
<h3>Requêtes Eloquent</h3>
<pre class="brush: php; title: code; notranslate">
&lt;?php

$users = User::where('email', strtolower($user-&gt;email))-&gt;whereNotNull('deleted_at')-&gt;get();
</pre>
<h3>Requêtes Doctrine2</h3>
<pre class="brush: php; title: code; notranslate">
&lt;?php

$query = EntityManager::createQuery(&quot;select u from User u where u.email = LOWER({$email}) and u.deteled_at IS NOT NULL&quot;);

$users = $query-&gt;getResult();
</pre>
<h2>Lequel choisir</h2>
<p>Il n&rsquo;y a pas de meilleur choix, les 2 ont leurs avantages &#8211; oui, et leurs inconvénients aussi. Au début on peut être plus facilement accroché par Eloquent, et Active Record donc. Plus simple, moins verbeux etc. Ca passe pour toutes les applications <strong>CRUD</strong>, et c&rsquo;est très bien.</p>
<p>Vu que je préfère éviter les débats Vim/Emacs, Chocolatine/Pain au chocolat, je vous recommande la lecture de <a href="http://culttt.com/2014/06/18/whats-difference-active-record-data-mapper/" target="_blank">ce billet</a> (en) qui vous donnera des pistes pour choisir lequel correspond le mieux à votre application.</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/differences-eloquent-doctrine2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">382</post-id>	</item>
		<item>
		<title>Trucs et astuces pour son serveur privé</title>
		<link>https://metrogeek.fr/trucs-astuces-serveur-prive/</link>
				<comments>https://metrogeek.fr/trucs-astuces-serveur-prive/#respond</comments>
				<pubDate>Mon, 12 Dec 2016 08:46:48 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[gnu]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=374</guid>
				<description><![CDATA[C&#8217;est bien d&#8217;installer apache, son serveur DNS, mais si on ne connait pas les outils de base ça ne sert à rien.Du coup je me suis dis que ce serait une bonne idée de compiler dans un article quelques trucs [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>C&rsquo;est bien d&rsquo;installer apache, son serveur DNS, mais si on ne connait pas les outils de base ça ne sert à rien.Du coup je me suis dis que ce serait une bonne idée de compiler dans un article quelques trucs et astuces, relatifs notamment à la surveillance de votre serveur.</p>
<p>C’est l’occasion d’apprendre ou réapprendre à se servir des outils inclus dans toute bonne distribution qui se respecte, mais aussi comment compléter ces outils.</p>
<h2>Monitoring « sur site »</h2>
<h3>Journaux</h3>
<p>Ce que j’appelle «&nbsp;monitoring sur site&nbsp;», c’est comment surveiller son système depuis un shell. Un certain nombre de commandes existent pour nous permettre de diagnostiquer le fonctionnement de notre serveur.</p>
<p>Pour commencer, rien ne vaut les journaux. Concernant notre serveur, voici ceux qui sont principalement à surveiller :</p>
<ul>
<li><em>/var/log/syslog</em>, probablement le plus important de tous</li>
<li><em>/var/log/fail2ban.log</em>, pour surveiller ce que fail2ban fait</li>
<li><em>/var/log/mail.log</em>, pour surveiller le serveur mail</li>
<li><em>/var/www/*/*/log/</em>, pour surveiller les accès et erreurs sur l’ensemble de vos sites Internet</li>
</ul>
<p>Pour consulter en temps réel un journal, utilisez la commande suivante :</p>
<pre class="brush: bash; title: code; notranslate">tail -f /var/log/syslog</pre>
<p>Pour consulter les X dernières lignes d’un journal :</p>
<pre class="brush: bash; title: code; notranslate">tail -X /var/log/syslog</pre>
<h3>Processus</h3>
<p>Le monitoring sur site implique également la surveillance des processus. La commande suivante :</p>
<pre class="brush: bash; title: code; notranslate">ps aux</pre>
<p>Vous indiquera l’état des processus au moment où vous lancez la commande. Pour consulter l’état des processus en temps réel, utilisez la commande :</p>
<pre class="brush: bash; title: code; notranslate">top</pre>
<p>Cette commande vous informe également de l’état de la mémoire, de l’utilisation CPU, et d’autres choses encore.</p>
<h3>Matériel</h3>
<p>Si vous hébergez vous-même votre serveur «&nbsp;à la maison&nbsp;», vous pourrez également avoir besoin de quelques capteurs de température :</p>
<pre class="brush: bash; title: code; notranslate">apt-get install lm-sensors
sensors-detect</pre>
<p>De même pour les disques durs :</p>
<pre class="brush: bash; title: code; notranslate">apt-get install hddtemp
hddtemp /dev/sd*</pre>
<p>D’autres informations relatives à votre matériel peuvent être extraites du pseudo système de fichiers <em>/proc</em> :</p>
<pre class="brush: bash; title: code; notranslate">cat /proc/cpuinfo
cat /proc/meminfo</pre>
<h3>RAID</h3>
<p>Si vous bénéficiez d’un raid logiciel, vous pouvez consulter son état de différentes manières :</p>
<pre class="brush: bash; title: code; notranslate">cat /proc/mdstat
mdadm --detail /dev/md0</pre>
<h2>Monitoring distant</h2>
<p>Le monitoring distant est effectué depuis une interface web par exemple. J’ai choisi <a href="http://phpsysinfo.sourceforge.net/">phpSysInfo</a>, que je trouve plus agréable à configurer et utiliser que munin, trop centré sur la création de graphs, et relativement compliqué à mettre en œuvre.</p>
<h3>Hôte virtuel</h3>
<p>Première chose, comme d’habitude, on s’occupe de l’hôte virtuel dans apache :</p>
<pre class="brush: bash; title: code; notranslate">mkdir -p /var/www/exemple.fr/system/www
nano /etc/apache2/sites-available/system.exemple.fr</pre>
<pre class="brush: bash; title: code; notranslate">&lt;VirtualHost *:80&gt;
    ServerName system.exemple.fr
    Redirect / https://system.exemple.fr/
&lt;/VirtualHost&gt;

&lt;VirtualHost *:443&gt;
    ServerName system.exemple.fr

    DocumentRoot /var/www/exemple.fr/system/www

    SSLEngine On
    SSLCertificateFile /scripts/certificate_authority/apache/system.exemple.fr.crt
    SSLCertificateKeyFile /scripts/certificate_authority/apache/system.exemple.fr.key
&lt;/VirtualHost&gt;</pre>
<p>Nous avons créé un hôte virtuel non sécurisé redirigeant vers un hôte virtuel sécurisé, nous avons déjà vu le principe. Créons maintenant les certificats :</p>
<pre class="brush: bash; title: code; notranslate">
/scripts/certificate_authority/make_request apache system.exemple.fr
/scripts/certificate_authority/sign_request apache system.exemple.fr
chown www-data:www-data /scripts/certificate_authority/apache/*
</pre>
<div class="warning_block message-block">
<p class="printonly"><strong>Warning!</strong></p>
<p>Lorsque le <em>Common Name</em> vous sera demandé, indiquez le nom de domaine ! Et dans notre cas, acceptez la création d’une clé sans mot de passe !</div>
<p>On active le site, et on redémarre apache :</p>
<pre class="brush: bash; title: code; notranslate">a2ensite system.exemple.fr
/etc/init.d/apache2 restart</pre>
<p>Dans ce cas, il n’y a pas vraiment besoin de tenir des journaux.</p>
<h3>Installation de phpSysInfo</h3>
<p>Rien de particulier à signaler : une fois l’application téléchargée et installée dans son répertoire (<em>/var/www/exemple.fr/system/www</em>), il suffit juste de la configurer en fonction des blocs que vous souhaitez afficher.</p>
<p>Certaines dépendances peuvent être nécessaires, en fonction des blocs que vous aurez configuré. L’application vous informera via des messages d’erreurs si des dépendances ne sont pas satisfaites. Vous pourrez alors aisément les installer.</p>
<h2>Notifications</h2>
<p>Si vous faites appel à crontab pour effectuer des tâches routinières, il peut être intéressant d’avoir des rapports par mail. Il vous suffit d’éditer votre crontab et d’y insérer la ligne suivante :</p>
<pre class="brush: bash; title: code; notranslate">MAIL=&quot;contact@exemple.fr&quot;</pre>
<p>Nous avons installé un serveur XMPP, on peut également s’en servir comme service de notification. Ainsi, pour toute application qui permet d’exécuter une commande suivant un évènement donné, on peut demander à cette application d’envoyer un message à un compte XMPP que vous aurez créé à cet effet. Nous utiliserons pour cela le script <em>sendxmpp</em> :</p>
<pre class="brush: bash; title: code; notranslate">apt-get install sendxmpp</pre>
<p>Que l’on utilisera de la manière suivante :</p>
<pre class="brush: bash; title: code; notranslate">echo &quot;Votre message&quot; | sendxmpp -u &lt;utilisateur&gt; -p &lt;mot de passe&gt; -j exemple.fr &lt;destinataire&gt;@exemple.fr</pre>
<h2>Liste des paquets installés</h2>
<p>Il peut être utile de récupérer la liste de tous les paquets installés, par exemple dans le cas d’une réinstallation ou d’un mirroring. Pour récupérer cette liste, on utilisera la commande suivante :</p>
<pre class="brush: bash; title: code; notranslate">dpkg -l | grep ii | awk -F ' ' '{print $2}'</pre>
<p>On peut, du coup, exporter cette liste dans un fichier :</p>
<pre class="brush: bash; title: code; notranslate">dpkg -l | grep ii | awk -F ' ' '{print $2}' &gt; packages.list</pre>
<h2>Conclusion</h2>
<p>Plein d’autres choses manquent surement à l’appel. On ne peut pas tout voir, mais théoriquement, ce qu’on a vu jusqu’aujourd’hui devrait être suffisant pour que vous puissiez jouer avec votre propre instance.</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/trucs-astuces-serveur-prive/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">374</post-id>	</item>
		<item>
		<title>Setup de Django avec Apache</title>
		<link>https://metrogeek.fr/setup-de-django-avec-apache/</link>
				<comments>https://metrogeek.fr/setup-de-django-avec-apache/#comments</comments>
				<pubDate>Tue, 29 Nov 2016 13:22:32 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[apache]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=356</guid>
				<description><![CDATA[C&#8217;était franchement pas le truc le plus facile, mais ça y est. Je peux faire tourner Django avec Apache. C&#8217;était vraiment pour le style, parce que tant que vous êtes en dev, il est largement préférable d&#8217;utiliser runserver, le serveur [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>C&rsquo;était franchement pas le truc le plus facile, mais ça y est. Je peux faire tourner <strong>Django</strong> avec Apache. C&rsquo;était vraiment pour le style, parce que tant que vous êtes en dev, il est largement préférable d&rsquo;utiliser <em>runserver</em>, le serveur web disponible avec Django. Pourquoi ?</p>
<p>Et bien parce qu&rsquo;il faut recharger <strong>apache</strong> à chaque modification de fichier. En discutant sur <em>IRC #django-fr</em> c&rsquo;est ce que j&rsquo;avais pensé lire, et ça s&rsquo;est confirmé quand j&rsquo;ai réussit à faire fonctionner le bouzin. Mais de toute façon notre application va partir en production, donc autant savoir quoi faire.</p>
<p><a href="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png"><img data-attachment-id="184" data-permalink="https://metrogeek.fr/django-base-de-donnees/challenge/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" data-orig-size="800,300" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge-300x113.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" src="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" alt="" width="800" height="300" class="aligncenter size-full wp-image-184" srcset="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png 800w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-300x113.png 300w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-768x288.png 768w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-200x75.png 200w" sizes="(max-width: 800px) 100vw, 800px" /></a></p>
<h2>Apache</h2>
<p>Au risque de dire quelques bêtises, l&rsquo;équivalent de fast-cgi quand on veut pythonner, c&rsquo;est <strong>wsgi</strong>. Pour ceux qui veulent en savoir plus, je vous recommande l&rsquo;article de <a href="http://sametmax.com/quest-ce-que-wsgi-et-a-quoi-ca-sert/" target="_blank">Sam et Max</a> qui traite du sujet. Il faut donc installer le module apache correspondant à <strong>votre distribution GNU/Linux</strong>. Ensuite, il faut activer le module en modifiant le httpd.conf et en ajoutant :</p>
<pre class="brush: bash; title: code; notranslate">
LoadModule wsgi_module modules/mod_wsgi.so
#ça peut changer en fonction de votre distribution aussi. Ici on est sur archlinux, donc Apache est brut.
</pre>
<p>Vu le temps que ça m&rsquo;a pris d&rsquo;avoir le bon template pour avoir un vhost qui fonctionne, dans le virtualenv, avec les bons chemins, ce n&rsquo;est pas une mauvaise idée de t&rsquo;en faire cadeau :</p>
<p><script src="https://gist.github.com/rikless/e0e762c05e60cf055e1eb56a1921c5dc.js"></script></p>
<h2>La homepage : première app du projet</h2>
<h3>On rembobine</h3>
<p>Dans le <a href="https://metrogeek.fr/point-etape-python/" target="_blank">billet précédent</a>, je pensais que pour utiliser <a href="https://github.com/jpadilla/django-dotenv" target="_blank">django-dotenv</a>, il fallait importer la fonction parse_dotenv pour l&rsquo;utiliser en précisant la clé désirée, et bien padutou. En fait, cette lib ajoute les variables d&rsquo;environnement, pour qu&rsquo;elles soient disponibles via votre système. Donc quand on a configuré le package, il faut simplement utiliser ce que Python propose pour les lire : </p>
<pre class="brush: python; title: code; notranslate">
os.getenv('DBCONNECTION')
</pre>
<h3>La homepage</h3>
<p>Il faut donc créer une app pour la home. Donc :</p>
<pre class="brush: bash; title: code; notranslate">
python manage.py startapp home
</pre>
<p>Et on va aller modifier le fichier url comme ceci pour faire pointer / vers la méthode index de la vue home : </p>
<pre class="brush: python; title: code; notranslate">
from django.conf.urls import url
from django.contrib import admin
from home import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.index)
]
</pre>
<p>Ensuite on va créer un layout de base à étendre, et insérer le hello world dans le template qui va afficher la page d&rsquo;accueil. En tout cas, je commence à bien saisir la structure, et ce système de template, même si à première vue est redondant, est en fait une très bonne solution pour la surcharge, et avec ce que j&rsquo;ai en tête, ça peut être très utile.</p>
<p>La prochaine fois, on verra comment préparer la stack front-end, avec webpack et npm. En attendant, si vous voulez le détail, <a href="https://github.com/rikless/helpmepyz/commit/78540e61081b5395b9402fb5c9884966d636511e" target="_blank">c&rsquo;est par ici</a> .</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/setup-de-django-avec-apache/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">356</post-id>	</item>
		<item>
		<title>Comment bloquer un site Internet</title>
		<link>https://metrogeek.fr/comment-bloquer-site-internet/</link>
				<comments>https://metrogeek.fr/comment-bloquer-site-internet/#respond</comments>
				<pubDate>Wed, 23 Nov 2016 13:35:47 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[gnu]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=343</guid>
				<description><![CDATA[Dans le cadre d’un petit réseau privé ou même d’une unique machine, empêcher l’accès à certains sites pour échapper à ces sites, par soucis de confidentialité, ou encore tout simplement pour bloquer des publicités, peut devenir utile. Je vous présente [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>Dans le cadre d’un petit réseau privé ou même d’une unique machine, empêcher l’accès à certains sites pour échapper à ces sites, par soucis de confidentialité, ou encore tout simplement pour bloquer des publicités, peut devenir utile.</p>
<p>Je vous présente aujourd’hui deux techniques pour bloquer l’accès à certains sites. On va même s&rsquo;amuser à bloquer google.fr parce qu&rsquo;on est des crypto cyberpunks anarcho-communisme complètement dingues.</p>
<h2>Première technique : le proxy</h2>
<p>Un serveur proxy est un serveur (matériel ou logiciel) s’intercalant entre deux machines. En l’occurrence, nous allons installer l’un des plus célèbres, <a href="http://www.squid-cache.org/">Squid</a>, sur une <a href="http://www.debian.org/">Debian</a>. L’installation est on ne peut plus simple :</p>
<pre class="brush: bash; title: code; notranslate">apt-get install squid</pre>
<p>On édite le fichier de configuration :</p>
<pre class="brush: bash; title: code; notranslate">nano /etc/squid/squid.conf</pre>
<p>Vous devriez avoir trois lignes relatives à la déclaration du réseau local :</p>
<pre class="brush: bash; title: code; notranslate">acl localnet src 10.0.0.0/8 # RFC1918 possible internal network
acl localnet src 172.16.0.0/12 # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network</pre>
<p>Décommentez celle(s) qui s’applique(nt) à votre configuration. En dessous, on rajoute les domaines à bloquer :</p>
<pre class="brush: bash; title: code; notranslate">acl blocked_domains dst google.fr
acl blocked_domains dst adsense.com
[...]</pre>
<p>Puis, plus loin, juste avant la ligne :</p>
<pre class="brush: bash; title: code; notranslate">http_access deny all</pre>
<p>Rajoutez :</p>
<pre class="brush: bash; title: code; notranslate">http_access allow localnet
http_access deny blocked_domains</pre>
<p>Il suffit maintenant de configurer votre navigateur pour qu’il utilise le proxy ainsi installé (par défaut, sur le port 3128).</p>
<p>Pour aller plus loin, on pourrait en faire un proxy transparent : si la machine sur laquelle vous avez installé Squid est aussi la machine qui partage votre connexion Internet, mettre en place une règle iptables pour intercepter tout paquet qui cherche à atteindre le port 80 en sortie, et le rediriger vers l’hôte local, port 3128 :</p>
<pre class="brush: bash; title: code; notranslate">iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128</pre>
<p>On pourrait également déplacer la liste des domaines à bloquer dans un fichier distinct. Pour ce faire, au lieu des directives «&nbsp;<em>acl blocked_domains [&#8230;]</em>«&nbsp;, on créé celle-ci :</p>
<pre class="brush: bash; title: code; notranslate">acl blocked_domains dst &quot;/etc/squid/blocked_domains&quot;</pre>
<p>Puis on créé le fichier spécifié, et on le remplit avec les domaines souhaités (un par ligne).</p>
<p>Une fois les modifications effectuées, n’oubliez pas de relancer Squid :</p>
<pre class="brush: bash; title: code; notranslate">/etc/init.d/squid restart</pre>
<h2>Deuxième technique : invalidation DNS</h2>
<p><a href="https://metrogeek.fr/wp-content/uploads/2016/11/sites-blocked.png"><img data-attachment-id="344" data-permalink="https://metrogeek.fr/comment-bloquer-site-internet/sites-blocked/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/11/sites-blocked.png" data-orig-size="300,200" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sites-blocked" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/11/sites-blocked-300x200.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/11/sites-blocked.png" class="aligncenter size-full wp-image-344" src="https://metrogeek.fr/wp-content/uploads/2016/11/sites-blocked.png" alt="sites-blocked" width="300" height="200" /></a></p>
<p>La deuxième technique fait appel à un serveur DNS présent sur votre réseau. Pour l’occasion, j’explique la technique avec <a href="http://www.isc.org/software/bind">bind</a>, mais le principe est valable quel que soit votre serveur DNS. Commencez par éditer le fichier de configuration principal de bind :</p>
<pre class="brush: bash; title: code; notranslate">nano /etc/bind/named.conf</pre>
<p>Rajoutez-y la ligne suivante :</p>
<pre class="brush: bash; title: code; notranslate">include &quot;/etc/bind/named.conf.blocked&quot;;</pre>
<p>Créez le fichier <em>named.conf.blocked</em>, et mettez-y les informations suivantes :</p>
<pre class="brush: bash; title: code; notranslate">zone &quot;google.fr&quot; { type master; file &quot;dummy-block&quot;; };</pre>
<p>Cette ligne bloque tout trafic vers google.fr. Si ce n’est pas ce que vous voulez, pensez à changer cette ligne pour mettre le domaine à bloquer. Cette technique a ceci de contraignant que le fichier <em>named.conf.blocked</em> doit contenir une ligne de ce type par domaine à bloquer, ce qui peut être pénible à maintenir, d’autant qu’il faut relancer bind après chaque modification. Nous verrons plus loin comment se faciliter un peu la vie. En attendant, il faut encore créer le fichier <em>/etc/bind/dummy-block</em> :</p>
<pre class="brush: bash; title: code; notranslate">$TTL 24h

@ IN SOA yourdomain.com. hostmaster.yourdomain.com. (
2003052800 86400 300 604800 3600 )

@ IN NS yourdomain.com.
@ IN A 127.0.0.1
* IN A 127.0.0.1</pre>
<p>Pensez juste à changer <em>yourdomain.com</em> et le faire pointer sur votre propre machine par exemple, puis redémarrez bind :</p>
<pre class="brush: bash; title: code; notranslate">/etc/init.d/bind9 restart</pre>
<p>Cette technique, encore une fois, est contraignante si vous souhaitez bloquer un nombre conséquent de sites. Pour une dizaine de domaines, c’est gérable, mais quand on cherche à en bloquer une centaine (par exemple, tous les serveurs de publicités) c’est une autre paire de manche. Je vais donc vous livrer un petit script qui va bosser pour vous.</p>
<p>En ce qui concerne la configuration de bind, si vous avez créé le fichier <em>named.conf.blocked</em>, supprimez-le. Créez un fichier <em>blocked_domains</em>, et comme pour Squid, remplissez-le avec les domaines à bloquer, un par ligne. Créez ensuite un fichier nommé par exemple <em>build_conf</em>, et rendez-le exécutable avant de l’éditer :</p>
<pre class="brush: bash; title: code; notranslate">touch build_conf &amp;&amp; chmod +x build_conf &amp;&amp; nano build_conf</pre>
<p>Mettez-y le code suivant :</p>
<pre class="brush: bash; title: code; notranslate">#!/bin/bash

# Script permettant de générer un fichier de configuration bind
# visant à bloquer les domaines contenus dans un fichier à part
# Auteur : Metrogeek `francois@metrogeek.fr`
# Licence : GNU/GPL dans sa dernière version

# Configuration générale

# Fichier contenant la liste des domaines
domains_file=&quot;blocked_domains&quot;

# Fichier à générer
blocked_conf=&quot;named.conf.blocked&quot;

# Fichier de définition du domaine
dummy_block=&quot;dummy-block&quot;

# Maintenant on peut bosser

# On formate un peu la liste des domaines

echo &quot;Suppression des lignes vides et espaces superflus...&quot;
sed '/^$/d' ` &quot;${domains_file}&quot; ` &quot;${domains_file}_temp&quot;
sed '/./!d' ` &quot;${domains_file}_temp&quot; ` &quot;${domains_file}_temp2&quot;
sed 's/^[ \t]*//' ` &quot;${domains_file}_temp2&quot; ` &quot;${domains_file}&quot;

rm &quot;${domains_file}_temp&quot; &quot;${domains_file}_temp2&quot;

echo &quot;Suppression des doublons...&quot;
sort -u &quot;${domains_file}&quot; ` &quot;${domains_file}_temp&quot;
mv &quot;${domains_file}_temp&quot; &quot;${domains_file}&quot;

echo &quot;Génération du fichier de configuration...&quot;
rm &quot;${blocked_conf}&quot;
touch &quot;${blocked_conf}&quot;

while read line
do
echo &quot;zone \&quot;${line}\&quot; { type master; file \&quot;${dummy_block}\&quot;; };&quot; `` &quot;${blocked_conf}&quot;
done ` &quot;${domains_file}&quot;

echo &quot;Terminé, redémarrage de bind&quot;
/etc/init.d/bind9 restart</pre>
<p>Chaque fois que vous ajouterez un ou plusieurs domaines au fichier <em>blocked_domains</em>, il suffira de lancer ce script. &nbsp;Cela sortirait du cadre de cet article, mais on pourrait aussi faire appel à inotify par exemple, pour relancer automatiquement ce script dès que le fichier <em>blocked_domains</em> est modifié.</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/comment-bloquer-site-internet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">343</post-id>	</item>
		<item>
		<title>Point d&#8217;étape avec Python</title>
		<link>https://metrogeek.fr/point-etape-python/</link>
				<comments>https://metrogeek.fr/point-etape-python/#comments</comments>
				<pubDate>Fri, 18 Nov 2016 13:58:30 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=337</guid>
				<description><![CDATA[T&#8217;en es où ? Ca fait maintenant quelques mois que je mets régulièrement le nez dans Python (plus dans Django, il faut bien le dire). J&#8217;ai bien les notions de base, mais il y a un point qui reste un [&#8230;]]]></description>
								<content:encoded><![CDATA[<h2>T&rsquo;en es où ?</h2>
<p>Ca fait maintenant quelques mois que je mets régulièrement le nez dans Python (plus dans Django, il faut bien le dire). J&rsquo;ai bien les notions de base, mais il y a un point qui reste un peu abstrait, c&rsquo;est la gestion des app.</p>
<p>La semaine dernière, j&rsquo;ai tenté d&rsquo;approfondir cet aspect, mais rien de bien concluant. Donc concrètement, au lieu d&rsquo;attendre, je vais commencer à coder, on verra ce que ça donne, et au pire, je casserai ce qui n&rsquo;est pas fait correctement, pour le refaire correctement quand j&rsquo;aurais compris !</p>
<p>Il est temps d&rsquo;y aller, donc go.</p>
<p><a href="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png"><img data-attachment-id="184" data-permalink="https://metrogeek.fr/django-base-de-donnees/challenge/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" data-orig-size="800,300" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge-300x113.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" class="aligncenter size-full wp-image-184" src="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png" alt="" width="800" height="300" srcset="https://metrogeek.fr/wp-content/uploads/2016/07/challenge.png 800w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-300x113.png 300w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-768x288.png 768w, https://metrogeek.fr/wp-content/uploads/2016/07/challenge-200x75.png 200w" sizes="(max-width: 800px) 100vw, 800px" /></a></p>
<h2>Construire le projet</h2>
<pre class="brush: bash; title: code; notranslate">

mkdir helpmepyz &amp;&amp; cd helpmepiz

virtualenv env

source env/bin/activate

pip install django

django-admin.py startproject helpmepyz

</pre>
<p>Ensuite, on va créer le gitignore :</p>
<pre class="brush: bash; title: code; notranslate">

env
*.DS_Store
*.pyc
__pycache__

</pre>
<p>Et ensuite il faut initialiser git :</p>
<pre class="brush: bash; title: code; notranslate">

git init &amp;&amp; git add . &amp;&amp; git commit -m &quot;$(curl -s http://whatthecommit.com/index.txt )&quot;

git remote add origin git@github.com:rikless/helpmepyz.git

</pre>
<p>On va partir sur une base de donnée Mysql. Je n&rsquo;ai pas encore testé le nouveau support de JSON ça sera l&rsquo;occasion :</p>
<p><del>pip install MySQL-python</del></p>
<p>En fait non, ce paquet ne supporte pas python 3.5, donc :</p>
<pre class="brush: bash; title: code; notranslate">

pip install mysqlclient

</pre>
<p>On va tout de suite installer un outil qui va permettre de gérer les variables d&rsquo;environnement. <a href="https://github.com/jpadilla/django-dotenv" target="_blank">django-env</a> a l&rsquo;air de faire le boulot.</p>
<pre class="brush: bash; title: code; notranslate">

pip install django-dotenv

</pre>
<p>Vu qu&rsquo;on a déjà 2 dépendances, on va tout de suite utiliser cette commande :</p>
<pre class="brush: bash; title: code; notranslate">

pip freeze &gt; requirements.txt

</pre>
<p>Ca permet de générer la liste de vos dépendances, un peu comme le <em>composer.json</em> pour ceux qui ont l&rsquo;habitude de PHP.</p>
<p>On va pouvoir créer les premières apps, et tester la connexion à la base.</p>
<p>La liste des modifs pour cette dernière partie <a href="https://github.com/rikless/helpmepyz/commit/fa357003f66262e51f144ab5a2771764ea16428a" target="_blank">ici</a></p>
<p>&nbsp;</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/point-etape-python/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">337</post-id>	</item>
		<item>
		<title>Double Authentification Laravel : Google Authenticator</title>
		<link>https://metrogeek.fr/double-authentification-laravel-google-authenticator/</link>
				<comments>https://metrogeek.fr/double-authentification-laravel-google-authenticator/#respond</comments>
				<pubDate>Mon, 07 Nov 2016 23:32:16 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[laravel]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=319</guid>
				<description><![CDATA[La double authentification se répand assez vite, et c’est une bonne chose. La confirmation par SMS est une très bonne chose, mais cette méthode a montrée ses faiblesses. Dans ce tutoriel, on va voir comment configurer une double authentification sur [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>La double authentification se répand assez vite, et c’est une bonne chose. La confirmation par SMS est une très bonne chose, mais cette méthode a montrée ses faiblesses.<br />
Dans ce tutoriel, on va voir comment configurer une double authentification sur une application Laravel, via Google Authenticator&nbsp;!</p>
<h2>Initialiser le projet</h2>
<p>A grands coupe de</p>
<pre class="brush: bash; title: code; notranslate">

composer create-project --prefer-dist laravel/laravel secure-me

</pre>
<p>On se déplace dans le dossier du projet, et on va demander à composer d’installer 2 dépendances&nbsp;: Une lib qui gère la double authentification avec Laravel, et une autre qui va servir à encoder en Base32.</p>
<pre class="brush: bash; title: code; notranslate">

composer require pragmarx/google2fa
composer require paragonie/constant_time_encoding

</pre>
<p>google2fa nécessite d’enregistrer le service provider, et on va ajouter la facade pour plus de facilité.<br />
Donc on ouvre config/app.php et on ajoute ces lignes dans les bonnes sections&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">
//côté service provider
PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class
//côté Facade
'Google2FA' =&gt; PragmaRX\Google2FA\Vendor\Laravel\Facade::class

</pre>
<p>Et enfin, on va utiliser cet outil démentiel de Laravel, qui vous permet de scafolder une auth en moins d’une seconde (accrochez-vous, ça va trembler) :</p>
<pre class="brush: bash; title: code; notranslate">
php artisan make:auth
</pre>
<h2>Structurer la base de donnée</h2>
<p>On va aller modifier la méthode up() du fichier de migration de la table users, avant de la lancer, comme ceci&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">
Schema::create('users', function (Blueprint $table) {
    $table-&gt;increments('id');
    $table-&gt;string('name');
    $table-&gt;string('email')-&gt;unique();
    $table-&gt;string('password');
    $table-&gt;rememberToken();
    $table-&gt;string('google2fa_secret')-&gt;nullable();
    $table-&gt;timestamps();
});
</pre>
<p>Maintenant, il faut modifier le modèle <em>App\User</em> pour ajouter ce champ <em>google2fa_secret</em> à la propriété fillable, pour pouvoir modifier le champ, et en <em>hidden</em>, pour que sa valeur ne soit jamais affichée quand vous retournez l’objet complet, qui sera casté en JSON (on ne sait jamais).</p>
<h2>Les controllers</h2>
<p>Et hop, dans la console&nbsp;:</p>
<pre class="brush: bash; title: code; notranslate">
php artisan make:controller GoogleAuthController
</pre>
<p>Et on va tout de suite aller y coller ce code :</p>
<pre class="brush: php; title: code; notranslate">&lt;?php

namespace App\Http\Controllers;

use App\Http\Requests\ActivateSecretValidation;
use Illuminate\Http\Request;
use Base32\Base32;

/**
 * Class GoogleAuthController
 * @package App\Http\Controllers
 */
class GoogleAuthController extends Controller
{

    protected $redirectTo = '/';


    /**
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function enableTwoFactor(Request $request)
    {
        //Generate a secret key in Base32 format
        $secret = strtoupper(Base32::encode(random_bytes(10)));
        $user = auth()-&gt;user();

        session(['google2fa_secret' =&gt; \Crypt::encrypt($secret), '2fa:user:id' =&gt; auth()-&gt;user()-&gt;id]);

        //generate image for QR barcode
        $QRCode = \Google2FA::getQRCodeGoogleUrl(
            config('app.name'),
            $user-&gt;email,
            $secret,
            200
        );

        return view('2fa/enable', ['image' =&gt; $QRCode,
            'secret' =&gt; $secret]);
    }


    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function disableTwoFactor()
    {
        $user = auth()-&gt;user();

        $user-&gt;google2fa_secret = null;
        $user-&gt;save();

        return view('2fa/disable');
    }

    /**
     * @param ActivateSecretValidation $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function activateTwoFactor(ActivateSecretValidation $request)
    {

        auth()-&gt;user()-&gt;google2fa_secret = session('google2fa_secret');
        auth()-&gt;user()-&gt;save();
        session()-&gt;forget(['google2fa_secret', '2fa:user:id']);

        return redirect()-&gt;intended($this-&gt;redirectTo)-&gt;with(['success' =&gt; 'Your account is secured !']);
    }

}</pre>
<p>3&nbsp;méthodes&nbsp;: une pour la demande d’activation, qui va générer le QRcode et demander le code de confirmation, une&nbsp;autre pour la demande de désactivation, et enfin une dernière qui va servir à envoyer les données de confirmation, pour valider l&rsquo;activation de la double authentification. Avec cette 3e méthode, on n&rsquo;activera la double authentification QUE si l&rsquo;user a bien confirmé le code.</p>
<p>On va pouvoir maintenant utiliser la méthode <em>authenticated()</em> qui est un petit <em>hook</em> qu’on va surcharger, puisque la méthode de base est simplement vide. Donc on ouvre <em>LoginContoller</em> et on ajoute cette méthode, qui va surcharger celle du Trait&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">protected function authenticated(Request $request, Authenticatable $user)
{
    if (!is_null($user-&gt;google2fa_secret)) {
        \Auth::logout();

        $request-&gt;session()-&gt;put('2fa:user:id', $user-&gt;id);

        return redirect('2fa/validate');
    }

    return redirect()-&gt;intended($this-&gt;redirectTo);
}</pre>
<p>Donc si l’user a activé la double authentification, il faut déconnecter l’utilisateur, et lui ajouter son user id en session. Quand c’est fait, on peut le diriger vers une page dans laquelle il doit saisir les codes de validation.</p>
<p>Si c’est désactivé, on ne le déconnecte pas et on l’emmène là où il voulait aller.</p>
<p><a href="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth.png"><img data-attachment-id="324" data-permalink="https://metrogeek.fr/double-authentification-laravel-google-authenticator/activate-double-auth/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth.png" data-orig-size="1017,531" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="activate-double-auth" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth-300x157.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth.png" class="aligncenter size-full wp-image-324" src="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth.png" alt="activate-double-auth" width="1017" height="531" srcset="https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth.png 1017w, https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth-300x157.png 300w, https://metrogeek.fr/wp-content/uploads/2016/11/activate-double-auth-768x401.png 768w" sizes="(max-width: 1017px) 100vw, 1017px" /></a></p>
<p>Maintenant, on ajoute la méthode <em>validate2fa()</em> dans <em>LoginController</em>, pour s’assurer que la valeur existe en session, et renvoyer l’user sur la page login si ce n’est pas le cas&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">public function validate2fa()
{
    if (session('2fa:user:id')) {
        return view('2fa/validate');
    }

    return redirect('login');
}</pre>
<p>Puis une méthode qui va servir à récupérer les données postées pour valider la double authentification :</p>
<pre class="brush: php; title: code; notranslate">public function postValidate2fa(SecretRequestValidation $request)
{
    $userId = $request-&gt;session()-&gt;pull('2fa:user:id');

    //login and redirect user
    \Auth::loginUsingId($userId);

    return redirect()-&gt;intended($this-&gt;redirectTo);
}</pre>
<p>Et on va donc créer l&rsquo;objet request correpondant :</p>
<pre class="brush: bash; title: code; notranslate">
php artisan make:request SecretRequestValidation
</pre>
<p>Et on va coller ceci dedans :</p>
<pre class="brush: php; title: code; notranslate">&lt;?php

namespace App\Http\Requests;

use App\User;
use Illuminate\Foundation\Http\FormRequest;

/**
 * Class SecretRequestValidation
 * @package App\Http\Requests
 */
class SecretRequestValidation extends FormRequest
{

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        try {
            User::findOrFail(
                session('2fa:user:id')
            );
        } catch (\Exception $e) {
            return false;
        }

        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'totp' =&gt; 'bail|required|digits:6|token_is_ok',
        ];
    }
}</pre>
<p>Oui on va créer une (2 en fait) règle de validation supplémentaire, en créant une nouvelle classe dans app/Http/Requests&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">&lt;?php

namespace App\Http\Requests;

use App\User;
use Illuminate\Validation\Validator;

/**
 * Class CustomValidator
 * @package App\Http\Requests
 */
class CustomValidator extends Validator
{
    /**
     * @param $attribute
     * @param $value
     * @param $parameters
     * @return bool
     */
    public function validateTokenIsOk($attribute, $value, $parameters)
    {
        try {
            $user = User::findOrFail(session('2fa:user:id'));

        } catch (\Exception $exc) {
            return false;
        }

        $secret = \Crypt::decrypt($user-&gt;google2fa_secret);

        return \Google2FA::verifyKey($secret, $value);
    }

    /**
     * @param $attribute
     * @param $value
     * @param $parameters
     * @return mixed
     */
    public function validateTokenIsValid($attribute, $value, $parameters)
    {
        $secret = \Crypt::decrypt(session('google2fa_secret'));

        return \Google2FA::verifyKey($secret, $value);
    }
}</pre>
<p>Il faut aussi modifier AppServiceProvider pour ajouter ces&nbsp;règles au boot. Donc on ajoute ceci à la méthode boot()&nbsp;:</p>
<pre class="brush: php; title: code; notranslate">public function boot()
{
    $this-&gt;app['validator']-&gt;resolver(function($translator, $data, $rules, $messages) {
        return new CustomValidator($translator, $data, $rules, $messages);
    });
}</pre>
<p>Pensez à ajouter le use.</p>
<p>On peut maintenant valider la dernière requête (qu&rsquo;on va d&rsquo;abord créer)&nbsp;:</p>
<pre class="brush: bash; title: code; notranslate">

php artisan make:request ActivateSecretValidation

</pre>
<p>Et voici son contenu :</p>
<pre class="brush: php; title: code; notranslate">&lt;?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

/**
 * Class ActivateSecretValidation
 * @package App\Http\Requests
 */
class ActivateSecretValidation extends FormRequest
{

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
       return \Auth::check();
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'totp' =&gt; 'bail|required|digits:6|token_is_valid',
        ];
    }
}</pre>
<h2>Les routes</h2>
<p>Les controllers sont prêts. Maintenant, il faut que les routes soient disponibles. Pour rappel, il faut une route pour activer la double authentification, une pour la désactiver. Une autre pour afficher un formulaire dans lequel l’user va pouvoir taper le code disponible dans l’application Google Autenticator, et enfin, la dernière url sur laquelle il va envoyer ce formulaire.</p>
<pre class="brush: php; title: code; notranslate">

Route::get('/2fa/enable', 'GoogleAuthController@enableTwoFactor');
Route::get('/2fa/disable', 'GoogleAuthController@disableTwoFactor');
Route::post('/2fa/activate', 'GoogleAuthController@activateTwoFactor');

Route::get('/2fa/validate', 'Auth\LoginController@validate2fa');
Route::post('/2fa/validate', ['middleware' =&gt; 'throttle:5', 'uses' =&gt; 'Auth\LoginController@postValidate2fa']);

</pre>
<h2>Les vues</h2>
<p>3 vues sont à prévoir :</p>
<ul>
<li>1 pour l&rsquo;activation</li>
<li>1 pour la désactivation</li>
<li>1 pour la validation après le login</li>
</ul>
<p>On ne traîne pas, voici les 3 fichiers blade qui se passent d&rsquo;explication.</p>
<p>disable.blade.php :</p>
<pre class="brush: php; title: code; notranslate">@extends('layouts.app')

@section('content')
    &lt;div class=&quot;container&quot;&gt;
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col-md-10 col-md-offset-1&quot;&gt;
               &lt;p&gt;
                   Double authentification désactivée. Mauvaise idée.
               &lt;/p&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
@endsection</pre>
<p>enable.blade.php</p>
<pre class="brush: php; title: code; notranslate">@extends('layouts.app')

@section('content')
    &lt;div class=&quot;container&quot;&gt;
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col-md-10 col-md-offset-1&quot;&gt;
                &lt;div class=&quot;panel panel-default&quot;&gt;
                    &lt;div class=&quot;panel-heading&quot;&gt;Secret Key&lt;/div&gt;

                    &lt;div class=&quot;panel-body&quot;&gt;
                        Ouvrez Google Authenticator et scannez le QR code suivant :
                        &lt;br /&gt;
                        &lt;img alt=&quot;Image of QR barcode&quot; src=&quot;{{ $image }}&quot; /&gt;

                        &lt;br /&gt;
                        Si vous avez un souci avec le QR code, vous pouvez taper ce code: &lt;code&gt;{{ $secret }}&lt;/code&gt;
                        &lt;br /&gt;&lt;br /&gt;
                    &lt;/div&gt;

                    &lt;form class=&quot;form-horizontal&quot; role=&quot;form&quot; method=&quot;POST&quot; action=&quot;/2fa/activate&quot;&gt;
                        {!! csrf_field() !!}

                        &lt;div class=&quot;form-group{{ $errors-&gt;has('totp') ? ' has-error' : '' }}&quot;&gt;
                            &lt;label class=&quot;col-md-4 control-label&quot;&gt;Clé de sécurité&lt;/label&gt;

                            &lt;div class=&quot;col-md-6&quot;&gt;
                                &lt;input type=&quot;number&quot; class=&quot;form-control&quot; name=&quot;totp&quot;&gt;

                                @if ($errors-&gt;has('totp'))
                                    &lt;span class=&quot;help-block&quot;&gt;
                                            &lt;strong&gt;{{ $errors-&gt;first('totp') }}&lt;/strong&gt;
                                        &lt;/span&gt;
                                @endif
                            &lt;/div&gt;
                        &lt;/div&gt;

                        &lt;div class=&quot;form-group&quot;&gt;
                            &lt;div class=&quot;col-md-6 col-md-offset-4&quot;&gt;
                                &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;
                                    &lt;i class=&quot;fa fa-btn fa-mobile&quot;&gt;&lt;/i&gt;Valider
                                &lt;/button&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/form&gt;

                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
@endsection</pre>
<p>et validate.blade.php</p>
<pre class="brush: php; title: code; notranslate">@extends('layouts.app')

@section('content')
    &lt;div class=&quot;container&quot;&gt;
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col-md-8 col-md-offset-2&quot;&gt;
                &lt;div class=&quot;panel panel-default&quot;&gt;
                    &lt;div class=&quot;panel-heading&quot;&gt;Double Authentification&lt;/div&gt;

                    &lt;div class=&quot;panel-body&quot;&gt;
                        &lt;form class=&quot;form-horizontal&quot; role=&quot;form&quot; method=&quot;POST&quot; action=&quot;/2fa/validate&quot;&gt;
                            {!! csrf_field() !!}

                            &lt;div class=&quot;form-group{{ $errors-&gt;has('totp') ? ' has-error' : '' }}&quot;&gt;
                                &lt;label class=&quot;col-md-4 control-label&quot;&gt;Clé de sécurité&lt;/label&gt;

                                &lt;div class=&quot;col-md-6&quot;&gt;
                                    &lt;input type=&quot;number&quot; class=&quot;form-control&quot; name=&quot;totp&quot;&gt;

                                    @if ($errors-&gt;has('totp'))
                                        &lt;span class=&quot;help-block&quot;&gt;
                                            &lt;strong&gt;{{ $errors-&gt;first('totp') }}&lt;/strong&gt;
                                        &lt;/span&gt;
                                    @endif
                                &lt;/div&gt;
                            &lt;/div&gt;

                            &lt;div class=&quot;form-group&quot;&gt;
                                &lt;div class=&quot;col-md-6 col-md-offset-4&quot;&gt;
                                    &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;
                                        &lt;i class=&quot;fa fa-btn fa-mobile&quot;&gt;&lt;/i&gt;Valider
                                    &lt;/button&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                        &lt;/form&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
@endsection
</pre>
<p>Et voilà, c&rsquo;est prêt !<br />
Les sources de ce tuto sont dispo sur <a href="https://github.com/rikless/google-auth-laravel-tutorial" target="_blank">Github</a>.</p>
<p>Crédits photo : Raphael Schaller raphaelphoto.ch</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/double-authentification-laravel-google-authenticator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">319</post-id>	</item>
		<item>
		<title>Devenir CTO (Directeur technique)</title>
		<link>https://metrogeek.fr/devenir-cto-directeur-technique/</link>
				<comments>https://metrogeek.fr/devenir-cto-directeur-technique/#respond</comments>
				<pubDate>Fri, 28 Oct 2016 10:00:58 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[dev]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=297</guid>
				<description><![CDATA[Il y a quelques semaines, j&#8217;ai lu ce billet sur lequel je suis tombé, depuis touiteur. Et vu que je le trouve très pertinent, et que le texte n&#8217;est disponible qu&#8217;en anglais, je me suis dis que ça pouvait être cool [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>Il y a quelques semaines, j&rsquo;ai lu <a href="https://juokaz.com/blog/becoming-a-cto" target="_blank">ce billet</a> sur lequel je suis tombé, depuis touiteur. Et vu que je le trouve très pertinent, et que le texte n&rsquo;est disponible qu&rsquo;en anglais, je me suis dis que ça pouvait être cool de proposer une traduction.</p>
<p>Voici donc.</p>
<hr />
<p>Si vous vous êtes déjà retrouvé à écrire un billet de blog qui explique pourquoi PHP c&rsquo;est naze, alors <strong>vous n&rsquo;êtes pas prêt</strong>.</p>
<p>Devenir Directeur Technique (CTO) ne ne veut pas dire que vous êtes le meilleur hacker de l&rsquo;équipe. Aujourd&rsquo;hui, écrire du code est probablement la dernière chose que vous seriez en train de faire. Vous êtes plutôt une personne qui est capable de communiquer la technologie aux autres, les guide dans l&rsquo;exécution du projet. C&rsquo;est en quelque sorte quelqu&rsquo;un qui protège les autres des interférences extérieures, et quand c&rsquo;est nécessaire, prend la <strong>responsabilité</strong> des erreurs.</p>
<p>C&rsquo;est facile de devenir Directeur Technique accidentellement, en étant recruté par une petite société qui n&rsquo;a aucun autre développeur, comme vous pouvez le voir dans beaucoup de startup. Mais bien que le titre dise Directeur Technique, c&rsquo;est probablement un acronyme un peu chic pour dire : Développeur Surchargé de Travail.</p>
<p>Je déteste les environnements dans lesquels l&rsquo;équipe technique ne fait qu&rsquo;implémenter ce qui a été envisagé par les autres. Ca pourrait aussi bien être une équipe en outsourcing puisqu&rsquo;ils sont complètement séparés du processus de décision. Comme l&rsquo;écrit Camille Fournier dans ‘<a href="http://whilefalse.blogspot.fr/2015/02/cto.html">On the role of CTO</a>’, “Le directeur technique doit protéger l&rsquo;équipe IT de devenir un outil d&rsquo;execution des idées, sans tendre à ses propres besoins et ses propres idées”.</p>
<p>Si une société a besoin d&rsquo;un directeur technique, alors cette personne définie la vision de l&rsquo;impact à long terme sur la technologie. De plus en plus d&rsquo;entreprises aujourd&rsquo;hui n&rsquo;utilisent pas la technologie, mais sont définit par elle. Tout est construit avec la technologie, du commerce de détails, à l&rsquo;application mobile, et tous y tirent un grand bénéfice quand quelqu&rsquo;un ce qu&rsquo;il faut pour que la technologie fasse encore mieux. C&rsquo;est le combat qu&rsquo;un Directeur Technique ne peut ignorer. L&rsquo;équipe technique doit pouvoir se positionner en maître d&rsquo;oeuvre.</p>
<p>Je suis déjà allé dans quelques réunions avec d&rsquo;autre Directeurs Techniques, et la majorité des discussions portent sur les manières de faire en sorte le reste de l&rsquo;entreprise respecte les processus de développement. Par exemple, vendre et faire accepter le test unitaire. Non, non non ! Pour ma part, je ne vais pas essayer de vous vendre quoique ce soit. Je vais dire : Voici la direction dans laquelle nous allons, et voilà comment on va faire. En bref, le quand le CTO donne une direction, ça doit se passer comme ça. Si un directeur technique n&rsquo;a pas ce petit pouvoir pour les décisions techniques, alors il n&rsquo;est pas CTO, mais plus ingénieur en chef dans un costume.  Le costume étant optionnel.</p>
<p>Le CTO est un emploi stratégique dans l&rsquo;entreprise , qui définit l&rsquo;orientation technique à l’intérieure de l&rsquo;entreprise. Ce n&rsquo;est pas le bon job si vous détestez les meetings, si vous détestez traiter avec ceux qui ne sont pas techniques, et pensez que les manager sont assis toute la journée, et ne font rien. Chaque meeting est une discussion sur l&rsquo;orientation que l&rsquo;entreprise va prendre, et comment la technologie peut aider, ou parfois, comment la technologie peut créer de nouvelles opportunités pour grossir.  Tout ceci doit être expliqué simplement, pour être compréhensible par tout le monde.</p>
<p>Donc, il est essentiel de comprendre les besoins de l&rsquo;entreprise et des clients. D&rsquo;après mon expérience, beaucoup de gens techniques aiment se mettre à l&rsquo;écart de tout ce qui touche au business. Pourtant, c&rsquo;est la première chose à savoir en tant que CTO. <strong>Aucune décision technique ne devrait se prendre dans une préoccupation  purement logicielle ou matérielles</strong>. La plupart du temps, le CTO devrait être en phase avec les gestionnaires de produits de sorte que la stratégie du produit soit compatible avec les opérations de développement.</p>
<p>En fin de compte, le CTO créé un environnement qui permet à l&rsquo;équipe de réaliser de grandes choses. Aujourd&rsquo;hui, une grande partie du problème est l&#8217;embauche. Tout le monde est à la recherche de développeurs, mais ils sont peu nombreux, donc l&rsquo;environnement doit être aussi accueillant que possible. C&rsquo;est quelque chose que le CTO devrait savoir faire, car il a été une fois l&rsquo;un d&rsquo;eux. Si l&rsquo;équipe veut faire du TDD, ou coder en binôme, ou s&rsquo;occuper des serveurs &#8211; ça doit être accepter par le CTO. C&rsquo;est aux CTO de considérer le plus grand impact de ces changements.</p>
<p>Réfléchir sur l&rsquo;impact financier des opérations technologiques est important. Une startup peut se permettre de se jeter sur toutes les dernières technos, mais une plus grande entreprise ne peut pas se le permettre. Tout doit être pesé sur une base de retour sur investissement, en demandant combien de valeur il faut livrer au client. Donc, dans la plupart des cas, il faut équilibrer l&rsquo;évolution et les mises à jour des infrastructures existantes, tout en ne tombant pas dans une réécriture trop lourde du code. Trouver ce qui donne 80% de rendement avec seulement 20% du d&rsquo;investissement, selon la règle des 80-20, y contribue en grande partie.</p>
<p>J&rsquo;ai fait des entretiens avec des futurs CTO qui disaient, «Pourquoi êtes-vous coincé avec cette vielle version, pourquoi ne pas passez à React.js? » Désolé de vous faire redescendre, mais ce n&rsquo;est pas une bonne idée. Parfois, des applications deviennent coûteuses à gérer, mais les réécrire offrent presque toujours une valeur nulle au client. Il faut équilibrer les efforts de développement. Construire une équipe de personnes qui veulent seulement utiliser les technologies qui viennent de sortir n&rsquo;est pas durable.</p>
<p>Il construit un écosystème  pour mettre en œuvre les choses que vous trouvez les plus importantes. Par exemple, je pense que la fiabilité et la sécurité sont les deux des caractéristiques les plus importantes de toute application. Ainsi, tout changement dans les objectifs de l&rsquo;entreprise sont pesés en tenant compte de ces 2 aspects. La confidentialité aussi importante, mais c&rsquo;est un sujet qui est encore difficile à appréhender pour les personnes non-techniques. Pourtant, elle limite parfois ce qu&rsquo;une entreprise peut faire, tout simplement parce que les choses pourraient tomber en dehors du respect de la vie privée. Une partie de mon travail consiste à appréhender ces aspects et à s&rsquo;assurer que l&rsquo;équipe l&rsquo;execute correctement.</p>
<p>Alors que je ne fais que la technologie. Je pense que la technologie devrait être invisible pour l&rsquo;utilisateur. Alors, quand on débat sur le fait que oui ou non PHP est naze, je pense que c&rsquo;est une question qui n&rsquo;est pas pertinente. C&rsquo;est une question stimulante pour certains, mais pour une entreprise, ça ne devrait pas compter. J&rsquo;aime à croire que c&rsquo;est une rampe de lancement pour devenir CTO &#8211; ne pas se soucier de ce genre de choses, ne pas se focaliser sur les détails techniques, mais plutôt sur la recherche de l&rsquo;équipe, etc.</p>
<p>Devenir un CTO c&rsquo;est <strong>avoir une vision d&rsquo;ensemble de l&rsquo;impact technologique</strong>, qui définit l&rsquo;entreprise et la façon dont d&rsquo;aider le client. Ca aide à être génial, et à comprendre la technologie, mais c&rsquo;est beaucoup plus que ça.</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/devenir-cto-directeur-technique/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">297</post-id>	</item>
		<item>
		<title>Django : customiser les formulaires d’admin</title>
		<link>https://metrogeek.fr/django-customiser-formulaires-admin/</link>
				<comments>https://metrogeek.fr/django-customiser-formulaires-admin/#respond</comments>
				<pubDate>Mon, 24 Oct 2016 07:24:53 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=272</guid>
				<description><![CDATA[On a vu dans un billet précédent comment créer les formulaires. On a aussi vu comment générer un panneau d’administration ultra rapidement avec Django. Maintenant, comment on customise les formulaires d’admin qui sont gracieusement générés pour simplifier votre vie de [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>On a vu dans un billet précédent <a href="https://metrogeek.fr/django-creer-formulaire/">comment créer les formulaires</a>. On a aussi vu comment <a href="https://metrogeek.fr/intro-django-admin/">générer un panneau d’administration</a> ultra rapidement avec Django. Maintenant, comment on customise les formulaires d’admin qui sont gracieusement générés pour simplifier votre vie de développeur débordé ?</p>
<h2>La surcharge</h2>
<p>Par défaut, il suffit de modifier le fichier <em>admin.py</em> de votre app, et d’ajouter par exemple <em>admin.site.register(Question)</em>. Pour ça, on va supprimer cette ligne, et créer une classe, dans laquelle on va définir nos personnalisations. Puis, il faut enregistrer le modèle pour l’admin – comme la ligne qu’on vient de supprimer – mais en ajoutant un paramètre :</p>
<pre class="brush: python; title: code; notranslate">

class QuestionAdmin(admin.ModelAdmin):
 fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)

De cette manière, on a juste changé l’ordre des champs, rien de bien foufou, mais c’est pour l’exemple.

On peut aussi créer des groupements de champs, en jouant comme ça&amp;amp;amp;amp;nbsp;:

class QuestionAdmin(admin.ModelAdmin):
 fieldsets = [
 (None, {'fields': ['question_text']}),
 ('Date information', {'fields': ['pub_date']}),
 ]

</pre>
<p>Si vous avez un formulaire avec une bonne dizaine de champs, ça peut vous aider par exemple à sectionner les choses, par exemple en groupant les dates dans leur <strong>propre groupe</strong>, etc.</p>
<p>On a travaillé depuis quelques billets avec le couple <strong>Question/Choix</strong>, donc vous avez probablement déjà enregistré ce modèle dans l’admin. Mais comment rendre ces <strong>relations</strong> disponibles et lisibles depuis vos formulaires ? C’est ce qu’on va voir maintenant.</p>
<h2>Jouer avec les relations</h2>
<p>Alors Django est suffisamment intelligent pour deviner que quand il y a une relation, il doit la proposer dans le formulaire, sous forme d’un select. Il y a même un lien qui permet d’ajouter une entité question par exemple, directement depuis ce formulaire.</p>
<p><img data-attachment-id="273" data-permalink="https://metrogeek.fr/django-customiser-formulaires-admin/relations-plus/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus.png" data-orig-size="485,296" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="relations-plus" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus-300x183.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus.png" class="aligncenter size-full wp-image-273" src="https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus.png" alt="relations-plus" width="485" height="296" srcset="https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus.png 485w, https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus-300x183.png 300w, https://metrogeek.fr/wp-content/uploads/2016/10/relations-plus-200x122.png 200w" sizes="(max-width: 485px) 100vw, 485px" /></p>
<p>Mais c’est vrai que ce n’est pas très efficace. En fait, il serait plus simple, quand on veut créer une question, de directement pouvoir ajouter les choix non ?</p>
<p>Et bien ouvrez <em>admin.py</em> :</p>
<pre class="brush: python; title: code; notranslate">
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)

</pre>
<p>Et du coup, le formulaire d’ajout de question devient :</p>
<p><img data-attachment-id="274" data-permalink="https://metrogeek.fr/django-customiser-formulaires-admin/model-relations-django/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django.png" data-orig-size="914,526" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="model-relations-django" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django-300x173.png" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django.png" class="aligncenter size-full wp-image-274" src="https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django.png" alt="model-relations-django" width="914" height="526" srcset="https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django.png 914w, https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django-300x173.png 300w, https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django-768x442.png 768w, https://metrogeek.fr/wp-content/uploads/2016/10/model-relations-django-200x115.png 200w" sizes="(max-width: 914px) 100vw, 914px" /><br />
C’est un aperçu rapide des modifications que vous pouvez faire, mais ça laisse une qualité de possibilités assez grande. Dans le prochain billet, on va voir comment changer <strong>l’apparence</strong> de l’admin, un truc essentiel non ?</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/django-customiser-formulaires-admin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">272</post-id>	</item>
		<item>
		<title>Installer et configurer un serveur DNS</title>
		<link>https://metrogeek.fr/creer-serveur-dns/</link>
				<comments>https://metrogeek.fr/creer-serveur-dns/#comments</comments>
				<pubDate>Fri, 14 Oct 2016 07:53:38 +0000</pubDate>
		<dc:creator><![CDATA[metrogeek]]></dc:creator>
				<category><![CDATA[gnu]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">https://metrogeek.fr/?p=262</guid>
				<description><![CDATA[Dans ce tutoriel on va voir comment créer son propre serveur DNS. Votre registrar propose certainement déjà un outil permettant de le gérer, mais c&#8217;est toujours intéressant de savoir faire soi-même avant de déléguer non ? La curiosité ! Nous [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>Dans ce tutoriel on va voir comment créer son propre serveur <strong>DNS</strong>. Votre registrar propose certainement déjà un outil permettant de le gérer, mais c&rsquo;est toujours intéressant de savoir faire soi-même avant de déléguer non ? <strong>La curiosité !</strong></p>
<p><img data-attachment-id="268" data-permalink="https://metrogeek.fr/creer-serveur-dns/ethernet/" data-orig-file="https://metrogeek.fr/wp-content/uploads/2016/10/ethernet.jpg" data-orig-size="800,200" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="ethernet" data-image-description="" data-medium-file="https://metrogeek.fr/wp-content/uploads/2016/10/ethernet-300x75.jpg" data-large-file="https://metrogeek.fr/wp-content/uploads/2016/10/ethernet.jpg" class="aligncenter size-full wp-image-268" src="https://metrogeek.fr/wp-content/uploads/2016/10/ethernet.jpg" alt="ethernet" width="800" height="200" srcset="https://metrogeek.fr/wp-content/uploads/2016/10/ethernet.jpg 800w, https://metrogeek.fr/wp-content/uploads/2016/10/ethernet-300x75.jpg 300w, https://metrogeek.fr/wp-content/uploads/2016/10/ethernet-768x192.jpg 768w, https://metrogeek.fr/wp-content/uploads/2016/10/ethernet-200x50.jpg 200w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>Nous utiliserons le serveur <a href="http://www.isc.org/software/bind" target="_blank">bind</a>. Nous allons tout d’abord l’installer sur le serveur principal en tant que maître. Si vous disposez d’un second serveur, vous pourrez le configurer en tant qu’esclave pour assurer la continuité du service.</p>
<p>Pour la suite de notre article (et pour tous les articles à venir), nous considérerons que vous êtes l’heureux possesseur du domaine exemple.fr, et que vous disposez de deux serveurs ayant les adresses <em>IP 1.1.1.1 et 2.2.2.2</em>. Si vous n’avez qu’un seul serveur à disposition, vous n’aurez besoin de faire que de petits ajustements qui n’empêcheront pas le système de fonctionner correctement. Vous pouvez également installer temporairement <strong>bind</strong> sur votre propre machine pour passer les tests de validation.</p>
<h2>Pare-feu</h2>
<p>Dans cet exemple, on va modifier le script pour <strong>iptables</strong>. Je suis plus un adepte de <strong>Shorewall</strong>, mais vu que personne ne l&rsquo;utilise, ça n&rsquo;aurait pas d’intérêt.</p>
<pre class="brush: bash; title: code; notranslate">
IPT=/sbin/iptables
${IPT} -A SERVICES -p tcp --dport 53 -j ACCEPT
${IPT} -A SERVICES -p udp --dport 53 -j ACCEPT

</pre>
<p>Nous ouvrons donc le port <strong>53</strong> en TCP et en UDP. Normalement, seul le protocole <strong>UDP</strong> est utilisé pour les requêtes, mais le protocole TCP est utilisé également pour les <strong>transferts de zones</strong> dont nous aurons besoin plus tard. Il est donc important d’ouvrir les connexions aux deux types de protocoles, à moins que vous ne configuriez pas un serveur esclave. Nous pourrions également spécifier directement l’adresse du serveur esclave afin d’éviter toute demande de transfert directement depuis iptables :</p>
<pre class="brush: bash; title: code; notranslate">
${IPT} -A SERVICES -p tcp --dport 53 -s 2.2.2.2 -j ACCEPT
${IPT} -A SERVICES -p udp --dport 53 -j ACCEPT
</pre>
<h2>Serveur maître</h2>
<p>Pour installer bind, rien de plus simple :&nbsp;<em>apt-get install bind9 dnsutils</em><br />
Le paquet <em>dnsutils</em> contient notamment les outils <strong>nslookup</strong> et <strong>dig</strong>, qui nous serviront par la suite à tester notre installation.<br />
Rendez-vous dans le répertoire de configuration de bind :</p>
<pre class="brush: bash; title: code; notranslate">
cd /etc/bind
/etc/init.d/bind9 stop
</pre>
<p>Réflexe à acquérir : toujours stopper un processus en cours d’exécution avant d’en modifier la configuration. Cela évite quelques surprises du genre configuration qui revient à son état précédent une fois le service relancé.</p>
<p>On créé le fichier le définition de notre domaine :</p>
<pre class="brush: bash; title: code; notranslate">
nano db.exemple.fr
$TTL 86400
@ IN SOA ns.exemple.fr. postmaster.exemple.fr. (
2012020501
2D ; Refresh
15M ; Retry
3W ; Expire
86400 ) ; Negative Cache TTL

IN NS ns.exemple.fr.
IN NS ns2.exemple.fr.

IN A 1.1.1.1

ns IN A 1.1.1.1
ns2 IN A 2.2.2.2
</pre>
<p><strong>Les domaines se terminent par un « . » !</strong></p>
<p>Quelques explications s’imposent. Dans la ligne relative au <strong>SOA</strong>, on déclare le serveur <strong>DNS autoritaire</strong> pour la zone (ns.exemple.fr) et l’adresse email du responsable (postmaster.exemple.fr, le « @ » de l’adresse étant remplacé par un « . »).</p>
<p>Ensuite, on attribue un numéro de série au fichier ; ce numéro ne s’invente pas : il s’agit de la date (au format YYYYMMDD) suivi d’un nombre compris entre 00 et 99. Pour plus de clarté, on va appeler ce nombre la « clé ». Si vous disposez de plusieurs domaines, vous pouvez utiliser le premier chiffre de la clé comme identifiant pour un domaine particulier (par exemple, « j’attribuerai toujours un 1 au domaine exemple.fr, et un 2 au domaine exemple2.fr« ), tandis que le second chiffre de la clé vous servira à indenter les modifications survenues dans ce fichier pour le jour donné.</p>
<p>Par exemple, vous faites 4 modifications sur le fichier db.exemple.fr, et 7 sur le fichier db.exemple2.fr, en date d’aujourd’hui. Vous pouvez attribuer les numéros de série suivants à vos fichiers : 2016101301 et 2016101330.&nbsp;<strong>N’oubliez jamais de modifier le numéro de série à chaque modification du fichier !</strong><br />
Si vous ne disposez que d’un seul serveur, vous pouvez omettre les lignes relatives au deuxième serveur DNS (ns2.exemple.fr et son adresse associée 2.2.2.2). Cependant, vous ne passerez pas les tests de validation si votre registrar a recours au <a href="https://www.zonemaster.net/" target="_blank"><strong>Zonemaster</strong></a> (anciennement ZoneCheck) de l’AFNIC, qui exige que vous ayez deux serveurs DNS configurés. Vous devriez installer temporairement un serveur bind sur votre propre machine.</p>
<p>Les valeurs suivantes (refresh, retry, etc.) devraient convenir à la majorité des situations.<br />
Nous définissons ensuite les deux serveurs DNS associés au nom de domaine : ns.exemple.fr. et ns2.exemple.fr.<br />
Ensuite, nous indiquons que le serveur principal a pour adresse <em>IP 1.1.1.1</em>, puis nous associons les adresses <em>1.1.1.1 et 2.2.2.2</em> aux deux serveurs de noms. Une fois que vous avez adapté cet exemple à votre propre domaine, vous pouvez enregistrer et fermer.</p>
<p>Théoriquement, dans une installation de base de bind sur une Debian stable, le fichier named.conf contient la ligne suivante :</p>
<pre class="brush: bash; title: code; notranslate">
include &quot;/etc/bind/named.conf.local&quot;;
#Si ce n’est pas le cas, rajoutez-là :
echo &quot;include \&quot;/etc/bind/named.conf.local\&quot;;&quot; &gt;&gt; named.conf
#Et modifiez le fichier named.conf.local :
nano named.conf.local
</pre>
<p>Ce fichier va contenir les <strong>directives</strong> de configuration pour un domaine particulier, en l’occurrence, <em>exemple.fr</em> (et/ou exemple2.fr). C’est une bonne pratique de configuration à laquelle passe la majorité des applications, cela permet de clarifier les choses, et de s’y retrouver facilement.</p>
<p>Mettez donc le contenu suivant dans ce fichier :</p>
<pre class="brush: bash; title: code; notranslate">
zone &quot;exemple.fr&quot; {
type master;
file &quot;/etc/bind/db.exemple.fr&quot;;
};
</pre>
<p>On défini notre instance de bind comme étant <strong>maître</strong> pour ce domaine, et on lui indique le fichier de configuration correspondant. Enregistrez et fermez ce fichier une fois modifié.&nbsp;Redémarrez ensuite bind, pour procéder à quelques tests :</p>
<pre class="brush: bash; title: code; notranslate">
/etc/init.d/bind9 restart
nslookup exemple.fr
Vous devriez obtenir la sortie suivante :
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: exemple.fr
Address: 1.1.1.1
</pre>
<p>Vous noterez qu’à cause de la propagation des <strong>DNS</strong>, votre domaine n’est peut être pas encore disponible depuis l’extérieur. N’hésitez pas à tester (en utilisant la même commande) régulièrement depuis une machine qui n’héberge pas le serveur bind.</p>
<p>Si la commande précédente vous retourne une sortie similaire, c’est que votre domaine est correctement configuré (du point de vue de bind en tout cas). En l’état actuel des choses, bind devrait donc être en mesure de répondre à des requêtes portant sur votre domaine, bien qu’encore aucun domaine « utile » ne soit créé.</p>
<h2>Serveur esclave</h2>
<p>Pour faire fonctionner deux instances de bind sur le modèle de <strong>maître/esclave</strong>, on commence par compléter un peu la configuration du serveur maître. On reste donc sur la même machine, pour créer une clé de transfert :</p>
<pre class="brush: bash; title: code; notranslate">
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST .exemple.fr.
</pre>
<p><em>dnssec-keygen</em> est un outil livré avec bind. Grâce à la commande suivante, on génère une clé en utilisant l’algorithme <em>HMAC-MD5</em>, d’une longueur de 512 bits, pour un hôte particulier (-n HOST), en l’occurrence, celui indiqué à la fin. Remplacez par le nom d’hôte du serveur. Par exemple, j’ai appelé mon serveur « foo », sur le domaine exemplebis.fr. La commande qui s’applique à mon cas devient donc :</p>
<pre class="brush: bash; title: code; notranslate">
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST foo.exemplebis.fr.
</pre>
<p><strong>Notez toujours le point à la fin du domaine.&nbsp;</strong>On génère une clé pour un hôte donné, mais <em>dnssec-keygen</em> permet bien d’autres choses que nous n’utiliserons pas ici. Notamment, vous pouvez choisir un algorithme différent, ou créer une clé pour toute une zone. Pour l’heure, nous souhaitons avoir la possibilité de transférer de manière <strong>sécurisée</strong> les données de zones (dans notre exemple, le fichier db.exemple.fr) de notre serveur maître vers le serveur esclave que nous configurerons plus tard. Cette commande est donc suffisante <strong>pour le moment</strong>.</p>
<p>A l’issue de l’exécution de cette commande (qui peut durer une vingtaine de secondes), deux nouveaux fichiers ont été créés. Ils commencent par la lettre K majuscule, et portent respectivement l’extension <em>.key</em> et <em>.private</em>. Le premier fichier contient une ligne qu’il est possible de rajouter dans un fichier de <strong>zone</strong>, tandis que le second contient quelques détails sur la création de la clé. Nous n’utiliserons dans notre cas précis aucun des deux dans son état actuel. Cependant, il peut être utile de les conserver pour un usage ultérieur.</p>
<p>La seule chose qui nous intéresse est la clé en elle-même qui figure dans les deux fichiers. Utilisez la commande cat sur le fichier .private, et copiez la clé qui apparaîtra. Créez ensuite le fichier transfer.conf :</p>
<pre class="brush: bash; title: code; notranslate">
nano transfer.conf
key &quot;TRANSFER&quot; {
algorithm hmac-md5;
secret &quot;la clé que vous avez copié&quot;;
};

server 2.2.2.2 {
keys {
TRANSFER;
};
};
</pre>
<p>Dans ce fichier, nous ajoutons une clé au « trousseau » de <strong>bind</strong>, qui ne sera destinée qu’au <strong>transfert des zones</strong> entre le maître et l’esclave. Si un cas se présente où nous devrons diffuser d’autres clés, nous en générerons de nouvelles, pour éviter toute interférence.</p>
<p>Ensuite, nous affectons cette clé au serveur esclave, <em>2.2.2.2</em>.&nbsp;Incluez ce fichier à votre configuration, puis modifiez le fichier named.conf.local :</p>
<pre class="brush: bash; title: code; notranslate">
echo &quot;include \&quot;/etc/bind/transfer.conf\&quot; &gt;&gt; /etc/bind/named.conf
nano named.conf.local
zone &quot;exemple.fr&quot; {
type master;
file &quot;/etc/bind/db.exemple.fr&quot;;
allow-transfer { 2.2.2.2; };
};
</pre>
<p>Nous avons rajouté la ligne <em>allow-transfer { 2.2.2.2; };</em> qui nous permet d’éviter que <strong>n’importe qui</strong> puisse transférer nos zones sur son serveur. Redémarrez bind :</p>
<pre class="brush: bash; title: code; notranslate">
/etc/init.d/bind9 restart
</pre>
<p>Désormais, lorsque le serveur maître redémarrera, il notifiera automatiquement le(s) serveur(s) esclave(s) de tout changement, et initiera le transfert des zones de manière sécurisée.</p>
<p>Passons maintenant à la configuration du serveur esclave à proprement parlé. Sur la machine qui hébergera ce serveur, installez bind :</p>
<pre class="brush: bash; title: code; notranslate">
apt-get install bind9 dnsutils
</pre>
<p>Nous avons créé le fichier <em>transfer.conf</em> sur le serveur maître. Le même fichier doit être créé sur la machine esclave, avec une petite nuance.</p>
<pre class="brush: bash; title: code; notranslate">
cd /etc/bind
/etc/init.d/bind9/stop
nano transfer.conf
key &quot;TRANSFER&quot; {
algorithm hmac-md5;
secret &quot;la clé que vous avez copié&quot;;
};

server 1.1.1.1 {
keys {
TRANSFER;
};
};
</pre>
<p>Vous noterez qu’il s’agit exactement du même fichier, y compris la même clé, mais que l’adresse IP de la clause server change. Dans la configuration du serveur esclave, c’est l’adresse IP du serveur maître qu’il faut indiquer. Ensuite, comme pour la configuration du serveur maître, on ajouter ce fichier à la configuration de bind :</p>
<pre class="brush: bash; title: code; notranslate">
echo &quot;include \&quot;/etc/bind/transfer.conf\&quot; &gt;&gt; /etc/bind/named.conf
</pre>
<p>Modifions ensuite le fichier named.conf.local pour y ajouter la configuration de votre (vos) domaine(s) :</p>
<pre class="brush: bash; title: code; notranslate">
zone &quot;exemple.fr&quot; {
type slave;
file &quot;/var/cache/bind/db.exemple.fr&quot;;
masters { 1.1.1.1; };
allow-notify { 1.1.1.1; };
};
</pre>
<p>Nous indiquons ici que le fichier de zone db.exemple.fr, une fois transféré, sera <strong>stocké</strong> dans le dossier /var/cache/bind, qui devrait déjà être créé. Si ce n’est pas le cas, il faut le créer, et donc tous les cas, lui attribuer <a href="https://gist.github.com/rikless/10591590" target="_blank"><strong>les bons droits</strong></a> :</p>
<pre class="brush: bash; title: code; notranslate">
mkdir -p /var/cache/bind
chown -R bind:bind /var/cache/bind
chmod -r 644 /var/cache/bind
</pre>
<p>Il suffit maintenant de redémarrer bind pour que les modifications soient prises en compte.</p>
<pre class="brush: bash; title: code; notranslate">
/etc/init.d/bind9 restart
</pre>
<p>Consultez immédiatement les journaux utilisés par bind :</p>
<pre class="brush: bash; title: code; notranslate">
tail -100 /var/log/syslog
</pre>
<p>Il se peut que vous y trouviez une erreur à propos de l’heure qui n’est pas synchronisée. Installez sur les deux serveurs le paquet <em>ntpdate</em>, puis synchronisez les horloges avant de redémarrer bind :</p>
<pre class="brush: bash; title: code; notranslate">
apt-get install ntpdate
ntpdate 0.fr.pool.ntp.org
/etc/init.d/bind9 restart
</pre>
<p>Testez maintenant votre serveur :</p>
<pre class="brush: bash; title: code; notranslate">
nslookup
&gt; server 127.0.0.1
Default server: 127.0.0.1
Address: 127.0.0.1#53
&gt; exemple.fr
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: exemple.fr
Address: 1.1.1.1
</pre>
<p>That&rsquo;s it !<br />
&lt;3</p>
]]></content:encoded>
							<wfw:commentRss>https://metrogeek.fr/creer-serveur-dns/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
						<post-id xmlns="com-wordpress:feed-additions:1">262</post-id>	</item>
	</channel>
</rss>
