Installation de Mastodon

Après avoir joué un peu avec le Mastodon et docker, j’ai eu envie de le déployer correctement. Je reprends l’article d’Agristan : https://angristan.fr/installer-instance-mastodon-debian-8/

Installation de Node.js

J’ai déjà ma propre installation, j’installe Yarn.

npm install -g yarn
Installation de Redis
apt install redis-server redis-tools
Installation de PostgreSQL
apt-get install postgresql postgresql-contrib

On crée un utilisateur et une base de données :

su - postgres
psql
CREATE USER mastodon CREATEDB;
\q
exit
Création de l’utilisateur Mastodon

On va mettre en place l’environnement de Mastodon avec cet utilisateur.

adduser --disabled-password --disabled-login mastodon

Pour se loger :

su - mastodon
Installation de Ruby
Installation des dépendances (en root) :
apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev
Installation de rbenv

On se connecte avec l’utilisateur mastodon

su - mastodon
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

On se reconnecte pour prendre en compte le nouvel environnement

exit
su - mastodon
Installation de ruby-build
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
Installation de Ruby
rbenv install 2.4.1

Cela peut prendre quelques minutes ou quelques dizaines de minutes suivant la puissance de votre serveur.

Installation de Mastodon
cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd live

Ensuite, on va utiliser la dernière version stable plutôt que le dépôt de développement continuellement mis à jour.

Note : $(git tag | tail -n 1) est une commande qui récupère automatiquement le dernier tag, c’est à dire le numéro de la dernière version.

git checkout $(git tag | tail -n 1)

Ensuite on installe le reste :

gem install bundler
bundle install --deployment --without development test
bundle install --with development
yarn install
Configuration

Pour la configuration voir plus bas.

Mise en place de la base de données
RAILS_ENV=production bundle exec rails db:setup
Pré-compilation des fichiers CSS et JS
RAILS_ENV=production bundle exec rails assets:precompile
Mise en place des scripts Systemd

Pour fonctionner, Mastodon a besoin de 3 services. Pour pouvoir les gérer facilement, on va utiliser des scripts systemd.

À faire en root.

Processus web
vi /etc/systemd/system/mastodon-web.service

Collez :

[Unit]
 Description=mastodon-web
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="RAILS_ENV=production"
 Environment="PORT=3000"
 ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target
Processus en arrière-plan
vi /etc/systemd/system/mastodon-sidekiq.service

Collez :

[Unit]
 Description=mastodon-sidekiq
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="RAILS_ENV=production"
 Environment="DB_POOL=20"
 ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 20 -q default -q mailers -q pull -q push
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target
Processus pour l’API
vi /etc/systemd/system/mastodon-streaming.service

Collez :

[Unit]
 Description=mastodon-streaming
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="NODE_ENV=production"
 Environment="PORT=4000"
 ExecStart=/usr/bin/npm run start
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target

On active les services :

systemctl enable /etc/systemd/system/mastodon-*.service

Et on démarre le bazar :

systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

Si vous modifiez la configuration :

systemctl restart mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

Pour vérifier que tout est en route :

systemctl status mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service
Mise à jour de Mastodon

Il y a souvent des mises à jour de Mastodon, surtout en ce moment. Pour mettre à jour votre instance, c’est très simple.

Sauvegarder les fichiers et la base de données avant de mettre à jour.

Déjà, une petite mise à jour des paquets ne fait pas de mal :

apt update && apt full-upgrade

On arrête tout :

systemctl stop mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

On récupère les sources, et on met à jour Mastodon, les dépendances Ruby et npm, on régénère les assets et on met à jour la BDD.

Note : $(git tag | tail -n 1) est une commande qui récupère automatiquement le dernier tag, c’est à dire le numéro de la dernière version.

Aussi, toutes ces commandes ne sont pas forcément nécessaires à chaque fois, mais les exécuter ne vous fera pas de mal 😉 . Je vous recommande de lire les notes de versions avant de mettre à jour.

su - mastodon
cd live
git fetch
git checkout $(git tag | tail -n 1)
bundle install
npm upgrade yarn
yarn install
RAILS_ENV=production bundle exec rails assets:clean
RAILS_ENV=production bundle exec rails assets:precompile
RAILS_ENV=production bundle exec rails db:migrate
exit

