0 Votes

Modifications pour le document Dashy

Modifié par john le 2026/09/26 16:54

Depuis la version 3.1
modifié par john
sur 2026/09/19 14:28
Commentaire de modification : Il n'y a aucun commentaire pour cette version
À la version 5.1
modifié par john
sur 2026/09/26 16:54
Commentaire de modification : Il n'y a aucun commentaire pour cette version

Résumé

Détails

Propriétés de la Page
Contenu
... ... @@ -1,14 +1,13 @@
1 -Tableau de bord d'accueil : liens vers tous les services auto-hébergés, avec leur état en direct et des widgets.
1 +Tableau de bord d'accueil du serveur principal : liens vers les services auto-hébergés avec leur état, et widgets. Il compte quatre pages : l'accueil (##conf.yml##) et trois pages secondaires.
2 2  
3 -== Fonctionnalités utilisées ==
3 +{{toc/}}
4 4  
5 -* Sections et liens vers les services, avec icônes stockées en local.
6 -* Indicateur d'état de chaque service (vérification de disponibilité).
7 -* Widgets de contenu dynamique, dont les cartes de statistiques GitHub fournies par une instance locale de github-readme-stats.
8 -* Configuration modifiable depuis l'interface, enregistrée dans le fichier YAML.
5 +Les valeurs propres à l'infrastructure sont remplacées par des marqueurs ##<ENTRE_CHEVRONS>## : ##<DOMAINE>##, adresses IP, comptes, mots de passe et clés.
9 9  
10 -== Stack ==
7 +== Déploiement ==
11 11  
9 +=== Stack Portainer ===
10 +
12 12  {{code language="yaml"}}
13 13  services:
14 14   dashy:
... ... @@ -19,7 +19,6 @@
19 19   - UID=1000
20 20   - GID=1000
21 21   - NODE_TLS_REJECT_UNAUTHORIZED=0
22 - - VUE_APP_BOB=<MOT_DE_PASSE>
23 23   ports:
24 24   - "4000:8080"
25 25   volumes:
... ... @@ -39,30 +39,217 @@
39 39   external: true
40 40  {{/code}}
41 41  
42 -* ##NODE_TLS_REJECT_UNAUTHORIZED=0## : le serveur de Dashy accepte les certificats non reconnus lors des vérifications d'état, nécessaire pour les services locaux en https avec un certificat auto-signé.
43 -* ##VUE_APP_BOB## : mot de passe d'un utilisateur de l'authentification intégrée, référencé par son nom dans ##conf.yml## (##password: VUE_APP_BOB##). Il est lu à la construction de l'application : après modification, reconstruire (Config > Rebuild).
40 +* ##NODE_TLS_REJECT_UNAUTHORIZED=0## : Dashy accepte les certificats auto-signés des services locaux (vérifications d'état, proxy CORS).
41 +* ##user-data## contient toute la configuration. Dashy sert ce dossier à la racine du site.
42 +* Le port ##4000## donne un accès direct depuis le LAN, sans SWAG ni Authelia. SWAG n'en a pas besoin : il joint le conteneur par le réseau ##proxy##.
44 44  
45 -=== Accès ===
44 +=== SWAG ===
46 46  
47 -* Consultation : publique, sans authentification.
48 -* Modification de la configuration : connexion en deux temps, d'abord Authelia, qui redirige ensuite vers la connexion de Dashy (utilisateur défini dans ##conf.yml##, mot de passe dans ##VUE_APP_BOB##).
49 -{{info}}En consultation publique, le contenu de ##conf.yml## reste lisible par tous : n'y mettre ni mot de passe, ni jeton, ni adresse de service qu'on ne veut pas rendre visible.{{/info}}
46 +##<APPDATA>/swag/config/nginx/proxy-confs/30-dashy.subdomain.conf## :
50 50  
51 -== Configuration ==
48 +{{code language="nginx"}}
49 +server {
50 + listen 443 ssl;
51 + listen [::]:443 ssl;
52 + server_name dash.<DOMAINE>;
52 52  
54 + include /config/nginx/ssl.conf;
55 + include /config/nginx/snippets/robots-default.conf;
56 +
57 + client_max_body_size 25m;
58 +
59 + # Authelia devant tout le domaine
60 + include /config/nginx/authelia-server.conf;
61 +
62 + # Upstream Dashy
63 + set $upstream_app dashy;
64 + set $upstream_port 8080;
65 + set $upstream_proto http;
66 +
67 + # (facultatif) proxy vers /pico/
68 + location /pico/ {
69 + include /config/nginx/authelia-location.conf;
70 + proxy_pass http://<IP_PICO>/;
71 + include /config/nginx/proxy.conf;
72 + proxy_set_header Connection close;
73 + }
74 +
75 + # API de Dashy (sauvegarde de la config, vérifications d'état)
76 + location ^~ /api/ {
77 + include /config/nginx/authelia-location.conf;
78 + include /config/nginx/proxy.conf;
79 + include /config/nginx/resolver.conf;
80 + proxy_pass $upstream_proto://$upstream_app:$upstream_port;
81 + }
82 + location = /cors-proxy {
83 + include /config/nginx/authelia-location.conf;
84 + # Dashy envoie la cible dans ce header
85 + set $target $http_target_url;
86 + if ($target = "") { return 400; }
87 +
88 + add_header Access-Control-Allow-Origin "*" always;
89 + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
90 + add_header Access-Control-Allow-Headers "*" always;
91 + if ($request_method = OPTIONS) { return 204; }
92 +
93 + # TLS (certs auto-signés possibles sur les cibles LAN, ex: Nextcloud)
94 + proxy_ssl_server_name on;
95 + proxy_ssl_verify off;
96 +
97 + # Par défaut, on ne fait pas confiance à l'input
98 + set $auth_header "";
99 + set $accept_header "";
100 + set $ocs_header "";
101 + set $host_override "";
102 +
103 + access_by_lua_block {
104 + local target = ngx.var.target
105 +
106 + local host, port = target:match("^https?://([^/:]+):?(%d*)")
107 + if not host then
108 + ngx.status = 400
109 + ngx.header["Content-Type"] = "application/json"
110 + ngx.say('{"error":"Target-URL invalide"}')
111 + return ngx.exit(400)
112 + end
113 +
114 + -- Cibles LAN explicitement autorisées (widgets Dashy internes)
115 + local allowed_internal = { ["<IP_SERVEUR>"] = true, ["<IP_ADGUARD>"] = true, ["<IP_PICO>"] = true }
116 + local function is_private_ip(h)
117 + if h == "localhost" then return true end
118 + local a, b = h:match("^(%d+)%.(%d+)%.%d+%.%d+$")
119 + if not a then return false end -- pas une IPv4 littérale -> traité comme hôte public
120 + a, b = tonumber(a), tonumber(b)
121 + if a == 127 or a == 10 or a == 0 then return true end
122 + if a == 172 and b >= 16 and b <= 31 then return true end -- 172.16.0.0/12 (docker inclus)
123 + if a == 192 and b == 168 then return true end
124 + if a == 169 and b == 254 then return true end -- link-local / metadata cloud
125 + return false
126 + end
127 +
128 + -- Anti-SSRF : on bloque tout le LAN/loopback/metadata, sauf les cibles explicitement whitelistées
129 + if is_private_ip(host) and not allowed_internal[host] then
130 + ngx.status = 403
131 + ngx.header["Content-Type"] = "application/json"
132 + ngx.say('{"error":"Cible interne non autorisée"}')
133 + return ngx.exit(403)
134 + end
135 +
136 + ngx.var.host_override = (port ~= "" and port ~= nil) and (host .. ":" .. port) or host
137 +
138 + -- Parse le JSON envoyé dans customheaders
139 + local cjson = require "cjson.safe"
140 + local hdrs = ngx.req.get_headers()
141 + local ch = hdrs["customheaders"]
142 + if ch then
143 + local obj = cjson.decode(ch)
144 + if obj then
145 + if obj["Authorization"] then ngx.var.auth_header = obj["Authorization"] end
146 + if obj["Accept"] then ngx.var.accept_header = obj["Accept"] end
147 + if obj["OCS-APIREQUEST"] ~= nil then
148 + ngx.var.ocs_header = tostring(obj["OCS-APIREQUEST"])
149 + end
150 + end
151 + end
152 + }
153 +
154 + # Injecte les vrais headers vers la cible
155 + proxy_set_header Authorization $auth_header;
156 + proxy_set_header Accept $accept_header;
157 + proxy_set_header OCS-APIREQUEST $ocs_header;
158 +
159 + proxy_set_header Host $host_override;
160 + proxy_set_header X-Forwarded-Proto https;
161 +
162 + proxy_pass $target;
163 +}
164 +
165 + # Application (SPA Vue en history mode)
166 + location / {
167 + include /config/nginx/authelia-location.conf;
168 + include /config/nginx/proxy.conf;
169 + include /config/nginx/resolver.conf;
170 + proxy_pass $upstream_proto://$upstream_app:$upstream_port;
171 +
172 + # --- Fallback SPA : si l’upstream renvoie 404 sur /login, /settings, etc.,
173 + # on renvoie l'index de l'app pour laisser Vue router côté client.
174 + proxy_intercept_errors on;
175 + error_page 404 = @dashy_fallback;
176 + }
177 +
178 + # Cible du fallback : renvoyer l'index de l'app en conservant les en-têtes
179 + location @dashy_fallback {
180 + proxy_set_header X-Original-URI $request_uri;
181 + proxy_pass $upstream_proto://$upstream_app:$upstream_port/;
182 + }
183 +}
184 +{{/code}}
185 +
186 +* Authelia protège tout le domaine, y compris les fichiers YAML, qui contiennent les identifiants des widgets.
187 +* ##/cors-proxy## remplace le proxy CORS de Dashy pour les widgets en ##useProxy: true##. Il ne relaie que les en-têtes ##Authorization##, ##Accept## et ##OCS-APIREQUEST##, et refuse les IP privées absentes de ##allowed_internal## : tout nouveau widget qui vise une IP du LAN doit y être ajouté.
188 +* ##/pico/## relaie l'interface web du Pico W.
189 +* ##@dashy_fallback## renvoie l'application sur les routes internes de Vue (##/login##...), que le serveur de Dashy renvoie en 404.
190 +
191 +=== Authelia ===
192 +
193 +Règle dans la section ##access_control## de la configuration d'Authelia :
194 +
195 +{{code language="yaml"}}
196 +access_control:
197 + default_policy: deny
198 + rules:
199 + - domain: "dash.<DOMAINE>"
200 + policy: one_factor
201 +{{/code}}
202 +
203 +Aucune règle ##bypass## pour ce domaine ne doit la précéder : Authelia applique la première règle qui correspond.
204 +
205 +== Fichiers de configuration ==
206 +
53 53  Dans ##<APPDATA>/Dashy/user-data## :
54 54  
55 -|=Élément|=Rôle
56 -|##conf.yml##|Configuration principale : pages, sections, liens, widgets, thème
57 -|##bookmark.yml##|Page secondaire de favoris
58 -|##item-icons/##|Icônes des services, stockées en local
209 +|=Page Dashy|=Fichier|=Sous-page|=Widgets avec identifiants
210 +|Accueil|##conf.yml##|[[Accueil>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.Accueil.WebHome]]|##adguard-stats##, ##adguard-filter-status##, ##adguard-top-domains## (compte AdGuard Home) ; ##nextcloud-system## (mot de passe d'application Nextcloud)
211 +|bookmarks|##bookmark.yml##|[[Bookmarks>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.Bookmarks.WebHome]]|—
212 +|cpu|##cpu.yml##|[[CPU>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.CPU.WebHome]]|—
213 +|news|##news.yml##|[[News>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.News.WebHome]]|##flight-data## (clé RapidAPI) ; ##news-headlines## (clé Currents API)
59 59  
60 -* ##appConfig.faviconApi: local## : aucune icône n'est récupérée sur un service externe.
61 -* Vérifier la syntaxe après une modification à la main :
215 +##item-icons/## contient les icônes locales et l'image de fond.
62 62  
217 +=== Multi-pages ===
218 +
219 +La page d'accueil est ##conf.yml##. Elle déclare les pages secondaires dans ##pages:## : nom affiché dans la barre de navigation et chemin relatif à ##user-data##.
220 +
221 +{{code language="yaml"}}
222 +pages:
223 + - name: bookmarks
224 + path: bookmark.yml
225 + - name: cpu
226 + path: cpu.yml
227 + - name: news
228 + path: news.yml
229 +{{/code}}
230 +
231 +Chaque page secondaire ne contient que ##pageInfo##, ##sections## et la même liste ##pages:##, pour garder la navigation. ##appConfig## n'est lu que dans ##conf.yml## et s'applique à toutes les pages.
232 +
233 +Fichiers présents mais non référencés : ##cpu2.yml## (ancienne copie de ##cpu.yml## à l'indentation cassée), ##conf.yml.bak## et ##bookmark.yml.bak##.
234 +
235 +=== Éléments communs ===
236 +
237 +##appConfig## est dans ##conf.yml##, dont le fichier complet est sur la sous-page [[Accueil>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.Accueil.WebHome]].
238 +
239 +* Thème ##dracula##, image de fond servie depuis ##item-icons/##.
240 +* ##statusCheck: false## au niveau global : la vérification d'état est activée item par item.
241 +* ##faviconApi: allesedv## pour les items en ##icon: favicon##. ##enableFontAwesome: true## pour les icônes ##fas##, ##fab## et ##fad##. Les icônes ##hl-...## viennent du jeu homelab intégré.
242 +* ##widgetsAlwaysUseProxy: false## : chaque widget choisit avec ##useProxy## s'il passe par ##/cors-proxy##. Le réglage se met sur le widget : au niveau de la section, il est ignoré.
243 +* Authentification : un compte ##admin## défini par son nom et le hash SHA-256 de son mot de passe (##echo -n '<MOT_DE_PASSE>' ~| sha256sum##). ##enableGuestAccess: true## : une fois passé Authelia, on voit les pages sans se connecter à Dashy. ##disableConfigurationForNonAdmin: true## : seul l'admin modifie la configuration.
244 +
245 +Vérifier la syntaxe après une modification à la main :
246 +
63 63  {{code language="bash"}}
64 64  docker exec dashy yarn validate-config
65 65  {{/code}}
250 +
66 66  == Statistiques GitHub : github-readme-stats ==
67 67  
68 68  Instance locale de github-readme-stats, qui génère les cartes SVG de statistiques GitHub affichées par un widget de Dashy : statistiques du profil, langages les plus utilisés, dépôts épinglés.
... ... @@ -104,6 +104,36 @@
104 104  
105 105  Puis redéployer la stack dans Portainer.
106 106  
292 +== Maintenance ==
293 +
294 +=== Après une migration ou une réinstallation ===
295 +
296 +|=Service|=À refaire
297 +|Nextcloud|Créer un nouveau mot de passe d'application et le reporter dans ##nextcloud-system## : les mots de passe d'application ne suivent pas une migration.
298 +|AdGuard Home|Reporter le compte de l'interface web dans les trois widgets ##adguard-*##. Si l'IP change : ##hostname## et ##allowed_internal## de SWAG.
299 +|Pico W|Si l'IP change : ##news.yml## (item et script), ##location /pico/## et ##allowed_internal## de SWAG.
300 +|SWAG, Authelia|Remettre ##30-dashy.subdomain.conf## complet et la règle ##one_factor##, puis vérifier en navigation privée que ##/conf.yml## redirige vers Authelia.
301 +|Dashy|Restaurer ##user-data##.
302 +
303 +=== Recharger la configuration ===
304 +
305 +* Dashy relit les fichiers YAML à chaque chargement : après une modification à la main, rafraîchir la page. Si l'ancienne version reste affichée, elle vient du stockage local du navigateur : réinitialiser les paramètres locaux depuis le menu de configuration.
306 +* SWAG : ##docker exec swag nginx -t## puis ##docker exec swag nginx -s reload##. Authelia : ##docker restart authelia##.
307 +
308 +=== Un widget reste vide ===
309 +
310 +Dans les outils de développement du navigateur (F12, onglet Réseau), regarder la requête du widget :
311 +
312 +|=Symptôme|=Cause
313 +|Erreur CORS sur un appel direct|Passer le widget en ##useProxy: true##
314 +|##/cors-proxy## : 302 ou 401|Session Authelia expirée : recharger la page
315 +|##/cors-proxy## : 403 ##Cible interne non autorisée##|IP absente de ##allowed_internal##
316 +|##/cors-proxy## : 401 ou 403 de la cible|Identifiants faux ou révoqués, compte sans droits, ou en-tête non relayé par le bloc Lua
317 +|##/cors-proxy## : 502 ou 504|Service cible arrêté ou injoignable depuis SWAG
318 +
319 +Journaux : ##docker logs dashy## et ##<APPDATA>/swag/config/log/nginx/error.log##.
320 +
107 107  == Sauvegarde ==
108 108  
109 -##<APPDATA>/Dashy/user-data## est sauvegardé par le script de [[Sauvegarde>>Wiki Batcave John.Infrastructure.Sauvegarde.WebHome]]. Dashy enregistre aussi une copie de la configuration précédente dans ce dossier à chaque sauvegarde depuis l'interface.
323 +##<APPDATA>/Dashy/user-data## est sauvegardé par le script de [[Sauvegarde>>Wiki Batcave John.Infrastructure.Sauvegarde.WebHome]], identifiants des widgets compris. Le fichier SWAG est aussi dans ##<APPDATA>##.
324 +