feat: add headscale test deployment artifacts
This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user