Et on redémarre tout :

systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service
Mise en place des crons

On édite le crontab :

crontab -e -u mastodon

Et on y ajoute :

@daily cd /home/mastodon/live && RAILS_ENV=production /home/mastodon/.rbenv/shims/bundle exec rake mastodon:daily
Installation du reverse proxy Nginx

On installe Nginx stable depuis les dépôts officiels :

wget -O - https://nginx.org/keys/nginx_signing.key | apt-key add -
echo "deb http://nginx.org/packages/debian/ $(lsb_release -sc) nginx" > /etc/apt/sources.list.d/nginx.list
apt update
apt install nginx

On ajoute la configuration :

nano /etc/nginx/conf.d/mastodon.conf

Et on y met (à adapter, ici c’est pour mstdn.io) :

map $http_upgrade $connection_upgrade {
 default upgrade;
 '' close;
}
server {
 listen 80;
 listen [::]:80;
 server_name www.mstdn.io mstdn.io;
 # On redirige tout en HTTPS
 return 301 https://mstdn.io$request_uri;

 access_log /dev/null;
 error_log /dev/null;
}

server {
 listen 443 ssl http2;
 listen [::]:443 ssl http2;
 server_name www.mstdn.io mstdn.io;

 # Ne s'applique pas si vous utilisez un sous-domaine
 if ($host = www.mstdn.io) {
  return 301 https://mstdn.io$request_uri;
 }

 access_log /var/log/nginx/mstdn-access.log;
 error_log /var/log/nginx/mstdn-error.log;

 # HTTPS
 ssl_certificate /etc/letsencrypt/live/www.mstdn.io/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/www.mstdn.io/privkey.pem;
 ssl_protocols TLSv1.2;
 ssl_ecdh_curve prime256v1;
 ssl_ciphers EECDH+AESGCM:EECDH+AES;
 ssl_prefer_server_ciphers on;
 resolver 80.67.169.12 80.67.169.40 valid=300s;
 resolver_timeout 5s;
 ssl_session_cache shared:SSL:10m;
 add_header Strict-Transport-Security "max-age=15768000";
 
 add_header Referrer-Policy "strict-origin-when-cross-origin";
 #Domaine à apdater à la fin
 add_header Content-Security-Policy "default-src 'none'; font-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self' data:; connect-src 'self' wss://mstdn.io; frame-ancestors 'none';";

 root /home/mastodon/live/public;

 location / {
  try_files $uri @proxy;
 }

 location @proxy {
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto https;
  proxy_pass_header Server;
  proxy_pass http://127.0.0.1:3000;
  proxy_buffering off;
  proxy_redirect off;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
 }

 location /api/v1/streaming {
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto https;
  proxy_pass http://127.0.0.1:4000;
  proxy_buffering off;
  proxy_redirect off;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
 }

 error_page 500 501 502 503 504 /500.html;
}

Avec une belle configuration HTTPS inclue. 🙂

Pour que tout ça soit fonctionnel on va générer les certificats correspondants au domaine.

 

 

Déployer une instance Mastodon sur Docker

Mastodon est un réseau social de micro-blogging libre et décentralisé. Il est une bonne alternative à Twitter. Voici comment tester un peu ses possibilités.

Prérequis

Avoir installé Docker.

Installation

Pour faire simple (bien que brutal) cloner le dépôt Github du projet.

$ git clone https://github.com/tootsuite/mastodon.git

Ensuite copier et éditer le fichier de configuration.

$ cp .env.production.sample .env.production

L’éditer et remplir les champs suivants :

LOCAL_DOMAIN= # d'abord remplis avec localhost j'ai ensuite laissé vide parce que mon instance est locale (pour mes tests)
LOCAL_HTTPS=false # true si certificat

Pour la configuration SMTP utiliser Mailgun ou tout autre serveur SMTP.

SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=toto
SMTP_PASSWORD=1234
SMTP_FROM_ADDRESS=notifications@example.com
SMTP_DOMAIN=example.com

Ajouter l’option SMTP_DOMAIN ce qui vous évitera des heures de recherches.

Lancer ensuite un build

docker-compose build

Puis générer la clé secrète

