Mots-clé : http

Linux / shell

Shell hints / aide

Commandes « one-line »

Connaître l’architecture de sa machine dpkg --print-architecture
Chercher les fichiers qui prennent de la place ncdu
Archiver au format :

  • tar.bz2
  • %Y.%m.%d-%Hh%Mm%Ss
tar -cjf "$(date '+%Y.%m.%d-%Hh%Mm%Ss').x.tar.bz2" htdocs/*
Archiver au format :

  • tar.gz
  • %Y.%m.%d-%Hh%Mm%Ss
tar -czf "$(date '+%Y.%m.%d-%Hh%Mm%Ss').x.tar.gz" htdocs/*

Redirection de la sortie

stderr vers stdout command 2>&1
stdout vers un fichier et stderr vers un autre command > out > 2>error
stderr vers stdout (&1) puis stdout vers un fichier command >out 2>&1
stderr vers stdout (&1) puis stdout ajouter un texte et l’afficher, sans problème de buffering (seule solution trouvée qui fonctionne chez moi) echo "bonjour" 2>&1 | awk -W interactive '{ print "Site SokoBan > "$0; fflush(stdout); }'
Tout rediriger vers un fichier Exemple court :
echo "test" &> /dev/null

Exemple long :
(psql -U xx -W -h xx -d my_base -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO public; GRANT ALL ON SCHEMA public TO my_base;" &> /dev/null) && (time (pg_restore -Fc -j 16 -d my_base my_sql_file.sql &> /dev/null))

Nettoyage de disque

Comment supprimer ses vieux noyaux (= Mint, Ubuntu etc.)
Oui c’est aussi simple que ça !
sudo purge-old-kernels

pip (= pip3)

Mettre tous les packages pour une version spécifique de python (ici 3.7) sudo -H LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/python3.7 -m pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | sudo -H LD_LIBRARY_PATH=/usr/local/lib xargs -n1 /usr/local/bin/python3.7 -m pip install -U
Vider le cache complet des packages puis enchainer une mise à jour des packages
sudo rm /var/cache/apt/*.bin && sudo rm -rf /var/lib/apt/lists/* && sudo apt-get clean && sudo apt-get update && sudo apt-get upgrade -y
Ignorer pour toujours une mise à jour d’un packet (ex ici, avec Python2.7 qui n’est plus maintenu)
sudo apt-mark hold libpython2.7
Mettre à jour tous les packages puis arrêter l’ordinateur
(c’est le shutdown -h now que
j’ai longtemps cherché, sudo halt » et autres ne fonctionnent pas

sudo apt-get update && sudo apt-get upgrade -y && shutdown -h now

copy/paste vim (trailing whitespaces!)

Solution au problème : quand on copie colle sous vim avec la souris
et qu’il ajoute plein d’espaces à la fin
Note : le -b signifie « CLIPBOARD »
c’est ce qui change tout !
xsel -b -o | sed 's/[ \t]*$//' | xsel -b
Sous Mint :
– aller dans les raccourcis claviers ;
– ajouter un nouveau personnalisé ;
– ce dernier doit lancer un script séparé
mais dans un terminal = gnome-terminal -e
(sinon le code seul, en direct, ne fonctionne pas)
gnome-terminal -e /xxx/trim.copy.paste.sh

et dans le fichier trim.copy.paste.sh :

#!/bin/bash
# -b = clipboard (= selection with mouse)
xsel -b -o | sed 's/[ \t]*$//' | xsel -b
# try both:
xsel -o | sed 's/[ \t]*$//' | xsel

https

Regénérer avec acme.sh : root@inyab2:~# acme.sh --renew -d hqf.fr
Pour génerer le https, avec création de tous les certificats + mise en place des renouvellements, utiliser certbot : root@inyab:~/certbot# ./certbot-auto
Déplacer certbot dans le dossier de letsencrypt pour être plus homogène : cd /etc/letsencrypt && mv ~/certbot .
S’il y a des problèmes d’accents, ordre shell pour tout chercher : grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx
Renouvellement automatique : cd /etc/letsencrypt/certbot && ./certbot-auto renew
Si jamais ça ne fonctionne pas, mettre toute la configuration en commentaire, puis demander à générer un certificat : cd /etc/letsencrypt/certbot && ./certbot-auto --nginx -d www.monsite.com
Autre option : faire son dossier à la main, s’assurer que nginx peut y accéder (= faire un fichier manuellement et l’ouvrir via le navigateur), et lancer certbot en précisant où déposer les certificats. cd /etc/letsencrypt/certbot && ./certbot-auto certonly -d www.ergofip.com,ergofip.com,configurateur.ergofip.com -w /web/htdocs/ergofip/htdocs/ergofip/

Changer le prompt

J’ai vu plein de choses, de discussions un peu partout, mais celle qui a fonctionné le mieux 100% sans fautes est ici, et je résume dans ce qui suit.
Séquence de caractères « non-visibles » = qu’on veut cacher, entourée par \[ et \] \[ code \]
Dans cette séquence de caractères « non-visibles », ajouter le code d’échappement qui précise qu’on veut mettre une couleur \033[X;YYm, et remplacer :
X par 0 (foncé) ou 1 (= plus clair)
YY par un code couleur
\[\033[X;YYm\]
Black \[\033[0;30m\]
Blue \[\033[0;34m\]
Brown \[\033[0;33m\]
Cyan \[\033[0;36m\]
Green \[\033[0;32m\]
Purple \[\033[0;35m\]
Red \[\033[0;31m\]
Finir par « reset à la couleur de base » \[\033[0m\]
Exemple de prompt qui affiche toutes les couleurs et qui termine par un reset à la couleur du prompt :
export PS1="\[\033[0;30m\]Black\[\033[0;34m\]Blue\[\033[0;33m\]Brown\[\033[0;36m\]Cyan\[\033[0;32m\]Green\[\033[0;35m\]Purple\[\033[0;31m\]Red\[\033[1;30m\]Black\[\033[1;34m\]Blue\[\033[1;33m\]Brown\[\033[1;36m\]Cyan\[\033[1;32m\]Green\[\033[1;35m\]Purple\[\033[1;31m\]Red\[\033[0m\]"

Déclaration de script

Shebang le meilleur
Merci stackoverflow
#!/usr/bin/env bash
La calculette version Linux = 10 fois plus puissante, ne pas oublier l'option "l" pour calculer avec des virgules (man bc) bc -l

Outils de capture d'écran

  • scrot = capture en ligne de commande
  • shutter meilleur que celui par défaut
sudo apt-get install scrot
sudo apt-get install shutter
Note : pour mettre shutter par défaut, lire la documentation ici.

Notifications scriptées sous gnome

Comment envoyer un message sous gnome (= Mint, Ubuntu etc.) #!/bin/bash
date=`(date '+%Y.%m.%d-%Hh%Mm%Ss')`
notify-send "$date: Bonjour !" "Tout le monde !"

NodeJS qui sert des fichiers et accède à MongoDB

// Exemple copié collé et adapté sur stackoverflow :
// http://stackoverflow.com/questions/15630770/node-js-check-if-path-is-file-or-directory
// http://stackoverflow.com/questions/7268033/basic-static-file-server-in-nodejs
//
var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    mongoose = require('mongoose'),
    fileSystem = require('fs'),
    path = require('path');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

var server;
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;

var personneSchema = new Schema({
  nom: String,
  prenom: String
});
var Personne = db.model('Personne', personneSchema);

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
    console.log('DB connexion reussie');
    server = http.createServer(function (request, response) {
        if (request.url=='/personnes') {
            console.log("> JSON");
            Personne.find({}).select('nom prenom').exec(function (err, p) {
                if (err) {
                    return console.log(err);
                }
                var retour='[';
                for (var i = 0; i < p.length; i++) {
                    retour+='{'+ p[i].nom+', '+p[i].prenom+'},';
                };
                retour=retour.substr(0, retour.length-2)+']';
                response.writeHead(200, {
                    'Cache-Control': 'no-cache, must-revalidate',
                    'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
                    'Content-type': 'application/json'
                });
                response.end(retour);
            });
            // Stopper tout traitement :
            return;
        }
        var uri = url.parse(request.url).pathname;
        var filename = path.join(process.cwd(), uri);
        console.log("> " + filename);
        fs.exists(filename, function(exists) {
            if ((!exists) || (fs.lstatSync(filename).isDirectory())) {
                console.log(">> fichier inexistant : " + filename);
                response.writeHead(200, {'Content-Type': 'text/plain'});
                response.write('404 Not Found\n');
                response.end();
                // Stopper tout traitement :
                return;
            }
            var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
            response.writeHead(200, {'Content-Type':mimeType});

            var fileStream = fs.createReadStream(filename);
            fileStream.pipe(response);
        });

        //var p = new Personne({
        // nom: 'Pons',
        // prenom: 'Olivier'
        //});
        //p.save(function (err) {
        // if (err) {
        // return console.log(err);
        // }
        // var query = Personne.find();
        // query.select('nom prenom');
        // query.exec(function (err, p) {
        // if (err) return console.log(err);
        // for (var i = 0; i < p.length; i++) {
        // console.log(p[i].nom+' '+p[i].prenom);
        // };
        // console.log('Nombre total d\'enregistrements : '+p.length);
        // });
        //})
    });
    // Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    // Put a friendly message on the terminal
    console.log("Server running at http://127.0.0.1:8000/");
});

Php, http et https : comment rester sur le même protocole ?

Bonjour,

Voici une petite astuce pour les développeurs de sites Internet.
Supposons que la page que vous êtes en train de développer soit du genre http://monsite.com/mapage.php.
Dans cette page, vous avez plusieurs liens/images vers le même site, mais seule l’adresse change un peu, par exemple http://autre.monsite.com/image1.png
Imaginez que quelques temps après, vous deviez changer de protocole et passer en mode sécurisé.
Vous devez changer aussi tous les autres liens, donc :

http://autre.monsite.com/image1.png

devient :

https://autre.monsite.com/image1.png

Eh bien voici l’astuce qui peut vous servir : vous pouvez demander au navigateur de rester sur le même type de protocole avec seulement deux slashes avant le nom du site. Notre exemple :

http://autre.monsite.com/image1.png

devient :

//autre.monsite.com/image1.png

(oui oui ça fonctionne et même très bien) !

Windows Vista : Apache : quand php ne charge pas le fichier php.ini

Votre fichier « php.ini » n’est pas chargé au démarrage d’Apache sous Windows Vista ?

Pas de problème. C’est très simple. Éditez votre fichier Apache de configuration, habituellement httpd.conf.
Juste avant la ligne de directive qui dit de charger le module Apache, il faut ajouter la directive PHPIniDir "C:/PHP" qui précise où doit se situer le fichier php.ini.

Exemple :

PHPIniDir "C:/PHP"
LoadModule php5_module "C:/PHP/php5apache2_2.dll"

Je ne vous parle pas de l’autre méthode moins efficace : lancer Notepad en tant qu’administrateur, ouvrir le fichier php.ini puis le sauver sous le répertoire C:\Windows (c’est le répertoire de configuration par défaut de php).
Je viens de passer plus de deux heures complètes avant de réussir ce qui me prend en temps normal, sur Linux et Windows XP, 5 minutes. Décidément, Vista est vraiment de la daube sous tous les points de vue.

Directive directory

<Directory [répertoire]> et </Directory> sont utilisées pour encadrer un groupe d’instructions qui vont être appliquées sur le répertoire et les sous-répertoires de ce répertoire.

On peut mettre n’importe quelle instruction tant que c’est une instruction « pour répertoire ». Dans tous les cas, [répertoire] est :

  • soit le nom complet du répertoire concerné (sans le slash final) ;
  • soit une expression régulière simple (que des ?, * ou []) (je n’entrerai pas en détail ici).

Exemple :

<Directory "/var/www/cgi-bin">
  AllowOverride None
  Options None
  Order allow,deny
  Allow from all
</Directory>

AllowOverride : All|None|directive-type [directive-type] ..

On précise quelles sont les directives autorisées dans le fichier .htaccess.

Voici en fonction de ce que l’on met, le résultat :

  • None : Les fichiers .htaccess sont complètement ignorés
  • All : Toutes les directives possibles dans un contexte .htaccess sont prises en compte
  • AuthConfig : Autorise les directives d’autorisation (!) à des utilisateurs (AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, Require, etc.).
  • FileInfo : Autorise les directives qui controllent les types des documents (DefaultType, ErrorDocument, ForceType, LanguagePriority, SetHandler, SetInputFilter, SetOutputFilter, et les directives du mod_mime Add* et Remove*, etc.), données méta de document (Header, RequestHeader, SetEnvIf, SetEnvIfNoCase, BrowserMatch, CookieExpires, CookieDomain, CookieStyle, CookieTracking, CookieName), directives mod_rewrite RewriteEngine, RewriteOptions, RewriteBase, RewriteCond, RewriteRule) et Action du module mod_actions.
  • Indexes : Autorise les directives qui controllent l’indexation de répertoire (AddDescription, AddIcon, AddIconByEncoding, AddIconByType, DefaultIcon, DirectoryIndex, FancyIndexing, HeaderName, IndexIgnore, IndexOptions, ReadmeName, etc.).
  • Limit : Autorise les directives qui controllent les accès « hôtes » (Allow, Deny et Order).
  • Options[=Option,...] : Autorise les directives qui controllent des particularités des répertoires (Options et XBitHack).

Order : Allow,Deny / Deny,Allow

La directive Order, lorsqu’elle est accompagnée des directives Allow et Deny, sert pour un système de contrôle en 3 passes.

  1. On passe au travers d’une des deux directives (Allow ou Deny)
  2. On passe ensuite l’autre directive (Deny ou Allow)
  3. Enfin on applique la 3ème passe pour toutes les requêtes qui n’ont correspondu ni à la première ni à la seconde

Notez bien que toutes les directives Allow et Deny sont appliquées, à l’inverse d’un pare-feu où, dès qu’il y a correspondance, on s’arrête. La troisième passe aussi est appliquée. En conséquence, l’ordre dans lequel les lignes de configuration apparaissent importe peu : toutes les directives Allow sont mises en un seul groupe, et toutes les directives Deny dans un autre. Les ordres possibles sont :

  1. Allow,Deny
    1. Toutes les directives Allow sont appliquées. Au moins l’une doit correspondre sinon la requête est rejetée.
    2. Ensuite, toutes les directives Deny sont appliquées. Si l’une d’elles correspond, la requête est rejetée.
    3. Enfin, toutes les requêtes qui ne sont validées ni par Allow ni par Deny sont considérées comme Deny
  2. Deny,Allow
    1. Toutes les directives Deny sont appliquées. Si l’une d’elles correspond, la requête est rejetée à moins qu’à la passe suivante, il y ait correspondance.
    2. Toutes les directives Allow sont appliquées.
    3. Toutes les requêtes qui ne sont validées ni par Allow ni par Deny sont considérées comme Allow
Validation : Résultat sur Allow,Deny Résultat sur Deny,Allow
Seul Allow valide Requête autorisée Requête autorisée
Seul Deny valide Requête refusée Requête refusée
Allow et Deny pas valides Seconde directive appliquée = refusée Seconde directive appliquée = autorisée
A la fois Allow & Deny valides Dernier contrôle valide appliqué = refusée Dernier contrôle valide appliqué = autorisée

Allow from all|host|env=env-variable [host|env=env-variable] ...

La directive Allow spécifie qui peut accéder à une zone du serveur.

L’accès peut être contrôlé par nom d’hôte, adresse IP, plage d’adresses IP ou encore d’autres caractéristiques de la requête du client qui ont été capturées dans des variables d’environnement.

Le premier argument est toujours from. Les arguments suivants peuvent prendre 3 formes différentes :

  • Si Allow from all est spécifié, alors tout le monde est autorisé, dans le cadre de la directive Allow, c’est à dire qu’il faudra prendre en compte la directive Deny et l’ordre spécifié par Order, mais ceci est expliqué plus haut.
  • Pour autoriser l’accès au serveur à des hôtes ou à des groupes d’hôtes on peut le faire en utilisant différents formats qui sont décrits en détail (en Anglais) ici.
  • Le dernier format possible est celui qui se base sur les variables d’environnement. C’est aussi expliqué en détail (en Anglais) ici.

Deny from all|host|env=env-variable [host|env=env-variable] ...

La directive Deny spécifie qui peut accéder à une zone du serveur.

L’accès peut être contrôlé par nom d’hôte, adresse IP, plage d’adresses IP ou encore d’autres caractéristiques de la requête du client qui ont été capturées dans des variables d’environnement.

Les arguments sont identiques à ceux décrit pour la directive Allow.

Pour plus de détails, vous pouvez le lire en Anglais ici.

Options [+|-]option [[+|-]option] ...

La directive Option décrit quelles sont les possibilités offertes au serveur pour un répertoire donné.

Option peut être mis à :

  • None : dans ce cas, aucune des possibilités supplémentaires n’est activée
  • All : toutes les possibilités supplémentaires sont actives sauf MultiViews. C’est la configuration par défaut.
  • ExecCGI : L’éxécution des scripts CGI (en utilisant le module mod_cgi) est autorisée. Le serveur suivra les liens symboliques de ce répertoire. Malgré le fait que le serveur suivra les liens symboliques de ce répertoire, cela ne change pas le nom du répertoire utilisé pour appliquer les directives dans les sections <Directory>.
    Notez que cette option est ignorée si elle est dans une section <Location> (mais c’est un peu hors sujet ici).
  • Includes : les inclusions côté serveur (en utilisant le module mod_include) sont autorisées.
  • IncludesNOEXEC : les inclusions côté serveur (en utilisant le module mod_include) sont autorisées, mais les commandes #exec et #exec cgi sont interdites.
    Il est toujours possible d’inclure en utilisant #include, des scripts virtuels CGI à partir de répertoires ScriptAliased (mais c’est un peu hors sujet ici).
  • Indexes : Si l’URL de la requête correspond à un répertoire, et qu’il n’y a aucun DirectoryIndex (par exemple ni de index.html, ni de index.php) dans ce répertoire, alors le module mod_autoindex renverra un listing formatté du répertoire.
  • MultiViews : Les contenus negotiés "MultiViews" sont autorisés en utilisant le module mod_negotiation.
  • SymLinksIfOwnerMatch : Le serveur ne suivra les liens symboliques que si l’id de l’utilisateur qui possède le répertoire – ou fichier – destination est le même que celui du lien.
    Notez que cette option est ignorée si elle est dans une section <Location> (mais c’est un peu hors sujet ici).

Normalement, si on applique plusieurs Options dans un répertoire, c’est la directive qui est la plus spécifique au répertoire qui est appliquée. Les autres Options sont ignorées. Les autres Options ne sont pas fusionnées.

Néanmoins, si, dans une directive Options, toutes les options qui suivent sont précédées par un signe + ou -, les deux Options sont fusionnées. Dans ce cas, n’importe quelle option précédée par un + est ajoutée aux options actives, et n’importe quelle option précédée par un – est retirée des options actives.

Regardez l’exemple (en Anglais) ici.

Notez bien encore une fois que si on ne précise pas la directive Options, la valeur All est appliquée.

Authname : à quoi ça sert ?

Domaine d’autorisation à utiliser lors de l’authentification HTTP. Cette directive applique le domaine d’autorisation à utiliser pour un répertoire donné.

Le domaine d’autorisation est affiché au client pour qu’il sache quel identifiant et quel mot de passe envoyer. AuthName prend un seul argument.

Si le domaine contient des espaces il doit être entouré par des guillemets.

Pour fonctionner, il doit être obligatoirement accompagné par les directives AuthType et Require, et éventuellement d’autres directives telles que AuthUserFile et AuthGroupFile.

Par exemple:

AuthName "Top Secret"

La chaine donnée par AuthName est ce qui va apparaître dans la fenêtre demandant le mot de passe de la plupart des browsers Internet.

Attention !

Si jamais vous ne mettez pas d’espaces dans la directive AuthName, alors il ne faut pas mettre de guillemets.

Par exemple:

AuthName "Top Secret"

Et :

AuthName Secret

sont des exemples corrects.

Mais ceci ne fonctionnera pas :

AuthName "Secret"

… cela peut, comme cela me l’a fait, faire perdre des heures entières…

Le module mod_rewrite

Apache se souvient des modèles, ou groupes passés dans les règles de réécriture, et on peut les rappeler grâce à la directive $N, avec (0 <= N <= 9).

Apache se souvient aussi des derniers ordres passés dans les conditions de réécriture, et on peut les rappeler grâce à la directive %N, avec (0 <= N <= 9).

Un exemple concret :

  1. RewriteCond %{HTTP_HOST} ^(www\.)+mamemeamoi\.(com|fr) [NC]
  2. RewriteCond %{REQUEST_URI} ^(.*)\.php$ [NC]
  3. RewriteRule ^/(.*) /$1?IDP=mameme [PT,QSA,S=4]

Traduit en clair, cela signifie :

  1. Si on vient ici à partir d’une adresse telles que www.mamemeamoi.com ou encore www.mamemeamoi.fr voire mamemeamoi.fr alors c’est bon on continue les conditions pour la règle à venir
  2. Si on demande à voir une page qui se termine par php alors c’est bon on continue les conditions pour la règle à venir
  3. Si on est arrivé jusqu’ici c’est que toutes les conditions ont été validées => on applique la règle qui est, traduite en Français :
    1. ^/(.*) /$1?IDP=mameme : on ajoute à l’URI, quelle qu’elle soit, les paramètres IDP=mameme ;
    2. Directive [PT] : on applique cette URI en interne de manière à faire croire à tout ce qui suit, y compris une fois que les règles de réécriture sont terminées, que c’est vraiment cette adresse qui a été demandée, donc les autres modules agiront aussi en conséquence ;
    3. Directive [QSA] : sur l’URI appliquée, on y fait suivre les paramètres qui se trouvaient après le ?, les paramètres _GET en php. Par exemple si on a demandé /t.php?i=3, on se retrouve avec l’URI finale /t.php?i=3&IDP=meme, alors que sans la directive QSA, on se retrouve avec l’URL finale /t.php?IDP=meme ;
    4. Directive [S=4] : on demande de sauter les 4 règles de réécriture qui suivent, et on appliquera celles qu’il y a après (s’il y en a).

Maintenant, voyons si on avait changé la règle de réécriture par :

  1. RewriteCond %{HTTP_HOST} ^(www\.)+mamemeamoi\.(com|fr) [NC]
  2. RewriteCond %{REQUEST_URI} ^(.*)\.php$ [NC]
  3. RewriteRule ^/(.*) /%1%2/$1

Regardez bien : il y a le sigle %1 mais aussi le sigle $1. En réalité le %1 est remplacé par ce qu’il y a dans les parenthèses rencontrées dans la condition de réécriture. Et en partant de la première condition ! A l’inverse, le $1 est remplacé par ce qu’il y a dans les parenthèses rencontrées dans la règle de réécriture. Ainsi si on demande l’URI http://www.mamemeamoi.com/popo.php, elle sera transformée en http://www.com/popo.php, et si on demande l’URI http://mamemeamoi.com/popo.php, elle sera transformée en http://com/popo.php. Ce qui ne sert à rien d’autre que de montrer un exemple. Mais imaginez ce que vous pouvez faire !