diff --git a/headscale-anytype-body.md b/headscale-anytype-body.md new file mode 100644 index 0000000..0dc661a --- /dev/null +++ b/headscale-anytype-body.md @@ -0,0 +1,233 @@ +# Headscale / Headscale UI sur QNAP — finalisation + +## Ce qui a déjà été déployé + +Stack Portainer : `headscale-test` + +Services : +- `headscale` +- `headscale-ui` +- `headscale-init` + +Chemins NAS : +- `/share/ZFS24_DATA/docker/headscale-test/config` +- `/share/ZFS24_DATA/docker/headscale-test/data` + +Ports de test actuels : +- API Headscale : `192.168.1.150:8086` +- Metrics : `192.168.1.150:9096` +- UI HTTP : `192.168.1.150:18087` +- UI HTTPS auto-signé : `192.168.1.150:18447` +- gRPC : `192.168.1.150:50443` + +Domaine cible configuré dans `config.yaml` : +- `https://hs.nucleon.fr` + +Base domain MagicDNS de test : +- `internal.hs.nucleon.fr` + +## Important + +`headscale-ui` doit idéalement être servi **sur le même sous-domaine que Headscale**, typiquement : +- `https://hs.nucleon.fr/` → Headscale +- `https://hs.nucleon.fr/web` → Headscale UI + +Sinon il faudra gérer CORS proprement au reverse proxy. + +--- + +## Étapes restantes pour finaliser l'installation + +### 1) Créer le sous-domaine DNS + +Créer un enregistrement DNS pour : +- `hs.nucleon.fr` + +Il doit pointer vers l'IP publique qui arrive sur ton reverse proxy. + +--- + +### 2) Mettre en place le reverse proxy HTTPS + +Objectif : exposer **le même host** pour Headscale et l'UI. + +Routing recommandé : +- `/web` → `http://headscale-ui:8080` +- `/` → `http://headscale:8080` + +Si tu le fais via SWAG/Nginx Proxy Manager/Caddy, garde bien cette logique de **même sous-domaine**. + +### Exemple logique de proxy + +- `https://hs.nucleon.fr/web` → UI +- `https://hs.nucleon.fr` → API Headscale + +Sans ça, l'UI peut afficher des erreurs de preflight / CORS. + +--- + +### 3) Vérifier la conf Headscale + +Fichier actuel : +- `/share/ZFS24_DATA/docker/headscale-test/config/config.yaml` + +Points déjà posés : +- `server_url: https://hs.nucleon.fr` +- SQLite locale +- MagicDNS activé +- ACL de test très ouverte +- DERP public Tailscale utilisé pour commencer + +À ajuster plus tard si besoin : +- DNS interne personnalisé +- OIDC / SSO +- DERP perso +- ACL plus stricte + +--- + +### 4) Créer le premier user / namespace + +Dans le conteneur `headscale`, créer ton premier user. + +Exemple logique : +- user principal : `christophe` + +Commande type à exécuter dans le conteneur : + +```bash +headscale users create christophe +headscale users list +``` + +--- + +### 5) Générer une API key pour l'UI + +Headscale UI a besoin d'une API key Headscale. + +Commande type : + +```bash +headscale apikeys create +``` + +Ensuite, dans Headscale UI : +- renseigner l'URL du serveur : `https://hs.nucleon.fr` +- coller l'API key générée + +Tant que le reverse proxy n'est pas proprement en place, l'UI peut être capricieuse. + +--- + +### 6) Générer des preauth keys pour connecter les machines + +Pour enregistrer une machine dans Headscale : + +```bash +headscale preauthkeys create --user christophe --reusable --expiration 24h +``` + +Selon le besoin, tu peux faire : +- des clés temporaires +- des clés réutilisables +- des clés taggées + +--- + +### 7) Reconfigurer les clients Tailscale vers Headscale + +Sur chaque machine, il faudra connecter le client Tailscale à ton serveur Headscale. + +Principe : +- se déconnecter proprement si besoin +- se reconnecter avec ton login server Headscale +- utiliser une preauth key quand nécessaire + +Le point clé côté client sera ton serveur : +- `https://hs.nucleon.fr` + +--- + +### 8) Vérifier la remontée des nodes + +Après connexion des clients : + +```bash +headscale nodes list +``` + +Vérifier : +- IPs attribuées +- nom des machines +- routes annoncées +- statut en ligne + +--- + +### 9) Durcir les ACL + +La policy actuelle est volontairement permissive pour les tests : +- tout le monde peut parler à tout le monde + +Fichier : +- `/share/ZFS24_DATA/docker/headscale-test/config/acl.hujson` + +Avant passage en production, définir : +- users +- tags +- groupes +- accès par rôle +- restrictions SSH +- accès subnet routers / exit nodes + +--- + +### 10) Préparer la migration depuis Tailscale + +Avant remplacement complet, valider : +- connexion d'au moins 2-3 machines +- DNS interne +- accès entre machines +- subnet router si besoin +- exit node si besoin +- stabilité mobile +- performance générale + +Migration prudente recommandée : +1. Monter Headscale en parallèle +2. Tester avec quelques machines +3. Reproduire les usages critiques +4. Basculer progressivement +5. Couper Tailscale quand tout est validé + +--- + +## Remarques d'architecture + +Pour les tests, le choix Docker/QNAP est bon. + +Mon avis : +- **pour tester** → stack Docker dédiée sur le QNAP, très bien +- **plus tard** → on pourra décider si ça reste autonome ou si on le rattache à une stack plus globale + +Je penche plutôt pour **le laisser séparé** d'OpenClaw : +- responsabilités plus claires +- moins de couplage +- maintenance plus simple +- migration / rollback plus propres + +--- + +## Checklist courte + +- [ ] DNS `hs.nucleon.fr` +- [ ] Reverse proxy HTTPS même host pour `/` et `/web` +- [ ] Création user `christophe` +- [ ] Génération API key UI +- [ ] Connexion UI +- [ ] Génération preauth keys +- [ ] Connexion des premières machines +- [ ] Validation réseau +- [ ] Durcissement ACL +- [ ] Migration progressive hors Tailscale diff --git a/headscale-test.compose.yml b/headscale-test.compose.yml new file mode 100644 index 0000000..c22004a --- /dev/null +++ b/headscale-test.compose.yml @@ -0,0 +1,145 @@ +services: + init-headscale: + image: alpine:3.20 + container_name: headscale-init + command: + - /bin/sh + - -c + - | + set -eu + mkdir -p /target/config /target/data /target/caddy + cat >/target/config/config.yaml <<'EOF_CONFIG' + server_url: https://hs.nucleon.fr + listen_addr: 0.0.0.0:8080 + metrics_listen_addr: 0.0.0.0:9090 + grpc_listen_addr: 0.0.0.0:50443 + grpc_allow_insecure: false + + noise: + private_key_path: /var/lib/headscale/noise_private.key + + prefixes: + v4: 100.64.0.0/10 + v6: fd7a:115c:a1e0::/48 + allocation: sequential + + derp: + server: + enabled: false + region_id: 999 + region_code: headscale + region_name: Headscale Embedded DERP + verify_clients: true + stun_listen_addr: 0.0.0.0:3478 + private_key_path: /var/lib/headscale/derp_server_private.key + automatically_add_embedded_derp_region: true + urls: + - https://controlplane.tailscale.com/derpmap/default + paths: [] + auto_update_enabled: true + update_frequency: 24h + + disable_check_updates: false + ephemeral_node_inactivity_timeout: 30m + + database: + type: sqlite + debug: false + sqlite: + path: /var/lib/headscale/db.sqlite + write_ahead_log: true + wal_autocheckpoint: 1000 + + log: + level: info + format: text + + policy: + mode: file + path: /etc/headscale/acl.hujson + + dns: + magic_dns: true + base_domain: internal.hs.nucleon.fr + override_local_dns: true + nameservers: + global: + - 1.1.1.1 + - 1.0.0.1 + - 2606:4700:4700::1111 + - 2606:4700:4700::1001 + split: {} + search_domains: [] + extra_records: [] + + unix_socket: /var/run/headscale/headscale.sock + unix_socket_permission: "0770" + + logtail: + enabled: false + + randomize_client_port: false + + taildrop: + enabled: true + EOF_CONFIG + cat >/target/config/acl.hujson <<'EOF_ACL' + { + // Politique ouverte pour la phase de test. + // À durcir ensuite (tags, groupes, règles ciblées). + "groups": {}, + "tagOwners": {}, + "acls": [ + { + "action": "accept", + "src": ["*"], + "dst": ["*:*"], + }, + ], + "ssh": [], + } + EOF_ACL + chmod 644 /target/config/config.yaml /target/config/acl.hujson + mkdir -p /target/data/cache + chown -R 0:0 /target/config /target/data /target/caddy + echo 'init ok' + volumes: + - /share/ZFS24_DATA/docker/headscale-test:/target + restart: "no" + + headscale: + image: headscale/headscale:latest + container_name: headscale + depends_on: + init-headscale: + condition: service_completed_successfully + command: serve + volumes: + - /share/ZFS24_DATA/docker/headscale-test/config:/etc/headscale + - /share/ZFS24_DATA/docker/headscale-test/data:/var/lib/headscale + ports: + - "8086:8080" + - "9096:9090" + - "50443:50443" + environment: + - TZ=Europe/Paris + restart: always + + headscale-ui: + image: ghcr.io/gurucomputing/headscale-ui:latest + container_name: headscale-ui + depends_on: + - headscale + environment: + - HTTP_PORT=8080 + - HTTPS_PORT=8443 + - TZ=Europe/Paris + ports: + - "18087:8080" + - "18447:8443" + restart: always + +networks: + default: + name: swag_lan + external: true