feat: add headscale test deployment artifacts

This commit is contained in:
Nox
2026-03-12 17:58:34 +00:00
parent 55cfa43a0c
commit 0c75377943
2 changed files with 378 additions and 0 deletions
+233
View File
@@ -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
+145
View File
@@ -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