Return false

Un blog IT de plus le blog de Hubebert.

Tuto: autohébergement, gérer soi-même le changement d’IP de sa box

Tu as un serveur hébergé chez toi? Une box qui change d’IP quand ça lui chante? Voici une solution pour y pallier.

Cet article fait suite à celui d’ecaheti du 16 Août concernant la configuration de son Raspberry Pi le changement d’IP de sa box.  Il a lui même réalisé une solution expliquée dans son article, mais celle-ci nécessite qu’un moteur PHP tourne sur le Rasp. Bien qu’il éxiste des outils pour gérer ça de façon automatique, il peut être préférable de le faire soi même, c’est pourquoi je propose ici une autre approche, moins gourmande pour le serveur local et plus simple à mettre en place à mon goût.

Voici la configuration d'origine

La configuration d'origine

Ingrédients:

  • Un serveur chez soi (Raspberry ou autre, peu importe)
  • Un serveur web avec PHP (free.fr en fournit gracieusement, ça fait parfaitement l’affaire)
  • Une box permettant le NAT (la redirection des ports)

L'objectif final: mise à jour de l'IP et redirection automatique

L'objectif final: mise à jour de l'IP et redirection automatique

Sur la box:

Rediriger les ports auquels ont veut accéder depuis l’extérieur vers l’adresse IP locale du serveur. Je ne rentrerais pas dans les détails, on trouve de très bons tutos un peu partout pour ça.

Espace Web 1/2 :

Comment connaître l’ip de ma box/mon serveur local?

La meilleure façon de connaître l’IP de mon serveur local est encore de regarder l’adresse d’origine d’une requête allant de mon serveur local à mon espace web.

Pour différencier une requête qui provient d’un visiteur “normal” de celles servant a mettre à jour l’adresse de ma box on va utiliser des variables POST. On va même “sécuriser” ça sous la forme d’un ensemble clé-valeur pour éviter que n’importe qui puisse changer l’IP de référence.
On va ensuite stocker l’IP d’ou provient la requête valide dans un fichier texte. Pour récupérer l’ip d’origine d’une requête en PHP, on utilise la variable $_SERVER["REMOTE_ADDR"]. C’est pratique d’autant plus qu’en ouvrant le fichier avec l’attribut "w+" on ne se préoccupe même pas de l’effacer, le nouveau contenu remplacera toujours l’ancien contenu du dit fichier.

$KEY      =    "le_serveur";
$VALEUR =    "c'est moi!";
$FICHIER =    "ip.txt";

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}

Voilà pour la partie mise à jour de l’IP côté PHP. Rien de bien méchant. Chaque fois qu’une requête contenant “le serveur=c’est moi” sera envoyée sur ce fichier, le fichier “ip.txt” sera mis à jour avec l’adresse d’origine. Il ne reste plus qu’a le faire régulièrement…

Serveur personnel:

La partie la plus facile. On va demander l’envoi de l’ensemble clé-valeur vers le serveur web. Pour gérer les tâches répétitives on utilise le cron, auquel on ajoute la ligne suivante:

user$: crontab -e #edition du fichier crontab avec votre editeur par défaut

#Ajout d'une ligne pour envoyer la requête toutes les 5 minutes
*/5 * * * * curl --silent -F le_serveur="c'est moi!" http://addresse/de/mon/fichier.php

Espace Web 2/2 :

Revenons à l’espace Web. Pour l’instant, le fichier PHP permet de mettre à jour l’IP de notre auto-hébergement automatiquement, mais si un visiteur arrive sur la page, il ne se passe rien (page blanche). À mon goût, il y a deux trucs sympas a faire pour un visiteur:

  • Une redirection transparente et instantanée vers le serveur local
  • Une liste des services proposés par le serveur local

Option 1: Redirection transparente

Sur le fichier côté serveur on va tout simplement… rediriger le navigateur, d’où le titre ! Pour cela il existe une fonction PHP: header(). Sans rentrer dans les détails, celle-ci ne fonctionnera si elle est utilisée en tête de fichier. Si on veut rediriger, il est important de l’appeler le plus tôt possible. (Typiquement: avant le code HTML s’il y en a). La fonction header prends comme paramètre une chaîne de caractères. Si elle content “location: http://uneurl“, elle va nous rediriger vers une adresse du type: http://uneurl. On déclare donc deux variables en tête de fichier: $PORT et $PROTOCOL.

