From d3a8394bc144b17cc5fb630b2b27fdaab7f89d53 Mon Sep 17 00:00:00 2001 From: Fabrice Date: Fri, 9 Oct 2026 15:01:09 +0000 Subject: [PATCH] Traefik : exemple de route /admin vers l'interface ; option --ecoute Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Mf2kATMtqVABHSYdxJMnim --- README.md | 3 ++- exemples/traefik-rtg-admin.yml | 27 +++++++++++++++++++++++++++ rtg/cli.py | 4 +++- rtg/interface/serveur.py | 12 ++++++++---- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 exemples/traefik-rtg-admin.yml diff --git a/README.md b/README.md index 650247d..3440186 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ L'interface permet de modifier le site et de lire les fichiers de l'ordinateur : ### Administration depuis le site -Pour administrer le site depuis son adresse publique (bouton « Connexion » en haut à droite de l'accueil, qui mène à `https://roadtrip.ouaibe.fr/admin/`), l'interface tourne sur la machine qui sert le site, derrière son serveur web en HTTPS. Les sources (rushs, traces, photos) doivent alors être accessibles depuis cette machine pour encoder et générer. +Pour administrer le site depuis son adresse publique (bouton « Connexion » en haut à droite de l'accueil, qui mène à `https://roadtrips.ouaibe.fr/admin/`), l'interface tourne sur la machine qui sert le site, derrière son serveur web en HTTPS. Les sources (rushs, traces, photos) doivent alors être accessibles depuis cette machine pour encoder et générer. 1. Sur cette machine, une fois : `rtg mot-de-passe`. 2. Lancer l'interface, en permanence de préférence (service, `tmux`…) : @@ -157,6 +157,7 @@ Pour administrer le site depuis son adresse publique (bouton « Connexion » en ``` Elle n'écoute que sur 127.0.0.1 : seul le serveur web peut la joindre. Le mot de passe est obligatoire. 3. Transmettre `/admin/` à l'interface depuis le serveur web. + - Traefik : copier `exemples/traefik-rtg-admin.yml` dans le dossier de configuration dynamique de Traefik, en y mettant les mêmes `entryPoints` et `certResolver` que pour le site. Le fichier indique l'adresse à mettre selon que Traefik tourne dans Docker sur le Mac, directement sur le Mac, ou sur une autre machine (dans ce dernier cas, lancer RTG avec `--ecoute 0.0.0.0` en plus). - nginx, dans le bloc `server` du site en HTTPS : ```nginx location /admin/ { diff --git a/exemples/traefik-rtg-admin.yml b/exemples/traefik-rtg-admin.yml new file mode 100644 index 0000000..f4390b1 --- /dev/null +++ b/exemples/traefik-rtg-admin.yml @@ -0,0 +1,27 @@ +# Traefik : envoie https://roadtrips.ouaibe.fr/admin/ vers l'interface RTG. +# +# 1. Copier ce fichier dans le dossier de configuration « dynamique » de +# Traefik (celui de providers.file), à côté de la configuration du site. +# 2. Mettre ci-dessous les mêmes entryPoints et certResolver que ceux du site. +# 3. Sur le Mac, laisser tourner : +# rtg --racine /Volumes/CLEROADTRIPS/Road-Trips interface --proxy --prefixe /admin +# +# Traefik transmet lui-même l'adresse du visiteur et le « https » à RTG +# (X-Forwarded-For, X-Forwarded-Proto) : rien d'autre à régler. +http: + routers: + rtg-admin: + rule: "Host(`roadtrips.ouaibe.fr`) && PathPrefix(`/admin`)" + entryPoints: [websecure] # même nom que pour le site + service: rtg-admin + tls: + certResolver: letsencrypt # même nom que pour le site + services: + rtg-admin: + loadBalancer: + servers: + # Traefik dans Docker sur ce Mac : + - url: "http://host.docker.internal:8765" + # Traefik installé directement sur ce Mac : "http://127.0.0.1:8765" + # Traefik sur une autre machine : "http://:8765", + # et lancer RTG avec --ecoute 0.0.0.0 en plus. diff --git a/rtg/cli.py b/rtg/cli.py index a724bd1..c972e52 100644 --- a/rtg/cli.py +++ b/rtg/cli.py @@ -57,6 +57,7 @@ def main(argv=None): i.add_argument("--proxy", action="store_true", help="derrière le serveur web du site (mot de passe obligatoire)") i.add_argument("--prefixe", default="", help="chemin de l'interface sur le site, par exemple /admin") + i.add_argument("--ecoute", help="adresse d'écoute (défaut 127.0.0.1 ; 0.0.0.0 si le serveur web est ailleurs)") mp = sp.add_parser("mot-de-passe", help="définir ou supprimer le mot de passe de l'interface") mp.add_argument("--supprimer", action="store_true") @@ -109,7 +110,8 @@ def main(argv=None): if bool(args.certificat) != bool(args.cle): sys.exit("❌ --certificat et --cle vont ensemble.") lancer(racine, args.port, ouvrir=not (args.sans_navigateur or args.proxy), distant=args.distant, - certificat=args.certificat, cle=args.cle, proxy=args.proxy, prefixe=args.prefixe) + certificat=args.certificat, cle=args.cle, proxy=args.proxy, prefixe=args.prefixe, + ecoute=args.ecoute) except KeyboardInterrupt: print("\nInterrompu.") sys.exit(130) diff --git a/rtg/interface/serveur.py b/rtg/interface/serveur.py index 8ff5784..fc577fc 100644 --- a/rtg/interface/serveur.py +++ b/rtg/interface/serveur.py @@ -837,13 +837,16 @@ def _echapper(s): def lancer(racine, port=8765, ouvrir=True, distant=False, certificat=None, cle=None, - proxy=False, prefixe=""): + proxy=False, prefixe="", ecoute=None): """Lance l'interface. distant : écoute sur toutes les interfaces réseau, mot de passe obligatoire ; certificat, cle : HTTPS ; proxy : derrière le serveur web du site (qui transmet https://…/admin/ à - 127.0.0.1:port), mot de passe obligatoire ; prefixe : « /admin ».""" - if (distant or proxy) and not acces.defini(): + 127.0.0.1:port), mot de passe obligatoire ; prefixe : « /admin » ; + ecoute : adresse d'écoute imposée (« 0.0.0.0 » si le serveur web est sur + une autre machine).""" + hors_machine = ecoute and ecoute not in ("127.0.0.1", "localhost", "::1") + if (distant or proxy or hors_machine) and not acces.defini(): raise SystemExit("❌ L'accès depuis le réseau demande un mot de passe : lancez d'abord « rtg mot-de-passe ».") contexte_tls = None if certificat: @@ -856,7 +859,8 @@ def lancer(racine, port=8765, ouvrir=True, distant=False, certificat=None, cle=N for p in ([port] if proxy else range(port, port + 20)): try: gardien = Gardien(p, distant=distant, https=bool(contexte_tls), proxy=proxy, prefixe=app.prefixe) - serveur = ThreadingHTTPServer(("0.0.0.0" if distant else "127.0.0.1", p), + adresse = ecoute or ("0.0.0.0" if distant else "127.0.0.1") + serveur = ThreadingHTTPServer((adresse, p), creer_gestionnaire(app, p, gardien)) port = p break