docker-compose run --rm web rake secret

Si tout ce passe bien recopier la clé dans le fichier .env.production

Créer la base de données

docker-compose run --rm web rails db:migrate

Et compiler les assets

docker-compose run --rm web rails assets:precompile

Vous pouver lancer le monstre :

docker-compose up

Ou en mode démon :

docker-compose up -d

Connectez vous sur le port 3000 : http://localhost:3000

Exemple Configuration
# Service dependencies
REDIS_HOST=redis
REDIS_PORT=6379
DB_HOST=db
DB_USER=postgres
DB_NAME=postgres
DB_PASS=
DB_PORT=5432

# Federation
LOCAL_DOMAIN=
LOCAL_HTTPS=false



# Application secrets
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=
SECRET_KEY_BASE=<secret>
OTP_SECRET=

# Registrations
# Single user mode will disable registrations and redirect frontpage to the first profile
# SINGLE_USER_MODE=true
# Prevent registrations with following e-mail domains
# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
# Only allow registrations with the following e-mail domains
# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc

# Optionally change default language
DEFAULT_LOCALE=fr

# E-mail configuration
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=notifications@example.com
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
#SMTP_AUTH_METHOD=plain
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true

# Optional asset host for multi-server setups
# CDN_HOST=assets.example.com

# S3 (optional)
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=http
# S3_HOSTNAME=192.168.1.123:9000


# S3 (Minio Config (optional) Please check Minio instance for details)
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=https
# S3_HOSTNAME=
# S3_ENDPOINT=

# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=


# Streaming API integration
# STREAMING_API_BASE_URL=


# Advanced settings
# If you need to use pgBouncer, you need to disable prepared statements:
# PREPARED_STATEMENTS=false
Administration

Créer un utilisateur avec l’interface de création de compte et le définir comme administrateur.

docker-compose run --rm web rails mastodon:make_admin USERNAME=<user>

 

Sources

https://angristan.fr/installer-instance-mastodon-debian-8/

https://blog.lertsenem.com/creer-son-instance-mastodon-perso-vite-fait-mal-fait-fr.html

https://github.com/tootsuite/mastodon

https://korben.info/synchroniser-mastodon-twitter.html

Installation de Docker sur Debian Jessie

Définition

Docker est un logiciel libre qui automatise le déploiement d’applications dans des conteneurs logiciels. Selon la firme de recherche sur l’industrie 451 Research, « Docker est un outil qui peut empaqueter une application et ses dépendances dans un conteneur isolé, qui pourra être exécuté sur n’importe quel serveur Linux ». Ceci permet d’étendre la flexibilité et la portabilité d’exécution d’une application, que ce soit sur la machine locale, un cloud privé ou public, une machine nue, etc.

Installation

Se Connecter avec l’utilisateur root ou préfixer les commandes par sudo.

Faire le ménage
apt remove docker docker-engine

Installation des outils

$ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     software-properties-common
Ajouter la clé PGP de Docker
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
Ajouter le dépôt

Ajouter la ligne suivante au fichier /etc/apt/sources.list

deb [arch=amd64] https://download.docker.com/linux/debian jessie stable

Et mettre à jour les dépôts :

apt update
Installer Docker
apt install docker-ce
Tester
docker run hello-world

 

Installer Docker-Compose

Docker-compose est l’outil indispensable pour gérer vos images.

$ curl -L "https://github.com/docker/compose/releases/download/1.11.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

Et pour l’auto complétion…

curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose

Sources

Wikipedia.org

https://docs.docker.com/engine/installation/linux/debian/

https://docs.docker.com/compose/install/

Blocage des pub avec Unbound

Voici un complément des bloqueurs de pub classique : le DNS.

# cd /etc/unbound/unbound.conf.d
wget -O- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | grep '^0\.0\.0\.0' | awk '{print "local-zone: \""$2"\" redirect\nlocal-data: \""$2" A 0.0.0.0\""}' > adslist

On ajoute la prise en charge de cette liste de domaines à bloquer dans notre fichier de configuration d’Unbound :

#Ads blocking
include: "/etc/unbound/unbound.conf.d/adslist"

Voilà ! Reste à relancer le service.

Défilement pleine page dynamique avec AngularJS 1.x

