0 Votes

Code source wiki de Dashy

Version 4.1 par john le 2026/09/26 16:22

Afficher les derniers auteurs
1 Tableau de bord d'accueil : liens vers tous les services auto-hébergés, avec leur état en direct et des widgets, répartis sur une page d'accueil et trois pages secondaires.
2
3 == Fonctionnalités utilisées ==
4
5 * Sections et liens vers les services, avec icônes stockées en local ou issues des jeux d'icônes intégrés.
6 * Indicateur d'état de chaque service (vérification de disponibilité).
7 * Configuration multi-pages : une page d'accueil (##conf.yml##) et trois pages secondaires déclarées dans sa section ##pages:##.
8 * Widgets de contenu dynamique, dont certains interrogent des services locaux ou des API externes avec des identifiants (AdGuard Home, Nextcloud, API de vols et d'actualités).
9 * Cartes de statistiques GitHub fournies par une instance locale de github-readme-stats.
10 * Accès protégé par Authelia au niveau de SWAG : aucune page ni aucun fichier de configuration n'est servi sans connexion.
11 * Proxy CORS personnalisé dans SWAG, qui remplace celui de Dashy pour les widgets en ##useProxy: true##.
12 * Configuration modifiable depuis l'interface, enregistrée dans les fichiers YAML.
13
14 == Stack ==
15
16 {{code language="yaml"}}
17 services:
18 dashy:
19 image: lissy93/dashy:latest
20 container_name: dashy
21 environment:
22 - NODE_ENV=production
23 - UID=1000
24 - GID=1000
25 - NODE_TLS_REJECT_UNAUTHORIZED=0
26 ports:
27 - "4000:8080"
28 volumes:
29 - <APPDATA>/Dashy/user-data:/app/user-data
30 restart: unless-stopped
31 healthcheck:
32 test: ['CMD', 'node', '/app/services/healthcheck']
33 interval: 90s
34 timeout: 10s
35 retries: 3
36 start_period: 40s
37 networks:
38 - proxy
39
40 networks:
41 proxy:
42 external: true
43 {{/code}}
44
45 * ##NODE_TLS_REJECT_UNAUTHORIZED=0## : le serveur de Dashy accepte les certificats non reconnus lors des vérifications d'état et dans son proxy CORS, nécessaire pour les services locaux en https avec un certificat auto-signé.
46 * ##UID## / ##GID## : propriétaire des fichiers écrits dans ##user-data## (sauvegarde depuis l'interface).
47 * Port ##4000## : accès direct depuis le LAN, sans SWAG ni Authelia. L'accès normal passe par SWAG, qui joint le conteneur par son nom sur le réseau ##proxy##, port interne ##8080##. Pour que tout accès passe par Authelia, supprimer cette publication de port : SWAG n'en a pas besoin.
48 * Volume : tout le dossier ##user-data## est monté dans ##/app/user-data##. Dashy sert ce dossier à la racine du site : ##conf.yml##, les pages secondaires et ##item-icons/## sont accessibles par leur nom.
49 * Réseau ##proxy## : réseau Docker externe partagé avec SWAG, à créer avant le premier déploiement (##docker network create proxy##).
50 * Mises à jour de l'image : [[Watchtower>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Watchtower.WebHome]].
51
52 === Exposition derrière SWAG ===
53
54 Fichier ##<APPDATA>/swag/config/nginx/proxy-confs/30-dashy.subdomain.conf##. Chaque ##location## inclut ##authelia-location.conf##, selon le même schéma que les autres services protégés. Voir aussi [[SWAG>>Wiki Batcave John.Infrastructure.ServeurPrincipal.SWAG.WebHome]].
55
56 {{code language="nginx"}}
57 server {
58 listen 443 ssl;
59 listen [::]:443 ssl;
60 server_name <DOMAINE_DASHY>;
61
62 include /config/nginx/ssl.conf;
63 include /config/nginx/snippets/robots-default.conf;
64
65 client_max_body_size 25m;
66
67 # Authelia : tout le domaine exige une connexion
68 include /config/nginx/authelia-server.conf;
69
70 set $upstream_app dashy;
71 set $upstream_port 8080;
72 set $upstream_proto http;
73
74 # Interface web du Pico W, relayée sous /pico/
75 location /pico/ {
76 include /config/nginx/authelia-location.conf;
77 proxy_pass http://<IP_PICO>/;
78 include /config/nginx/proxy.conf;
79 proxy_set_header Connection close;
80 }
81
82 # API de Dashy (sauvegarde de la config, vérifications d'état...)
83 location ^~ /api/ {
84 include /config/nginx/authelia-location.conf;
85 include /config/nginx/proxy.conf;
86 include /config/nginx/resolver.conf;
87 proxy_pass $upstream_proto://$upstream_app:$upstream_port;
88 }
89
90 # Proxy CORS des widgets, traité par SWAG et non par Dashy
91 location = /cors-proxy {
92 include /config/nginx/authelia-location.conf;
93 set $target $http_target_url;
94 if ($target = "") { return 400; }
95
96 add_header Access-Control-Allow-Origin "*" always;
97 add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
98 add_header Access-Control-Allow-Headers "*" always;
99 if ($request_method = OPTIONS) { return 204; }
100
101 proxy_ssl_server_name on;
102 proxy_ssl_verify off;
103
104 set $auth_header "";
105 set $accept_header "";
106 set $ocs_header "";
107 set $host_override "";
108
109 access_by_lua_block {
110 local target = ngx.var.target
111 local host, port = target:match("^https?://([^/:]+):?(%d*)")
112 if not host then
113 ngx.status = 400
114 ngx.header["Content-Type"] = "application/json"
115 ngx.say('{"error":"Target-URL invalide"}')
116 return ngx.exit(400)
117 end
118
119 -- Cibles LAN autorisées (widgets Dashy internes)
120 local allowed_internal = { ["<IP_SERVEUR>"] = true, ["<IP_ADGUARD>"] = true, ["<IP_PICO>"] = true }
121 local function is_private_ip(h)
122 if h == "localhost" then return true end
123 local a, b = h:match("^(%d+)%.(%d+)%.%d+%.%d+$")
124 if not a then return false end
125 a, b = tonumber(a), tonumber(b)
126 if a == 127 or a == 10 or a == 0 then return true end
127 if a == 172 and b >= 16 and b <= 31 then return true end
128 if a == 192 and b == 168 then return true end
129 if a == 169 and b == 254 then return true end
130 return false
131 end
132
133 -- Anti-SSRF : LAN, loopback et metadata bloqués sauf liste blanche
134 if is_private_ip(host) and not allowed_internal[host] then
135 ngx.status = 403
136 ngx.header["Content-Type"] = "application/json"
137 ngx.say('{"error":"Cible interne non autorisée"}')
138 return ngx.exit(403)
139 end
140
141 ngx.var.host_override = (port ~= "" and port ~= nil) and (host .. ":" .. port) or host
142
143 -- En-têtes envoyés par Dashy en JSON dans CustomHeaders
144 local cjson = require "cjson.safe"
145 local ch = ngx.req.get_headers()["customheaders"]
146 if ch then
147 local obj = cjson.decode(ch)
148 if obj then
149 if obj["Authorization"] then ngx.var.auth_header = obj["Authorization"] end
150 if obj["Accept"] then ngx.var.accept_header = obj["Accept"] end
151 if obj["OCS-APIREQUEST"] ~= nil then ngx.var.ocs_header = tostring(obj["OCS-APIREQUEST"]) end
152 end
153 end
154 }
155
156 proxy_set_header Authorization $auth_header;
157 proxy_set_header Accept $accept_header;
158 proxy_set_header OCS-APIREQUEST $ocs_header;
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 mode history)
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 # Une 404 de l'upstream sur /login, /settings... renvoie l'index de l'app
173 proxy_intercept_errors on;
174 error_page 404 = @dashy_fallback;
175 }
176
177 location @dashy_fallback {
178 proxy_set_header X-Original-URI $request_uri;
179 proxy_pass $upstream_proto://$upstream_app:$upstream_port/;
180 }
181 }
182 {{/code}}
183
184 Fonctionnement du proxy CORS :
185
186 * Un widget en ##useProxy: true## n'appelle pas l'API cible depuis le navigateur : il envoie la requête à ##/cors-proxy## sur le domaine de Dashy, avec l'adresse cible dans l'en-tête ##Target-URL## et ses propres en-têtes (authentification comprise) en JSON dans ##CustomHeaders##.
187 * Derrière SWAG, c'est ce bloc ##location = /cors-proxy## qui répond, pas le proxy intégré de Dashy. Il ne transmet que ##Authorization##, ##Accept## et ##OCS-APIREQUEST## : un widget qui a besoin d'un autre en-tête doit être ajouté dans le bloc Lua.
188 * Les adresses IP privées sont refusées (403), sauf celles de ##allowed_internal##. Tout nouveau widget qui vise une IP du LAN doit y être ajouté, puis SWAG rechargé. Un nom de domaine public passe sans liste blanche.
189 * Les appels à ##/cors-proxy## partent de la page Dashy, sur le même domaine : le navigateur y joint le cookie de session Authelia, et ##/cors-proxy## n'est pas utilisable sans connexion.
190 * Les requêtes ##OPTIONS## (pré-vol CORS) reçoivent leur 204 avant le contrôle Authelia, car les ##if## de nginx sont évalués avant ##auth_request##.
191 * En accès direct sur le port ##4000##, c'est le proxy intégré de Dashy qui répond, sans liste blanche ni Authelia.
192 * Nécessite le module Lua de nginx, présent dans l'image SWAG.
193
194 === Accès ===
195
196 L'accès se fait en deux étapes :
197
198 1. **Authelia**, devant tout le domaine : sans session Authelia, SWAG redirige vers le portail Authelia. Cela couvre l'interface, ##conf.yml## et les pages secondaires, l'API de Dashy, ##/cors-proxy## et ##/pico/##.
199 1. **Dashy**, une fois Authelia passé : son écran de connexion donne accès à l'éditeur de configuration au compte administrateur défini dans ##appConfig.auth.users## (##disableConfigurationForNonAdmin: true##). Voir [[Authentification>>||anchor="HAuthentification"]].
200
201 Règle dans la configuration d'[[Authelia>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Authelia.WebHome]], section ##access_control## :
202
203 {{code language="yaml"}}
204 access_control:
205 default_policy: deny
206 rules:
207 - domain: "<DOMAINE_DASHY>"
208 policy: one_factor
209 {{/code}}
210
211 * La règle ne sert que si SWAG interroge Authelia : sans les ##include## d'Authelia dans le fichier SWAG, elle n'est jamais évaluée, quelle que soit sa ##policy##. Il faut les deux.
212 * Une règle ##bypass## pour ce domaine, placée avant, annulerait la protection : Authelia applique la première règle qui correspond.
213 * ##enableGuestAccess: true## ne concerne que les personnes déjà passées par Authelia : elles voient les pages sans se connecter à Dashy, mais ne peuvent pas modifier la configuration.
214 * Le fichier Authelia ouvre aussi le CORS de ##/.well-known/openid-configuration## et ##/jwks.json## au domaine de Dashy, en prévision d'une connexion OIDC. Celle-ci n'est pas activée dans ##conf.yml##.
215
216 {{warning}}C'est Authelia qui protège les fichiers, pas Dashy : l'authentification de Dashy se fait dans le navigateur et masque seulement l'éditeur. ##conf.yml## et les pages secondaires contiennent les identifiants des widgets, les clés d'API, les adresses internes et le hash du mot de passe administrateur. Toute voie d'accès qui contourne Authelia (port ##4000##, autre proxy, règle ##bypass##) les rend lisibles. Vérifier après chaque modification de SWAG ou d'Authelia, en navigation privée : ##/conf.yml## doit renvoyer vers le portail Authelia.{{/warning}}
217
218 == Configuration ==
219
220 Dans ##<APPDATA>/Dashy/user-data## :
221
222 |=Élément|=Rôle
223 |##conf.yml##|Page d'accueil et configuration commune : ##appConfig##, ##pageInfo##, ##pages##, sections
224 |##bookmark.yml##|Page secondaire //bookmarks// : favoris web
225 |##cpu.yml##|Page secondaire //cpu// : supervision Glances
226 |##news.yml##|Page secondaire //news// : capteurs, flux, actualités, crypto
227 |##item-icons/##|Icônes des services et image de fond, stockées en local
228 |##conf.yml.bak##, ##bookmark.yml.bak##|Copies manuelles, non utilisées par Dashy
229 |##config-backups/##|Dossier de sauvegardes de Dashy (vide actuellement)
230
231 === Fonctionnement multi-pages ===
232
233 La page d'accueil est toujours ##conf.yml##. Les autres pages sont déclarées dans sa section ##pages:## : chaque entrée donne le nom affiché dans la barre de navigation et le chemin du fichier, relatif à ##user-data## (une URL distante est aussi acceptée).
234
235 {{code language="yaml"}}
236 pages:
237 - name: bookmarks
238 path: bookmark.yml
239 - name: cpu
240 path: cpu.yml
241 - name: news
242 path: news.yml
243 {{/code}}
244
245 * Une page secondaire ne contient que ##pageInfo## et ##sections## : ##appConfig## (thème, authentification, recherche...) est lu uniquement dans ##conf.yml## et s'applique à toutes les pages.
246 * Chaque page secondaire répète la même liste ##pages:##, pour garder la navigation identique d'une page à l'autre. Aucune ne déclare de fichier supplémentaire.
247 * Dans ##pageInfo.navLinks## des pages secondaires, un lien ##Home## vers ##/## ramène à l'accueil.
248 * Ajouter une page : créer le fichier dans ##user-data##, l'ajouter dans ##pages:## de ##conf.yml## et des autres pages, puis recharger.
249
250 === Récapitulatif des pages ===
251
252 |=Page Dashy|=Fichier|=Sous-page XWiki|=Widgets utilisant des identifiants
253 |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). Les widgets ##image## dépendent du jeton GitHub de github-readme-stats, stocké côté serveur.
254 |bookmarks|##bookmark.yml##|[[Bookmarks>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.Bookmarks.WebHome]]|Aucun widget
255 |cpu|##cpu.yml##|[[CPU>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.CPU.WebHome]]|Aucun (Glances sans authentification)
256 |news|##news.yml##|[[News>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.News.WebHome]]|##flight-data## (clé RapidAPI), ##news-headlines## (clé Currents API)
257
258 === Fichiers non référencés ===
259
260 * ##cpu2.yml## : ancienne copie de ##cpu.yml## avec une indentation à un espace qui casse la structure YAML. Déclarée nulle part, mais servie comme les autres fichiers. À supprimer.
261 * ##conf.yml.bak## et ##bookmark.yml.bak## : copies de sauvegarde, non déclarées.
262
263 === Structure d'un fichier ===
264
265 Un fichier de page contient trois blocs de premier niveau, plus ##appConfig## et ##pages## pour ##conf.yml## :
266
267 {{code language="yaml"}}
268 pageInfo:
269 title: <TITRE>
270 description: <SOUS_TITRE>
271 navLinks:
272 - title: <LIBELLE>
273 target: newtab
274 path: https://<SITE_PERSO>
275 appConfig:
276 # conf.yml uniquement, voir ci-dessous
277 pages:
278 # conf.yml, recopié dans chaque page secondaire
279 sections:
280 - name: <NOM_SECTION>
281 icon: <ICONE>
282 displayData:
283 sortBy: default # default | alphabetical | random
284 rows: 1
285 cols: 1
286 collapsed: false
287 hideForGuests: false
288 items:
289 - title: <NOM_SERVICE>
290 description: <DESCRIPTION>
291 icon: <ICONE>
292 url: https://<DOMAINE_SERVICE>/
293 target: newtab
294 statusCheck: true
295 statusCheckAllowInsecure: true
296 id: <ID>
297 widgets:
298 - type: <TYPE_WIDGET>
299 useProxy: true
300 options:
301 <OPTION>: <VALEUR>
302 id: <ID>
303 {{/code}}
304
305 * ##id## : identifiant unique généré par l'interface. Facultatif en écriture manuelle : Dashy en génère un s'il manque.
306 * ##icon## : formes utilisées dans cette configuration :
307 ** nom de fichier présent dans ##item-icons/## (##portainer.svg##) ;
308 ** ##hl-<nom>## : jeu d'icônes homelab intégré (##hl-jellyfin##) ;
309 ** classes Font Awesome (##fas fa-terminal##, ##fab fa-github##, ##fad fa-clock##), actif via ##enableFontAwesome: true## ;
310 ** ##favicon## : favicon du site récupéré par le service défini dans ##faviconApi## ;
311 ** emoji (##🛡️##) ou URL complète d'une image.
312 * ##useProxy## se place sur le widget, pas sur la section : placé au niveau de la section, il est ignoré.
313
314 === appConfig et thème ===
315
316 {{code language="yaml"}}
317 appConfig:
318 theme: dracula
319 layout: auto
320 iconSize: small
321 backgroundImg: /item-icons/<IMAGE_FOND>
322 startingView: default
323 defaultOpeningMethod: newtab
324 statusCheck: false
325 statusCheckInterval: 0
326 faviconApi: allesedv
327 enableFontAwesome: true
328 enableMaterialDesignIcons: false
329 widgetsAlwaysUseProxy: false
330 webSearch:
331 searchEngine: duckduckgo
332 openingMethod: newtab
333 searchBangs: {}
334 disableWebSearch: false
335 auth:
336 enableGuestAccess: true
337 users:
338 - user: <UTILISATEUR_DASHY>
339 hash: <HASH_SHA256_DU_MOT_DE_PASSE>
340 type: admin
341 enableHeaderAuth: false
342 headerAuth:
343 userHeader: REMOTE_USER
344 proxyWhitelist: []
345 enableKeycloak: false
346 hideComponents:
347 hideHeading: false
348 hideNav: false
349 hideSearch: false
350 hideSettings: false
351 hideFooter: false
352 showSplashScreen: false
353 preventWriteToDisk: false
354 preventLocalSave: false
355 disableConfiguration: false
356 disableConfigurationForNonAdmin: true
357 allowConfigEdit: true
358 enableServiceWorker: false
359 disableContextMenu: false
360 disableUpdateChecks: false
361 disableSmartSort: false
362 enableErrorReporting: false
363 {{/code}}
364
365 |=Clé|=Effet
366 |##theme: dracula##|Thème sombre intégré, appliqué à toutes les pages
367 |##backgroundImg##|Image de fond, servie depuis ##item-icons/##
368 |##statusCheck: false##|Pas de vérification d'état globale : elle est activée item par item (##statusCheck: true##)
369 |##faviconApi: allesedv##|Les icônes ##favicon## sont récupérées via le service externe allesedv
370 |##widgetsAlwaysUseProxy: false##|Chaque widget choisit avec ##useProxy## s'il passe par ##/cors-proxy##
371 |##webSearch##|Recherche web DuckDuckGo depuis la barre de recherche, en nouvel onglet
372 |##preventWriteToDisk: false##|L'interface peut écrire dans les fichiers YAML du volume
373 |##preventLocalSave: false##|Les modifications peuvent aussi être gardées dans le stockage local du navigateur
374 |##disableConfigurationForNonAdmin: true##|Seul un compte ##type: admin## voit l'éditeur de configuration
375
376 === Authentification ===
377
378 * Un seul compte, administrateur, défini par son nom et le hash SHA-256 de son mot de passe. Générer le hash :
379
380 {{code language="bash"}}
381 echo -n '<MOT_DE_PASSE_DASHY>' | sha256sum
382 {{/code}}
383
384 * ##enableGuestAccess: true## : les visiteurs authentifiés par Authelia mais pas par Dashy voient toutes les pages. ##hideForGuests: true## sur une section la masque aux invités, sans la retirer des fichiers servis.
385 * ##enableHeaderAuth## (utilisateur transmis par le reverse proxy dans ##REMOTE_USER##) et ##enableKeycloak## sont désactivés.
386
387 === Vérifier la syntaxe ===
388
389 Après une modification à la main :
390
391 {{code language="bash"}}
392 docker exec dashy yarn validate-config
393 {{/code}}
394
395 == Statistiques GitHub : github-readme-stats ==
396
397 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.
398
399 {{code language="yaml"}}
400 services:
401 github-readme-stats:
402 image: github-readme-stats:local
403 container_name: github-readme-stats
404 restart: unless-stopped
405 ports:
406 - "9000:9000"
407 environment:
408 - PAT_1=${PAT_1}
409 - CACHE_SECONDS=14400
410 {{/code}}
411
412 * ##PAT_1## : jeton d'accès personnel GitHub, défini dans les variables de la stack Portainer. Jeton classique avec les permissions ##repo## pour compter les dépôts privés.
413 * ##CACHE_SECONDS## : durée de mise en cache des cartes (4 heures), pour limiter les appels à l'API GitHub.
414 * Accessible uniquement en local, sur le port 9000.
415
416 Principales adresses :
417
418 |=Carte|=Adresse
419 |Statistiques du profil|##/api?username=<UTILISATEUR_GITHUB>##
420 |Langages les plus utilisés|##/api/top-langs?username=<UTILISATEUR_GITHUB>##
421 |Dépôt épinglé|##/api/pin?username=<UTILISATEUR_GITHUB>&repo=<DEPOT>##
422
423 Dans Dashy, les cartes s'affichent avec un widget de type ##image## qui pointe vers l'instance locale (voir la sous-page [[Accueil>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Dashy.Accueil.WebHome]]).
424
425 === Image locale ===
426
427 Portainer ne sait pas construire une image dans une stack : l'image ##github-readme-stats:local## est construite sur l'hôte, depuis le dépôt cloné. Elle n'est donc pas mise à jour par Watchtower. Pour la mettre à jour, depuis le dossier du dépôt :
428
429 {{code language="bash"}}
430 git pull
431 docker build -t github-readme-stats:local .
432 {{/code}}
433
434 Puis redéployer la stack dans Portainer.
435
436 == Maintenance ==
437
438 === Après une migration ou une réinstallation d'un service ===
439
440 |=Service migré ou réinstallé|=À refaire dans Dashy
441 |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 (sauvegarde restaurée, passage à AIO, nouvelle instance). Vérifier que le compte est toujours administrateur et que le nom d'utilisateur a gardé la même casse.
442 |AdGuard Home|Reporter le nom d'utilisateur et le mot de passe de l'interface web dans les trois widgets ##adguard-*##. Si l'adresse IP change : mettre à jour ##hostname## et la liste ##allowed_internal## de SWAG.
443 |Glances|Mettre à jour ##hostname## dans tous les widgets ##gl-*## de ##cpu.yml## si le domaine change.
444 |github-readme-stats|Reconstruire l'image locale et recréer le jeton ##PAT_1## s'il a expiré.
445 |Pico W|Mettre à jour son IP dans ##news.yml## (item et script du widget ##embed##), dans ##location /pico/## et dans ##allowed_internal## de SWAG.
446 |SWAG|Recopier ##30-dashy.subdomain.conf## complet. Sans les ##include## d'Authelia, Dashy et ses fichiers de configuration redeviennent publics. Sans le bloc ##/cors-proxy##, les widgets en ##useProxy: true## passent par le proxy de Dashy, sans liste blanche.
447 |Authelia|Vérifier que la règle ##one_factor## du domaine de Dashy est toujours présente et qu'aucune règle ##bypass## ne la précède.
448 |Dashy|Restaurer ##user-data## (fichiers YAML et ##item-icons/##). Aucun identifiant n'est stocké ailleurs.
449 |API externes (RapidAPI, Currents)|Si la clé est régénérée ou le compte recréé, reporter la nouvelle clé dans ##news.yml##.
450
451 === Recharger la configuration ===
452
453 * Modification depuis l'interface : l'enregistrement sur le disque, depuis l'éditeur de configuration, écrit le fichier YAML de la page affichée.
454 * Modification à la main : Dashy relit les fichiers YAML à chaque chargement, un rafraîchissement du navigateur suffit. Si l'ancienne configuration reste affichée, elle vient du stockage local du navigateur : réinitialiser les paramètres locaux depuis le menu de configuration, ou vider les données du site.
455 * Changement dans la stack (variables d'environnement, image) : redéployer la stack dans Portainer.
456 * Changement dans le fichier SWAG : ##docker exec swag nginx -t## puis ##docker exec swag nginx -s reload##.
457 * Changement dans la configuration d'Authelia : ##docker restart authelia##.
458
459 === Un widget reste vide ===
460
461 Dans l'ordre :
462
463 1. Outils de développement du navigateur (F12), onglets Console et Réseau : repérer la requête du widget et son code de retour.
464 1. Requête vers ##/cors-proxy## :
465 1*. 302 vers le portail Authelia, ou 401 : session Authelia expirée ; recharger la page et se reconnecter ;
466 1*. 400 ##Target-URL invalide## : ##hostname## mal formé (schéma ##http:~/~/## ou ##https:~/~/## obligatoire) ;
467 1*. 403 ##Cible interne non autorisée## : IP du LAN absente de ##allowed_internal## dans SWAG ;
468 1*. 401 ou 403 renvoyé par la cible : identifiants faux, mot de passe d'application révoqué, compte sans droits suffisants, ou en-tête d'authentification non transmis par le bloc Lua ;
469 1*. 502 ou 504 : service cible arrêté ou injoignable depuis le conteneur SWAG.
470 1. Requête directe (sans ##/cors-proxy##) bloquée avec une erreur CORS dans la console : passer le widget en ##useProxy: true##.
471 1. Journaux : ##docker logs swag## et ##<APPDATA>/swag/config/log/nginx/error.log## pour le proxy, ##docker logs dashy## pour le serveur de Dashy.
472 1. Vérifier la syntaxe du fichier avec ##yarn validate-config## : une erreur d'indentation peut vider toute une section.
473 1. Tester l'API cible à la main depuis l'hôte, avec les mêmes identifiants. Exemple pour Nextcloud :
474
475 {{code language="bash"}}
476 curl -u '<UTILISATEUR_NEXTCLOUD>:<MOT_DE_PASSE_APPLICATION>' -H 'OCS-APIREQUEST: true' \
477 'https://<DOMAINE_NEXTCLOUD>/ocs/v2.php/apps/serverinfo/api/v1/info?format=json'
478 {{/code}}
479
480 == Sauvegarde ==
481
482 ##<APPDATA>/Dashy/user-data## est sauvegardé par le script de [[Sauvegarde>>Wiki Batcave John.Infrastructure.Sauvegarde.WebHome]]. Il contient toute la configuration, identifiants des widgets compris : la sauvegarde doit être protégée en conséquence. Le fichier SWAG ##30-dashy.subdomain.conf## est aussi dans ##<APPDATA>##, couvert par la même sauvegarde.