MAJ stackdl/readme.md

This commit is contained in:
NightPumpkin 2021-08-22 23:20:34 +02:00
parent fcbd547eb1
commit a9188d4619

View File

@ -1,448 +1,33 @@
Installation de la stack "Downloads-VPN"
============
Bienvenue sur mon nouveau tutoriel. Celui-ci, je l'espere va vous apprendre a installer Jackett, Prowlarr, rutorrent, Qbittorrent, Sonarr, Radarr et Lidarr et à faire en sorte que tout ce petit monde communique au travers d'un conteneur OpenVPN.
Cette stack docker-compose contient les logiciels suivants :
| Nom du service | Dépot Officiel | Dépot utilisé* |
| ------ | ------ | ------ |
| OpenVPN Client | [dperson](https://github.com/dperson/openvpn-client) | [dperson](https://github.com/dperson/openvpn-client) |
| Jackett | [Jackett](https://github.com/Jackett/Jackett) | [Linuxserver](https://github.com/linuxserver/docker-jackett) |
| Prowlarr | [Prowlarr](https://github.com/Prowlarr/Prowlarr) | [Linuxserver](https://github.com/linuxserver/docker-prowlarr) |
| rtorrent-rutorrent | [rakshasa](https://github.com/rakshasa/rtorrent)-[Novik](https://github.com/Novik/ruTorrent) | [Crazymax](https://github.com/crazy-max/docker-rtorrent-rutorrent) |
| qBittorrent | [qBittorrent](https://github.com/qbittorrent/qBittorrent) | [Linuxserver](https://github.com/linuxserver/docker-qbittorrent) |
| Sonarr | [Sonarr](https://github.com/Sonarr/Sonarr) | [Linuxserver](https://github.com/linuxserver/docker-sonarr) |
| Radarr | [Radarr](https://github.com/Radarr/Radarr) | [Linuxserver](https://github.com/linuxserver/docker-radarr) |
| Lidarr | [Lidarr](https://github.com/Lidarr/Lidarr) | [Linuxserver](https://github.com/linuxserver/docker-lidarr) |
Elle permet d'installer rapidement ces logiciels et de s'assurer que ces derniers ne communiquerons que à travers le Client VPN.
**Disclamer : Ce tutoriel n'est pas là pour vous apprendre à télécharger des fichiers illégaux, tous messages à ce sujet seront supprimés.**
## Table des matières
- 1. [Prérequis](#1-prérequis)
- 1.a [Création des dossiers](#1-a-création-des-dossiers)
- 1.b [Modifications des .env](#1-b-modifications-des-env)
- 1.c [Transfert des fichiers dans /downloads-vpn](#1-c-transfert-des-fichiers-dans-downloads-vpn)
- 1.d [Mise en place de la config .opvn](#1-d-mise-en-place-de-la-config-opvn)
- 1.e [Optionnel - Création et Execution de TUN.sh](#1-e-optionnel-création-et-execution-de-tun)
- 2. [Création des conteneurs](#2-création-des-conteneurs)
- 2.a [Création du réseau](#2-a-création-du-réseau)
- 2.b [Création des conteneurs](#2-b-création-des-conteneurs)
- 3. [Les Bases](#3-les-bases)
- 3.a [Commandes de bases ( Docker )](#3-a-commandes-de-bases-docker)
- 3.b [Accès aux interfaces ( WebUI )](#3-b-accès-aux-interfaces-webui)
- 4. [Configuration de rutorrent](#4-configuration-de-rutorrent)
- 4.a [Réactiver la fonction Effacer / Effacer et Supprimer les données](#4-a-réactiver-la-fonction-effacer-effacer-et-supprimer-les-données)
- 4.b [Sécuriser laccès à l'interface](#4-b-sécuriser-l-accès-à-l-interface)
- 5. [Configuration de jackett](#5-configuration-de-jackett)
- 5.a [Configurer Flaresolverr](#5-a-configurer-flaresolverr)
- 6. [Aller plus loin](#6-aller-plus-loin)
- 6.a [S'assurer qu'on passe bien par le VPN](#6-a-s-assurer-qu-on-passe-bien-par-le-vpn)
- 6.b [Rajouter les chemins vers ces médias](#6-b-rajouter-les-chemins-vers-ces-medias)
- 6.c [Mise à jour automatique ( watchtower )](#6-c-mise-à-jour-automatique-watchtower)
- 6.d [Reboot automatique en cas de soucis ( autoheal )](#6-d-reboot-automatique-en-cas-de-soucis-autoheal)
- 7. Dépannage ( Ce construira au fur et a mesure des questions )
## 1. Prérequis
- Cette stack est concu pour fonctionner dans un dossier `downloads-vpn`, avec l'architecture suivante :
```
downloads-vpn ---- vpn ------------ config
| |_ scripts
|
|-- rutorrent ------ data
| |_ passwd
| |_ downloads
|
|-- qbittorrent ---- config
| |_ downloads
|
|-- prowlarr ------- config
|
|-- sonarr --------- config
|
|-- radarr --------- config
|
|-- jackett -------- config
|
|-- lidarr --------- config
|_ music
```
- Dans le paragraphe 1.a nous allons les créer avec une ligne de commande, et dans le paragraphe 1.b nous allons modifier le .env afin qu'il utilise bien ces dossiers ( en fonction de leurs localisation sur votre machine ).
### 1.a. Création des dossiers
- Avec `cd` aller dans le dossier de votre choix, par exemple "docker".
Exemple : Si votre dossier "docker" ce trouve dans /volume1, alors la commande sera :
`cd /volume1/docker`
- Maintenant que nous sommes dans le bon dossier, nous allons executer la commande suivante pour créer d'un coup, toute l'architecture nécessaire :
`mkdir -p downloads-vpn/vpn/{config,scripts} downloads-vpn/rutorrent/{data,passwd,downloads} downloads-vpn/qbitorrent/{config,downloads} downloads-vpn/prowlarr/config downloads-vpn/sonarr/config downloads-vpn/radarr/config downloads-vpn/jackett/config downloads-vpn/lidarr/{config,music}`
### 1.b. Modifications des .env
- Récupérer sur votre machine les fichiers [.env](https://gitea.zoz-serv.org/Zoz/plex_fr_discord_repo/raw/branch/evo-stackdl/docker-compose/openvpn-rutorrent-prowlarr-jackett-flaresolver-radarr-sonarr/.env), [TUN.sh](https://gitea.zoz-serv.org/Zoz/plex_fr_discord_repo/raw/branch/evo-stackdl/docker-compose/openvpn-rutorrent-prowlarr-jackett-flaresolver-radarr-sonarr/TUN.sh), [docker-compose.yml](https://gitea.zoz-serv.org/Zoz/plex_fr_discord_repo/raw/branch/evo-stackdl/docker-compose/openvpn-rutorrent-prowlarr-jackett-flaresolver-radarr-sonarr/docker-compose.yml) et [rtorrent-rutorrent.env](https://gitea.zoz-serv.org/Zoz/plex_fr_discord_repo/raw/branch/evo-stackdl/docker-compose/openvpn-rutorrent-prowlarr-jackett-flaresolver-radarr-sonarr/rtorrent-rutorrent.env).
> Vous pouvez faire un clic droit - Enregistrer sous ... sur les liens ci-dessus pour télécharger les fichiers.
- Par defaut, il n'y a rien a modifier dans `rtorrent-rutorrent.env`.
- Dans le fichier `.env` vous allez devoir modifier plusieurs chose :
**PUID et PGID** devront correspondre aux ID de votre utilisateurs, plus d'info ici : [Connaitre le PUID / PGID d'un utilisateur](https://www.forum-nas.fr/viewtopic.php?f=56&t=13213)
**RACINE** correspond au chemin vers le dossier downloads-vpn créé a l'étape 1.a.
Dans ce cas, c'est : `/volume1/docker/downloads-vpn`
### 1.c Transfert des fichiers dans /downloads-vpn
- Une fois les modifications effectuées, il faut transfert tous les fichiers ( .env, TUN.sh, docker-compose.yml, rtorrent-rutorrent.env ) dans le dossier `/downloads-vpn` précédemment créé ! Par exemple, avec FileZilla.
### 1.d Mise en place de la config .opvn
- Dans notre dossier `downloads-vpn/vpn/config`, nous allons placer notre configuration .ovpn récupéré sur notre serveur OpenVPN.
> **Note :** Si votre config VPN demande une identifications par mot de passe, alors il vous faudra modifier dans votre fichier .ovpn la ligne :
>
>```
>auth-user-pass
>```
>par :
>```
>auth-user-pass /vpn/vpn.auth
>```
>
>Dans le dossier `downloads-vpn/vpn/config` en plus du fichier .ovpn, vous aller devoir créer un fichier `vpn.auth` contenant 2 lignes, sur la 1ere ligne, votre identifiant de connexion au VPN, et sur la 2eme ligne, votre mot de passe.
>
>**Exemple :**
>```
>votreidentifiantdeconnexion
>votremotdepasse
>```
### 1.e Optionnel - Création et Execution de /tun
- Si vous êtes sur un NAS de type Synology par exemple, alors la création du TUN est **obligatoire**.
- Pour cela :
Recupérer le fichier `TUN.sh` présent, et placer le dans votre dossier `downloads-vpn`.
Vous devez être "root" pour l'executer, pour cela, passer en root avec sudo :
```
sudo su -
```
Puis rendez-vous dans le dossier contenant TUN.sh, dans mon cas `/volume1/docker/downloads-vpn`
```
cd /volume1/docker/downloads-vpn
```
on chmod le script pour le rendre executable :
```
chmod 0755 TUN.sh
```
et executer le script :
```
./TUN.sh
```
## 2. Création des conteneurs
### 2.a Création du réseau
- On créé le reseau `vpn-network` necesaire au fonctionnement du conteneurs VPN :
```
docker network create vpn-network
```
### 2.b Création des conteneurs
Maintenant que votre "stack" est prete rendez-vous dans le dossier `downloads-vpn`, dans mon cas `/volume1/docker/downloads-vpn` :
```
cd /volume1/docker/downloads-vpn
```
## 3. Les Bases
> L'installation n'étant pas classique, si vous utilisez l'interface Docker de DSM par exemple, elle va refuser de démarrer les conteneurs rattachés au conteneur vpn ( car pour elle, il n'est relié a aucun réseau, et ne comprend pas que son réseau soit un conteneur.
Il faut donc obligatoirement utiliser les commandes en SSH ou autre logiciel de monitoring Docker compatible*. Voici quelques commandes de base :
**L'utilisation de [Portainer](https://www.forum-nas.fr/viewtopic.php?f=56&t=14030) est possible par exemple.*
### 3.a Commandes de bases ( Docker )
- Arreter un conteneur : `docker stop <nom_du_conteneur>`
Exemple pour le conteneur **rutorrent** : `docker stop rutorrent`
- Redémarrer un conteneur : `docker restart <nom_du_conteneur>`
Exemple pour le conteneur **rutorrent** : `docker restart rutorrent`
- Démarrer un conteneur : `docker start <nom_du_conteneur>`
Exemple pour le conteneur **rutorrent** : `docker start rutorrent`
- Supprimer un conteneur : `docker rm <nom_du_conteneur>`
Exemple pour le conteneur **rutorrent** : `docker rm rutorrent`
- Créer / Mettre à jour la "stack" : `docker-compose up -d`
Cette commande permet de créer la stack présent dans le fichier docker-compose.yml, les conteneurs non-existant seront créés, les modifiés seront mis à jour.
> Note : Vous devez etre dans la dossier contenant le fichier docker-compose.yml pour que cette commande fonctionne.
### 3.b Accès aux interfaces ( WebUI )
- L'acces à chaque service se fait via une WebUI ( Interface Web ), sur un port quil lui est propre.
- Pour rutorrent, c'est le port `8080`. Donc l'adresse sera sous la forme : `http://IP_DE_LA_MACHINE:8080`
Exemple : Si l'adresse IP de votre machine est `192.168.1.10`, alors l'adresse d'accès sera : `http://192.168.1.10:8080`
- Ci-dessus la liste des ports des interfaces de chaque service :
| Service | Port |
| ------ | ------ |
| rutorrent | 8080 |
| qbittorrent | 8586 |
| jackett | 9117 |
| prowlarr | 9696 |
| sonarr | 8989 |
| radarr | 7878 |
| lidarr | 8686 |
## 4. Configuration de rutorrent
Depuis l'interface SSH, les commandes ci-dessous sont à executer en étant a la racine de votre dossier `downloads-vpn`.
### 4.a Réactiver la fonction Effacer / Effacer et Supprimer les données
- Par défaut dans l'image de crazymax, la fonction "Effacer et Supprimer les données" sur un torrent n'existe pas. Uniquement la fonction "Effacer", et celle-ci efface le torrent **ET** les données.
**Il n'est donc pas possible d'effacer simplement un torrent du client, sans supprimer les fichiers associés.**
Ici nous allons voir comment ré-activer cette fonction :
Ceci doit être fait, conteneur à larrêt, pour arrêter le conteneur, utiliser la commande :
```
docker stop rutorrent
```
Pour réactiver cette fonction, il faut éditer le fichier `rtorrent-rutorrent.env` :
> Note : Vous pouvez l'éditer directement depuis SSH avec l'utilitaire `nano` : `nano rtorrent-rutorrent.env`.
Retirer **erasedata** de la ligne ( N°23 ) suivante :
```
RU_REMOVE_CORE_PLUGINS=erasedata,httprpc,geoip,geoip2
```
Ce qui donne :
```
RU_REMOVE_CORE_PLUGINS=httprpc,geoip,geoip2
```
Enregistrer, et quitter.
Puis, nous allons editer le fichier `.rtorrent.rc` présent dans `downloads-vpn/rutorrent/data/rtorrent` :
> Note : Vous pouvez l'éditer directement depuis SSH avec l'utilitaire `nano` : `nano rutorrent/data/rtorrent/.rtorrent.rc`.
Les deux dernieres lignes sont :
```
# Erase data when torrent deleted (no need erasedata plugin on ruTorrent)
method.set_key = event.download.erased,delete_erased,"execute=rm,-rf,--,$d.data_path="
```
Nous allons commenter la commande avec le caractère `#` afin de la désactiver, ce qui donne :
```
# Erase data when torrent deleted (no need erasedata plugin on ruTorrent)
#method.set_key = event.download.erased,delete_erased,"execute=rm,-rf,--,$d.data_path="
```
Enregistrer, et quitter.
Nous allons re-créer le conteneur rutorrent, avec cette nouvelle configuration, pour cela nous executons simplement la commande : `docker-compose up -d`.
### 4.b Sécuriser laccès à l'interface
- La création du fichier htaccess afin de sécuriser l'acces a l'interface de rutorrent est très simple.
Arreter le conteneur :
```
docker stop rutorrent
```
Puis executer la commande suivante :
```
docker run --rm -it httpd:2.4-alpine htpasswd -Bbn MON_PSEUDO MON_MOT_DE_PASSE >> $(pwd)/rutorrent/passwd/rutorrent.htpasswd
```
Dans cette commande, il faut modifier :
**MON_PSEUDO**, par le pseudo voulu pour l'identification
**MON_MOT_DE_PASSE**, par le mot de passe souhaité pour l'identification
Une fois la commande executée, redémarrer le conteneur rutorrent :
```
docker start rutorrent
```
Maintenant, l'acces à l'interface de rutorrent réclame une identification :)
## 5. [Configuration de jackett](#5-configuration-de-jackett)]
### 5.a [Configurer Flaresolverr](#5-a-configurer-flaresolverr)]
## 6. Aller plus loin
- Retrouvez ici des astuces pour aller "un peu plus loin" dans la configurations de vos conteneurs, avec par exemple, la méthode pour rajouter des montages ( dossier de votre serveur dans le conteneur ), ou régler la mise à jour automatique de vos conteneurs.
/!\ Depuis l'interface SSH, les commandes ci-dessous sont à executer en étant à la racine de votre dossier `downloads-vpn`.
### 6.a S'assurer qu'on passe bien par le VPN
- Pour s'assurer que notre client torrent utilise bien le conteneur VPN, on peu utliser un service comme [Check my IP](http://checkmyip.torrentprivacy.com/).
Quand vous allez cliquer sur le lien du site, vous arrivez sur une page indiquant à gauche votre adresse IP.
Cliquer sur **Download test torrent fileimage** pour récupérer le .torrent, ne fermer pas la page du site et rendez-vous dans votre client torrent.
Placer le torrent en téléchargement comme un torrent normal, et retourner sur la page du site [Check my IP](http://checkmyip.torrentprivacy.com/). Quelques dizaines de secondes plus tard, la case de droite doit retourner l'IP de votre VPN ( une IP différente de la votre ! )
Si c'est le cas, c'est parfait :)
Si la case n'affiche rien, vérifier que le conteneur VPN à établi la connexion.
### 6.b Rajouter les chemins vers ces médias
Comment rajouter simplement des montages de dossiers aux instances rutorrent, qbittorrent, sonarr, ... ?
Pour cela plusieurs méthodes, en voici une :
Nous allons ici rajouter un dossier de Films ( /volume1/films ) et un dossier Series ( /volume1/series )
Editer le fichier `.env` avec la commande `nano .env`
En dessus de la ligne `RACINE=...` rajouter les lignes vers vos medias sous la forme :
```
NOM_VARIABLE=/Chemin/Dossier
```
Dans notre exemple, le fichier `.env` aura donc la forme suivante :
```
PUID=1000
PGID=1000
TZ=Europe/Paris
RACINE=/volume1/docker/downloads-vpn
FILMS=/volume1/films
SERIES=/volume1/series
```
Une fois les modifications effectuées, on enregistre et on quitte le fichier.
Maintenant, nous allons donner acces à ces dossiers a nos conteneurs. Prenons exemple avec le conteneur rutorrent.
Editer le fichier `docker-compose.yml` avec la commande `nano docker-compose.yml`
Trouver dans le fichier la configuration du conteneur rutorrent que voici :
```
rtorrent-rutorrent:
image: crazymax/rtorrent-rutorrent:latest
container_name: rutorrent
# labels:
# - com.centurylinklabs.watchtower.enable=true
# - autoheal=true
depends_on:
- vpn
env_file:
- "./rtorrent-rutorrent.env"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
network_mode: "service:vpn"
volumes:
- ${RACINE}/rutorrent/data:/data
- ${RACINE}/rutorrent/passwd:/passwd
- ${RACINE}/rutorrent/downloads:/downloads
ulimits:
nproc: 65535
nofile:
soft: 32000
hard: 40000
restart: unless-stopped
```
Dans la partie `volumes`, nous allons rajouter 2 lignes correspondantes à nos dossiers Films et Series qui nous avons configurés dans le fichier `.env`.
De cette manière :
```
rtorrent-rutorrent:
image: crazymax/rtorrent-rutorrent:latest
container_name: rutorrent
# labels:
# - com.centurylinklabs.watchtower.enable=true
# - autoheal=true
depends_on:
- vpn
env_file:
- "./rtorrent-rutorrent.env"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
network_mode: "service:vpn"
volumes:
- ${RACINE}/rutorrent/data:/data
- ${RACINE}/rutorrent/passwd:/passwd
- ${RACINE}/rutorrent/downloads:/downloads
- ${FILMS}:/media/film
- ${SERIES}:/media/series
ulimits:
nproc: 65535
nofile:
soft: 32000
hard: 40000
restart: unless-stopped
```
De cette manières, les dossiers films et séries seront accessible dans le conteneur rutorrent dans un dossier /media. Vous pouvez suivre cette même procédure pour les autres conteneurs.
Pour appliquer les changements, il ne reste qu'à mettre à jour la stack avec la commande `docker-compose up -d`, plus d'info dans le point 3.a [Commandes de bases ( Docker )](#3-a-commandes-de-bases-docker).
### 6.c Mise à jour automatique ( watchtower )
Watchtower est un conteneur qui va surveiller vos conteneurs à la recherche de mise à jour disponible ! Si une mise a jour est disponible, alors Watchtower, arrete le conteneur, récupere la nouvelle image, et re-créé le conteneur avec le nouvelle image.
Pour l'installation de Watchtower en Docker sur votre serveur, je vous laisse avec ce tuto : [Installation de Watchtower en Docker un NAS Synology](https://www.forum-nas.fr/viewtopic.php?f=56&t=14474), le point 1 vous apprendra à installer Watchtower.
une fois Watchtower installé, il vous suffit de décommenter pour **chaque** services la ligne `labels` ( si cela n'est pas déja fait ) et la ligne `- com.centurylinklabs.watchtower.enable=true`.
**Exemple :**
```
rtorrent-rutorrent:
image: crazymax/rtorrent-rutorrent:latest
container_name: rutorrent
labels:
- com.centurylinklabs.watchtower.enable=true
# - autoheal=true
depends_on:
- vpn
env_file:
- "./rtorrent-rutorrent.env"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
network_mode: "service:vpn"
volumes:
- ${RACINE}/rutorrent/data:/data
- ${RACINE}/rutorrent/passwd:/passwd
- ${RACINE}/rutorrent/downloads:/downloads
ulimits:
nproc: 65535
nofile:
soft: 32000
hard: 40000
restart: unless-stopped
```
La procédure est identique pour chacun des services du docker-compose que vous souhaitez surveiller.
Pour appliquer les changements, il ne reste qu'à mettre à jour la stack avec la commande `docker-compose up -d`, plus d'info dans le point 3.a [Commandes de bases ( Docker )](#3-a-commandes-de-bases-docker).
### 6.d Reboot automatique en cas de soucis ( autoheal )
- En cas de soucis de VPN la connexion est coupée, et donc, plus rien ne fonctionne. Souvent, un reboot soucis à faire re-prendre la connexion VPN. Afin de ne pas avoir à la faire manulement nous allons utiliser le conteneur [autoheal](https://github.com/willfarrell/docker-autoheal). Celui-ci va surveiller notre conteneur VPN, et dans le cas ou la connexion est interrompu va redémarrer le conteneur sans action de notre part.
Malheuresement, cela ne suffit pas, les conteneurs rattaché au conteneur vpn doivent également être redémarrés :)
Nous allons voir ci-dessous comment mettre ceci en place.
- Dans un 1er temps, installer le conteneur autoheal en suivant le **point 2/** de ce tutoriel : [Redémarrer automatiquement un conteneur Docker avec un statut unhealthy](https://www.forum-nas.fr/viewtopic.php?f=90&t=16019)
Maintenant, pour activer la surveillance du conteneur VPN, il vous suffit de décommenter pour le service vpn la ligne `labels` ( si cela n'est pas déja fait ) et la ligne `- autoheal=true`.
**Exemple :**
Dashy
============
Dashy vous aide à organiser vos services auto-hébergés, en les rendant tous accessibles à partir d'un seul endroit
<p align="center">
<img width="220" src="https://i.ibb.co/yhbt6CY/dashy.png" />
</p>
## Caractéristiques
* Recherche instantanée par nom, domaine et tags - commencez simplement à taper
* Raccourcis clavier entièrement personnalisables pour la navigation, le filtrage et le lancement d'applications
* Plusieurs thèmes de couleurs intégrés, avec éditeur de couleurs d'interface utilisateur et prise en charge du CSS personnalisé
* Disposition personnalisable, tailles, texte, visibilité des composants, comportement et couleurs, etc.
* De nombreuses options pour les icônes, y compris la prise en charge de Font-Awesome, le favicon à récupération automatique, les images et les emojis
* Possibilité d'afficher l'état du service pour chacune de vos applications/liens, pour une surveillance de base de la disponibilité et de la disponibilité
* Choisissez comment lancer les applications, que ce soit dans votre navigateur, une vue modale contextuelle ou un espace de travail
* Option pour l'image d'arrière-plan en plein écran, les liens de barre de navigation personnalisés, le pied de page html, le titre, etc.
* Fonctionnalité de sauvegarde et de restauration en nuage cryptée en option disponible
* Authentification facultative avec prise en charge multi-utilisateurs et privilèges configurables pour protéger votre tableau de bord
* La petite taille de l'ensemble, l'interface utilisateur et la PWA entièrement réactives rendent l'application facile à utiliser sur n'importe quel appareil
* Facile à configurer avec Docker, ou sur bare metal, ou avec un déploiement cloud en un clic
* Prise en charge multilingue, avec plus de langues ajoutées régulièrement
* Configuration simple basée sur YAML à fichier unique, ou configuration de l'application directement via l'interface utilisateur
* Fort accent sur la confidentialité
* Et bien plus encore...
## Demo ⚡
[Demo 1](https://dashy-demo-1.as93.net) ┆ [Demo 2](https://dashy-demo-2.as93.net) ┆ [Demo 3](https://dashy-demo-3.as93.net)
Lien du Github : https://github.com/Lissy93/dashy