Sur ma station météo j’ai voulu implémenter un défilement pleine page (FullPage scrolling ou snap scroll).  La difficulté était de charger et de rafraichir dynamiquement les éléments affichés. Il existe probablement des solutions plus élégantes. Mais celle-ci répond à mon besoin.

Défilement pleine page

Pour le réaliser j’ai utilisé angular-snapscroll couplé à ses dépendances.

<div ng-controller="SnapCtrl as snapCtrl">
    <div ng-init="snapIndex=0" snapscroll="" fit-window-height="" snap-index="snapIndex" ng-swipe-up="snapIndex=snapIndex+1" ng-swipe-down="snapIndex=snapIndex-1" before-snap="snapCtrl.beforeSnap(snapIndex)">
      <div class="container">
        vue 1
      </div>

      <div class="container">
        vue 2
      </div>
    </div>
  </div>

Je maintiens un index qui sera récupéré par mon contrôleur. Voici le code, pour le moment, qui affiche l’index :

'use strict';

/**
 * @ngdoc function
 * @name App.controller:SnapCtrl
 * @description
 * # SnapCtrl
 * Controller of fullPage Scrolling
 */
angular.module('App')
  .controller('SnapCtrl', function($window, $location, $state) {

    var vm = this;

    vm.beforeSnap = function(snapIndex) {
      console.log('snapping to', snapIndex);
    };

  });

Routage des vues

Pour le routage j’utilise ui.router  et les vues multiples.

Nommage des vues :

  <div ng-controller="SnapCtrl as snapCtrl">
    <div ng-init="snapIndex=0" snapscroll="" fit-window-height="" snap-index="snapIndex" ng-swipe-up="snapIndex=snapIndex+1" ng-swipe-down="snapIndex=snapIndex-1" before-snap="snapCtrl.beforeSnap(snapIndex)">
      <div class="container">
        <div ui-view="vue1"></div>
      </div>

      <div class="container">
        <div ui-view="vue2"></div>
      </div>
    </div>
  </div>

Maintenant passons au routage :

angular.module('App')
  .config(function($routeProvider) {
    $routeProvider
      .otherwise({
      redirectTo: '/'
    });
  });

angular.module('App')
  .config(function($stateProvider) {
    $stateProvider
      .state('vue1', {
        url: "/",
        views: {
          "vue1": {
            templateUrl: 'views/vue1.html'
          },
          "vue2": {
            template: ''
          }
        }
      })
      .state('vue2', {
        url: "/vue2",
        views: {
          "vue1": {
            template: ''
          },
          "vue2": {
            templateUrl: 'views/vue2.html'
          }
        }
      });
  });

On affiche donc les vues 1 et 2 en fonction de la position du scroll.

Voici donc le contrôleur  qui va forcer la navigation.

'use strict';

/**
 * @ngdoc function
 * @name weathergFrontApp.controller:SnapCtrl
 * @description
 * # SnapCtrl
 * Controller of the App
 */
angular.module('App')
  .controller('SnapCtrl', function($window, $location, $state) {

    var vm = this;

    vm.sections = ['vue1', 'vue2']; //routes to load (vue1.html, etc)

    vm.beforeSnap = function(snapIndex) {
      console.log('snapping to', snapIndex);
      
      $state.go(vm.sections[snapIndex]);
    };


  });

Sources

Documentation angular-snapscroll

Documentation ui-router

https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

 

Chargement dynamique d’environnements avec AngularJs

Afin de pouvoir automatiser le passage de l’environnement de développement à l’environnent déployé. J’ai utilisé quelques astuces afin de gagner du temps lors de la production de version.

La solution consiste à générer un fichier env.js contenant les variables de déploiement. C’est Grunt qui fera le travail de configuration.

Installation de grunt-ng-constant

npm install --save-dev

Ecriture des configurations

Dans un répertoire config, on placera le template. Ce template sera utilisé pour générer le fichier de configuration. Dans ce script on stockera les différentes variables dans comme variable d’environnements (window.__env).

/**** DO NOT MODIFY DIRECLTY - THIS FILE IS AUTO GENERATED ***/ 
'use strict'; 