Port étant le port sur lequel rediriger (par défaut :80 pour le web), et le protocole a utiliser (http://, https:// …). À nouveau je ne vais pas rentrer dans les détails, le port 80 et le http couvrant la majorité des cas.

<?php
$KEY        =    "le_serveur";
$VALEUR     =    "c'est moi!";
$FICHIER    =    "ip.txt";
$PORT       =    ":80";
$PROTOCOL   =    "http://";

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {//Mise à jour de l'ip
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}else{//Redirection du client
$addresse   =   file_get_contents($FICHIER);
$addresse   =   $PROTOCOL . $addresse . $PORT;
header("location: $addresse");
}
?>

Protip: En PHP, lorsqu’on utilise des guillements doubles, on peut mettre nos variables directement entre les guillements. (Comme dans la ligne 15)

Option 2: Liste des services

Exemple de rendu de la liste de services

Exemple de rendu de la liste de services

On peut tout à fait s’arrêter ici et faire une page d’accueil sur le serveur local, permettant de lister les services dispos. Cependant, dans certains cas, il peut être utile de faire cela directement sur le serveur distant : pour économiser les (maigres) ressources d’un Raspberry Pi par exemple, et éviter d’y faire tourner un PHP juste pour afficher une page.

Pour lister les différents services, on va faire ça “en dur” ou de façon statique, pour éviter de scanner systématiquement tous les ports de votre serveur local à chaque visite. On va donc faire une liste des différents services que procure notre serveur. Cette liste va prendre la  forme d’un tableau associatif contenant le nom du service, et le port sur lequel il est publié.

Voici un exemple pour mon serveur.

$SERVICES    =    Array(
"Pages Web"=>":80",
"Streaming Video"=>":1234",
"Interface web qBittorrent"=>":8112",
"Interface web Transmission"=>":9091"
);

On va ensuite réaliser une boucle qui parcours ce tableau pour nous réaliser une liste au format HTML qu’il nous suffira ensuite d’afficher dans le corps d’une page HTML.

$IP = file_get_contents($FICHIER);
$listeHTML = "<ul>";
foreach($SERVICES as $nom => $port){
$URL = $PROTOCOL . $IP . $port;
$listeHTML .= "<li><a href='$URL'>$nom</a></li>";
}
$listeHTML .= "</ul>";

Pour les fénants, le code de la page HTML entière:


<?php
$KEY        =    "le_serveur";
$VALEUR     =    "c'est moi!";
$FICHIER    =    "ip.txt";
$PORT       =    ":80";
$PROTOCOL   =    "http://";
$SERVICES    =    Array(
"Web"=>":80",
"Streaming"=>":1234",
"qBittorrent"=>":8112",
"Transmission"=>":9091"
);

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}else{
$IP = file_get_contents($FICHIER);
$listeHTML = "<ul>";
foreach($SERVICES as $nom => $port){
$URL = $PROTOCOL . $IP . $port;
$listeHTML .= "<li><a href='$URL'>$nom</a></li>";
}
$listeHTML .= "</ul>";
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<link href='http://fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet' type='text/css'>
<title>Mon chouette serveur Perso!</title>
<style type="text/css" media="screen">
*{
text-align:center;
}
h1{
font-family:'Ubuntu';
}
ul{
list-style-type:none;
}
</style>
</head>

<body>
<h1>Mon chouette serveur Perso...</h1>
<p>...est à votre disposition, et fournit les services suivants:</p>
<?php echo $listeHTML;?>
</body>
</html>
Voilà, en espérant avoir été clair et que cela resserve à d’autres.
Avec la démocratisation du Raspbery Pi, ce genre de petit script peut éviter des déboires à certains d’entre vous et vous permettre de vous concentrer sur des problèmes plus intérressants.

Tags: , , , , , , , ,

15 commentaires pour “Tuto: autohébergement, gérer soi-même le changement d’IP de sa box”

  1. firekorn dit :

    Et un passage en IPV6?
    Je ne dis pas que ton idée est nul, au contraire, mais passé en IPV6 avec un FAI qui l’accepte ça règle le problème puisque tu a juste à relever l’IPV6 du serveur et le tour est joué, puisqu’en IPV6, l’IP de la box ne te sert pas de relais comme en IPV4.

  2. Simon dit :

    Il n’y a plus de renouvellement d’IP toute les 24h en IPv6? Je ne connais pas les box (j’habite pas en France) mais sur mon routeur netgear, il est possible d’y relier son compte dyndns. Hyper simple, hyper fiable.

  3. firekorn dit :

    Le renouvellement d’IP est toujours effectué mais tout ton réseau est visible de n’importe où car tes serveurs et pc en locales n’ont justement plus d’IP locales comme en IPV4. Donc la seul IP que tu a besoin de récupérer est celle de ton serveur.

    Après actuellement l’IPV6 n’étant pas proposé par tout les FAI, ta méthode aidera surement plus d’une personne.

  4. ecaheti dit :

    Bon article, je comprends mieux ce dont tu parlais dans ton commentaire. Cependant je tiens a préciser que le morceaux de PHP qui tourne sur mon serveur a la maison ne sert pas du tout a la redirection. J’aurais très bien pu mettre ma page de garde PHP sur le serveur distant pour faire le même taf sans avoir besoin de PHP en locale.
    Ceci dit, j’ai de mon côté un accès FTP “maison vers serveur” qui pourrait poser des soucis a certains. Enfin comme d’hab’ sur ce genre de problématiques, y a toujours trouze milles solution !

  5. Toilal dit :

    Tu aurais aussi pu utiliser un service web. http://freegeoip.net/json/ par exemple (JSON REST).

  6. Hubebert dit :

    @firekorn:
    Bonne remarque, mais on est malheureusement pas encore passé au “full IPv6″…

    @ecaheti:
    noté, il sert a quoi le PHP sans indiscretion?

    @Toilal:
    De ce que j’ai vu freegoip c’est plutôt pour géolocaliser un IP que pour rediriger qui que ce soit non?
    Anyway, moins je suis dépendant d’un intermédiaire, mieux je me porte :)

  7. LeGreg dit :

    firekorn a dit :
    Le renouvellement d’IP est toujours effectué mais tout ton réseau est visible de n’importe où car tes serveurs et pc en locales n’ont justement plus d’IP locales comme en IPV4. Donc la seul IP que tu a besoin de récupérer est celle de ton serveur.

    Euh je pense qu’il est probablement toujours recommandé d’avoir un NAT même en IPv6. Perso je ne mettrais pas tout mon réseau locale adressable depuis l’extérieur. Au pire un serveur unique en DMZ ou je ne sais quoi.. Tant que ça reste configurable..

  8. e-t172 dit :

    Euh je pense qu’il est probablement toujours recommandé d’avoir un NAT même en IPv6. Perso je ne mettrais pas tout mon réseau locale adressable depuis l’extérieur.

    Tu confonds NAT et pare-feu. Rien ne t’empêche d’avoir un pare-feu en IPv6.

  9. LeGreg dit :

    non je ne veux pas de machine adressable à part la box/routeur. Ce n’est possible qu’avec un NAT à priori.

  10. ecaheti dit :

    Sur la page de garde hébergé sur le Pi, il sert à récuperer l’adresse de base (donc l’ip, pour le coup) de la page pour ensuite créer un lien vers cette même adresse mais avec un port différent. Version courte : sur la même IP, un lien vers un port différent. Un de mes critères était d’en mettre le moins possible sur le serveur distant pour éviter d’avoir à maintenir un site en 2 morceaux. Le serveur distant ne contient qu’une page HTML uploadé par le Pi, avec une redirection et un peu de texte pour décorer (la date du changement d’IP et l’uptime du serveur au moment ou la page à été uploadée.

  11. firekorn dit :

    “One of the promises of IPv6 is that the almost infinite number of addresses and the better (but not perfect) renumbering makes NAT unnecessary so it will once again be possible to deploy new applications without cumbersome workarounds or random failures that the widespread use of NAT imposes in today’s IPv4.”

    source : http://ipv6.com/articles/nat/NAT-In-Depth.htm

    Le but de l’IPV6 en plus de pallié au manque d’IPV4 et de se débarrasser du NAT.
    Donc ça te gène de perdre le NAT et de rendre tout ton réseau directement adressable? Si oui, j’aimerai savoir le pourquoi.

  12. LeGreg dit :

    Quel est l’intérêt de dire au reste du monde que c’est telle ou telle machine qui a fait une requête ? De plus si une machine est adressable c’est un risque, risque qui est effectivement mitigeable avec un bon firewall, mais est-ce que les box offriront un firewall configuré pour refuser toute requête entrante par défaut ? Ou est-ce que les “applications” rendues possibles par IPv6 vont imposer que ton frigo soit accessible aux requêtes entrantes sans configuration spéciale (pour ménager l’utilisateur lambda) ?

  13. Duncan dit :

    En ce qui me concerne, j’ouvre un tunnel SSH vers mon serveur derrière ma box et je configure le navigateur pour qu’il passe par le tunnel.
    Une fois le navigateur configuré, je n’ai qu’a taper l’adresse local du serveur pour accéder aux service.
    Il est même possible de surfer via ce tunnel sans avoir de restriction coté proxy.

  14. GaLaK dit :

    Et comment tu connais l’adresse de ton serveur (aka de ta box) ? C’était pas la question ici !?

    Sinon pas mal de box/serveurs (je pense aux box FAI, aux Syno, à certains routeurs, etc.) permettent de paramétrer un compte DynDNS ou autre, ça simplifie la tâche.

  15. Toilal dit :

    Hubebert a dit :
    @Toilal:
    De ce que j’ai vu freegoip c’est plutôt pour géolocaliser un IP que pour rediriger qui que ce soit non?
    Anyway, moins je suis dépendant d’un intermédiaire, mieux je me porte :)

    Regarde la réponse du web service, il y a bien l’adresse IP dedans (parmis d’autres infos).

    Pour l’indépendance c’est un argument, mais personnellement je préfère encore m’appuyer sur un web service existant plutôt que de développer (+publier +maintenir) un web service.

    En tout cas j’ai acheté un commmandé un RaspberryPi (même deux :p), et je ferais peut-être quelques posts d’ici quelques jours de mon utilisation de la machine.

Laisser un commentaire

Si vous avez un compte sur WeFrag, connectez-vous pour publier un commentaire.

Vous pouvez, entre autres, utiliser les tags XHTML suivant :
<a href="" title="">...</a>,<b>...</b>,<blockquote cite="">...</blockquote>,<code>...</code>,<i>...</i>