(function (window) {
  window.__env = window.__env || {};

  {% constants.forEach(function (constant){ %}
  window.__env.{%- constant.name %}={%= constant.value %};
  {% }) %}

}(this));



Et les fichiers de configurations…

Pour le développement :

{
  "APIEndpoint": {
    "protocol": null,
    "host": null,
    "port": null
  }
}

Pour la production :

{
  "APIEndpoint": {
    "protocol": "http",
    "host": "api.host.fr",
    "port": 80
  }
}

Chargement de la configuration

Maintenant nous allons configurer notre module. En chargeant les variables d’environnement (window.__env) .

/**
 * Configuration for module.
 */
'use strict';

angular.module('MyModule')
   .constant('Config', {
    API: {
      useMocks: true,
      fakeDelay: 2000,
      protocol: window.__env.APIEndpoint.protocol || window.location.protocol
        .split(':')[0],
      host: window.__env.APIEndpoint.host || window.location.hostname,
      //port: String(window.location.port || 80),
      port: window.__env.APIEndpoint.port || 3000
    }
  });

On n’oubliera pas d’inclure le fichier env.js à nos scripts.

Script de production

On enregistre une tache ngConstant chargée de générer le fichier env.js

// Automatically load required Grunt tasks
  require('jit-grunt')(grunt, {
    useminPrepare: 'grunt-usemin',
    ngtemplates: 'grunt-angular-templates',
    cdnify: 'grunt-google-cdn',
    ngconstant: 'grunt-ng-constant'
  });

/* ... */ 

 ngconstant: {
      options: {
        // Name of our Angular module with configuration data.
        name: 'env',
        // Place where we need to create new file with our config module.
        dest: '<%= yeoman.app %>/scripts/env.js',
        // This object will be merged to all config files.
        constants: 'config/default.json',
        // Template to create config module.
        template: grunt.file.read('config/env-template.ejs')
      },
      // Environments
      development: {
        constants: 'config/development.json'
      },
      production: {
        constants: 'config/production.json'
      }
    }

/* ... */

  grunt.registerTask('build', function(target) {
    var ngconstantTask = 'ngconstant:development';

    if (target === 'production') {
      ngconstantTask = 'ngconstant:production';
    }

    grunt.task.run([
      ngconstantTask,
      'clean:dist',
      'wiredep',
      'useminPrepare',
      'concurrent:dist',
      'postcss',
      'ngtemplates',
      'concat',
      'ngAnnotate',
      'copy:dist',
      'cdnify',
      'cssmin',
      'uglify',
      'filerev',
      'usemin',
      'htmlmin'
    ]);
  });

  grunt.registerTask('default', [
    'newer:jshint',
    'newer:jscs',
    'test',
    'build'
  ]);

Sources :

http://www.jvandemo.com/how-to-configure-your-angularjs-application-using-environment-variables/

http://cayugasoft.com/configuring-multiple-environments-angular-js-using-grunt-ng-constant/

Démarrer une application graphique sur un affichage distant en ssh

Pour lancer une application sur l’hôte SSH :

Il suffit d’exécuter export DISPLAY=:id# dans la session SSH.

toto@pc:~$ ssh testSSH@myServer
toto@pc:~$ export DISPLAY=:0
toto@pc:~$ gedit
ssh testSSH@myServer "DISPLAY=:0 nohup gedit"

Pour l’affichage en root

export XAUTHORITY=/home/user/.Xauthority

 

Script de reconnexion automatique au réseau Wifi

Lors de mes tests de station météo j’ai pu constater qu’au bout que quelques jours la station ne répondais plus. Diagnostique, plus de réseau wifi. J’ai donc fouiner pour dénicher ce script.

#!/bin/bash

# L'adresse IP du serveur que vous voulez pinger (8.8.8.8 est un serveur DNS public de Google)
SERVER=8.8.8.8

# Envoyer seulement 2 pings, et envoyer la sortie vers /dev/null
ping -c2 ${SERVER} > /dev/null

# Si le code retour du ping ($?) est différent de 0 (qui correspond à une erreur)
if [ $? != 0 ]
then
    # Restart the wireless interface
    # Relancer l'interface wifi
    ifdown --force wlan0
    ifup wlan0
fi

A placer dans un fichier a rendre exécutable :

sudo chmod +x /usr/local/bin/wifi_rebooter.sh

Ajouter la tache cron suivante en éditant le fichier /etc/crontab

*/5 *   * * *   root    /usr/local/bin/wifi_rebooter.sh

 

Sources :

http://www.domopi.eu/reconnecter-automatiquement-votre-raspberry-pi-au-wifi/

NodeJS et demon

Pour compléter l’article sur la manière de créer un service sous Debian. Voici comment créer un service à partir d’une application NodeJS.

J’utilise forever. Pour l’installer, rien de plus simple avec NPM.

npm install -g forever

Je crée un répertoire dans lequel forever viendra écrire ses fichiers PID.

mkdir /var/run/forever

Voici maintenant le fichier de service :

#!/bin/sh

# configure env 
export PATH=$PATH:/usr/local/bin
export NODE_PATH=$NODE_PATH:/usr/local/lib/node_modules
export SERVER_PORT=80
export SERVER_IFACE='0.0.0.0'

# Chemin vers l'application
APP_DIR=/var/app


case "$1" in
  start)
  #exec forever --sourceDir=$APP_DIR -p /var/run/forever start -c "npm start" 
  exec forever --sourceDir=$APP_DIR -p /var/run/forever start bin/www 
$APP_DIR
  ;;

  stop)
  exec forever stop --sourceDir=$APP_DIR bin/www
  ;;
esac

exit 0

 

Sources  :

https://thomashunter.name/blog/running-a-node-js-process-on-debian-as-an-init-d-service

https://www.npmjs.com/package/forever-service

Matomo encountered an error: Uncaught Error: Class "Piwik\Plugins\CustomVariables\CustomVariables" not found in /var/www/piwik/core/Tracker/TrackerCodeGenerator.php:101 Stack trace: #0 /var/www/piwik/plugins/SitesManager/API.php(160): Piwik\Tracker\TrackerCodeGenerator->generate() #1 [internal function]: Piwik\Plugins\SitesManager\API->getJavascriptTag() #2 /var/www/piwik/core/API/Proxy.php(255): call_user_func_array() #3 /var/www/piwik/core/Context.php(29): Piwik\API\Proxy->Piwik\API\{closure}() #4 /var/www/piwik/core/API/Proxy.php(158): Piwik\Context::executeWithQueryParameters() #5 /var/www/piwik/core/API/Request.php(274): Piwik\API\Proxy->call() #6 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik/Request/Php.php(46): Piwik\API\Request->process() #7 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik/Request/Php.php(18): WP_Piwik\Request\Php->call() #8 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik/Request.php(63): WP_Piwik\Request\Php->request() #9 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik.php(1038): WP_Piwik\Request->perform() #10 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik.php(1205): WP_Piwik->request() #11 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik/TrackingCode.php(16): WP_Piwik->updateTrackingCode() #12 /var/www/thegtricks/wp-content/plugins/wp-piwik/classes/WP_Piwik.php(296): WP_Piwik\TrackingCode->__construct() #13 /var/www/thegtricks/wp-includes/class-wp-hook.php(324): WP_Piwik->addJavascriptCode() #14 /var/www/thegtricks/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters() #15 /var/www/thegtricks/wp-includes/plugin.php(517): WP_Hook->do_action() #16 /var/www/thegtricks/wp-includes/general-template.php(3080): do_action() #17 /var/www/thegtricks/wp-content/themes/twentyfifteen-child/footer.php(45): wp_footer() #18 /var/www/thegtricks/wp-includes/template.php(810): require_once('...') #19 /var/www/thegtricks/wp-includes/template.php(745): load_template() #20 /var/www/thegtricks/wp-includes/general-template.php(92): locate_template() #21 /var/www/thegtricks/wp-content/themes/twentyfifteen/index.php(65): get_footer() #22 /var/www/thegtricks/wp-includes/template-loader.php(106): include('...') #23 /var/www/thegtricks/wp-blog-header.php(19): require_once('...') #24 /var/www/thegtricks/index.php(17): require('...') #25 {main} thrown (which lead to: Session must be started before any output has been sent to the browser; output started in /var/www/thegtricks/wp-includes/script-loader.php/2938)